Added the "reverse lookup" daemon-config parameter.
[rsync/rsync.git] / loadparm.c
index d2d4617..b3197a8 100644 (file)
  * and Karl Auer.  Some of the changes are:
  *
  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
- * Copyright (C) 2003-2008 Wayne Davison <wayned@samba.org>
+ * Copyright (C) 2003-2009 Wayne Davison <wayned@samba.org>
  */
 
 /* Load parameters.
  *
  *  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.
  *
  * To add a parameter:
  *
- * 1) add it to the global or service structure definition
+ * 1) add it to the global or section structure definition
  * 2) add it to the parm_table
  * 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
- *    (ie. service) parameter then initialise it in the sDefault structure
+ * 4) If it's a global then initialise it in init_globals. If a local module
+ *    (ie. section) parameter then initialise it in the sDefault structure
  *
  *
  * Notes:
  */
 
 #include "rsync.h"
-#include "ifuncs.h"
-#define PTR_DIFF(p1, p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
+#include "itypes.h"
+
+extern item_list dparam_list;
+
 #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))
 
 #ifndef LOG_DAEMON
 #define LOG_DAEMON 0
@@ -60,12 +60,12 @@ typedef char pstring[1024];
 
 /* the following are used by loadparm for option lists */
 typedef enum {
-       P_BOOL, P_BOOLREV, P_CHAR, P_INTEGER, P_OCTAL,
-       P_PATH, P_STRING, P_GSTRING, P_ENUM, P_SEP
+       P_BOOL, P_BOOLREV, P_CHAR, P_INTEGER,
+       P_OCTAL, P_PATH, P_STRING, P_ENUM
 } parm_type;
 
 typedef enum {
-       P_LOCAL, P_GLOBAL, P_SEPARATOR, P_NONE
+       P_LOCAL, P_GLOBAL, P_NONE
 } parm_class;
 
 struct enum_list {
@@ -87,9 +87,9 @@ struct parm_struct {
 #endif
 
 /* some helpful bits */
-#define pSERVICE(i) ServicePtrs[i]
-#define iSERVICE(i) (*pSERVICE(i))
-#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
+#define iSECTION(i) ((section*)section_list.items)[i]
+#define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count)
+#define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char *)(p)) - (char *)&sDefault))
 
 /*
  * This structure describes global (ie., server-wide) parameters.
@@ -106,7 +106,7 @@ typedef struct {
 static global Globals;
 
 /*
- * This structure describes a single service.  Their order must match the
+ * This structure describes a single section.  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.)
  */
@@ -149,17 +149,23 @@ typedef struct {
        BOOL munge_symlinks;
        BOOL numeric_ids;
        BOOL read_only;
+       BOOL reverse_lookup;
        BOOL strict_modes;
        BOOL transfer_logging;
        BOOL use_chroot;
        BOOL write_only;
-} service;
+} section;
+
+typedef struct {
+       global g;
+       section s;
+} global_and_section;
 
-/* This is a default service used to prime a services structure.  In order
+/* This is a default section used to prime a sections structure.  In order
  * to make these easy to keep sorted in the same way as the variables
  * above, use the variable name in the leading comment, including a
  * trailing ';' (to avoid a sorting problem with trailing digits). */
-static service sDefault = {
+static section sDefault = {
  /* auth_users; */             NULL,
  /* charset; */                NULL,
  /* comment; */                NULL,
@@ -198,6 +204,7 @@ static service sDefault = {
  /* munge_symlinks; */         (BOOL)-1,
  /* numeric_ids; */            (BOOL)-1,
  /* read_only; */              True,
+ /* reverse_lookup; */         True,
  /* strict_modes; */           True,
  /* transfer_logging; */       False,
  /* use_chroot; */             True,
@@ -205,9 +212,9 @@ static service sDefault = {
 };
 
 /* local variables */
-static service **ServicePtrs = NULL;
-static int iNumServices = 0;
-static int iServiceIndex = 0;
+static item_list section_list = EMPTY_ITEM_LIST;
+static item_list section_stack = EMPTY_ITEM_LIST;
+static int iSectionIndex = -1;
 static BOOL bInGlobalSection = True;
 
 #define NUMPARAMETERS (sizeof (parm_table) / sizeof (struct parm_struct))
@@ -322,6 +329,7 @@ static struct parm_struct parm_table[] =
 #endif
  {"read only",         P_BOOL,   P_LOCAL, &sDefault.read_only,         NULL,0},
  {"refuse options",    P_STRING, P_LOCAL, &sDefault.refuse_options,    NULL,0},
+ {"reverse lookup",    P_BOOL,   P_LOCAL, &sDefault.reverse_lookup,    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},
@@ -359,13 +367,13 @@ static void init_locals(void)
  int fn_name(void) {return *(int *)(ptr);}
 
 #define FN_LOCAL_STRING(fn_name, val) \
- char *fn_name(int i) {return LP_SNUM_OK(i) && pSERVICE(i)->val? pSERVICE(i)->val : (sDefault.val? sDefault.val : "");}
+ char *fn_name(int i) {return LP_SNUM_OK(i) && iSECTION(i).val? iSECTION(i).val : (sDefault.val? sDefault.val : "");}
 #define FN_LOCAL_BOOL(fn_name, val) \
- BOOL fn_name(int i) {return LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val;}
+ BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(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;}
+ char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(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;}
+ int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : sDefault.val;}
 
 FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
@@ -412,6 +420,7 @@ FN_LOCAL_BOOL(lp_list, list)
 FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)
 FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids)
 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_transfer_logging, transfer_logging)
 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
@@ -437,16 +446,16 @@ static void string_set(char **s, const char *v)
                exit_cleanup(RERR_MALLOC);
 }
 
-/* Copy a service structure to another. */
-static void copy_service(service *pserviceDest, service *pserviceSource)
+/* Copy a section structure to another. */
+static void copy_section(section *psectionDest, section *psectionSource)
 {
        int i;
 
        for (i = 0; parm_table[i].label; i++) {
                if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
                        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);
+                       void *src_ptr = SECTION_PTR(psectionSource, def_ptr);
+                       void *dest_ptr = SECTION_PTR(psectionDest, def_ptr);
 
                        switch (parm_table[i].type) {
                        case P_BOOL:
@@ -476,11 +485,11 @@ static void copy_service(service *pserviceDest, service *pserviceSource)
        }
 }
 
-/* Initialise a service to the defaults. */
-static void init_service(service *pservice)
+/* Initialise a section to the defaults. */
+static void init_section(section *psection)
 {
-       memset((char *)pservice, 0, sizeof (service));
-       copy_service(pservice, &sDefault);
+       memset((char *)psection, 0, sizeof (section));
+       copy_section(psection, &sDefault);
 }
 
 /* Do a case-insensitive, whitespace-ignoring string compare. */
@@ -511,15 +520,15 @@ static int strwicmp(char *psz1, char *psz2)
        return *psz1 - *psz2;
 }
 
-/* Find a service by name. Otherwise works like get_service. */
-static int getservicebyname(char *name, service *pserviceDest)
+/* Find a section by name. Otherwise works like get_section. */
+static int getsectionbyname(char *name, section *psectionDest)
 {
        int i;
 
-       for (i = iNumServices - 1; i >= 0; i--) {
-               if (strwicmp(iSERVICE(i).name, name) == 0) {
-                       if (pserviceDest != NULL)
-                               copy_service(pserviceDest, pSERVICE(i));
+       for (i = section_list.count - 1; i >= 0; i--) {
+               if (strwicmp(iSECTION(i).name, name) == 0) {
+                       if (psectionDest != NULL)
+                               copy_section(psectionDest, &iSECTION(i));
                        break;
                }
        }
@@ -527,33 +536,25 @@ static int getservicebyname(char *name, service *pserviceDest)
        return i;
 }
 
-/* Add a new service to the services array, with defaults set. */
-static int add_a_service(char *name)
+/* Add a new section to the sections array w/the default values. */
+static int add_a_section(char *name)
 {
        int i;
-       int num_to_alloc = iNumServices+1;
+       section *s;
 
        /* it might already exist */
        if (name) {
-               i = getservicebyname(name, NULL);
+               i = getsectionbyname(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++;
+       i = section_list.count;
+       s = EXPAND_ITEM_LIST(&section_list, section, 2);
 
-       init_service(pSERVICE(i));
+       init_section(s);
        if (name)
-               string_set(&iSERVICE(i).name, name);
+               string_set(&s->name, name);
 
        return i;
 }
@@ -600,8 +601,8 @@ static BOOL set_boolean(BOOL *pb, char *parmvalue)
 static BOOL do_parameter(char *parmname, char *parmvalue)
 {
        int parmnum, i;
-       void *parm_ptr=NULL; /* where we are going to store the result */
-       void *def_ptr=NULL;
+       void *parm_ptr; /* where we are going to store the result */
+       void *def_ptr;
        char *cp;
 
        parmnum = map_parameter(parmname);
@@ -617,10 +618,10 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
                parm_ptr = def_ptr;
        else {
                if (parm_table[parmnum].class == P_GLOBAL) {
-                       rprintf(FLOG, "Global parameter %s found in service section!\n", parmname);
+                       rprintf(FLOG, "Global parameter %s found in module section!\n", parmname);
                        return True;
                }
-               parm_ptr = ((char *)pSERVICE(iServiceIndex)) + PTR_DIFF(def_ptr, &sDefault);
+               parm_ptr = SECTION_PTR(&iSECTION(iSectionIndex), def_ptr);
        }
 
        /* now switch on the type of variable it is */
@@ -659,12 +660,8 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
                string_set(parm_ptr, parmvalue);
                break;
 
-       case P_GSTRING:
-               strlcpy((char *)parm_ptr, parmvalue, sizeof (pstring));
-               break;
-
        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)) {
                                *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
                                break;
@@ -675,8 +672,6 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
                                *(int *)parm_ptr = atoi(parmvalue);
                }
                break;
-       case P_SEP:
-               break;
        }
 
        return True;
@@ -686,11 +681,36 @@ static BOOL do_parameter(char *parmname, char *parmvalue)
  * Returns True on success, False on failure. */
 static BOOL do_section(char *sectionname)
 {
-       BOOL isglobal = strwicmp(sectionname, GLOBAL_NAME) == 0;
+       BOOL isglobal;
+
+       if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */
+               bInGlobalSection = 1;
+               if (strcmp(sectionname+1, "push") == 0) {
+                       global_and_section *gs = EXPAND_ITEM_LIST(&section_stack, global_and_section, 2);
+                       memcpy(&gs->g, &Globals, sizeof Globals);
+                       memcpy(&gs->s, &sDefault, sizeof sDefault);
+               } else if (strcmp(sectionname+1, "pop") == 0
+                || strcmp(sectionname+1, "reset") == 0) {
+                       global_and_section *gs = ((global_and_section *)section_stack.items) + section_stack.count - 1;
+                       if (!section_stack.count)
+                               return False;
+                       memcpy(&Globals, &gs->g, sizeof Globals);
+                       memcpy(&sDefault, &gs->s, sizeof sDefault);
+                       if (sectionname[1] == 'p')
+                               section_stack.count--;
+               } else
+                       return False;
+               return True;
+       }
+
+       isglobal = strwicmp(sectionname, GLOBAL_NAME) == 0;
 
        /* if we were in a global section then do the local inits */
-       if (bInGlobalSection && !isglobal)
+       if (bInGlobalSection && !isglobal) {
+               if (!section_list.count)
+                       set_dparams(0);
                init_locals();
+       }
 
        /* if we've just struck a global section, note the fact. */
        bInGlobalSection = isglobal;
@@ -700,8 +720,8 @@ static BOOL do_section(char *sectionname)
                return True;
 
 #if 0
-       /* If we have a current service, tidy it up before moving on. */
-       if (iServiceIndex >= 0) {
+       /* 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;
@@ -713,7 +733,7 @@ static BOOL do_section(char *sectionname)
                return False;
        }
 
-       if ((iServiceIndex = add_a_service(sectionname)) < 0) {
+       if ((iSectionIndex = add_a_section(sectionname)) < 0) {
                rprintf(FLOG, "Failed to add a new module\n");
                bInGlobalSection = True;
                return False;
@@ -722,38 +742,58 @@ static BOOL do_section(char *sectionname)
        return True;
 }
 
-/* Load the services array from the services file. Return True on success,
+/* Load the modules from the config file. Return True on success,
  * False on failure. */
-BOOL lp_load(char *pszFname, int globals_only)
+int lp_load(char *pszFname, int globals_only)
 {
-       pstring n2;
-
        bInGlobalSection = True;
 
        init_globals();
 
-       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);
+}
+
+BOOL set_dparams(int syntax_check_only)
+{
+       char *equal, *val, **params = dparam_list.items;
+       unsigned j;
+
+       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 = '=';
+       }
 
-       /* We get sections first, so have to start 'behind' to make up */
-       iServiceIndex = -1;
-       return pm_process(n2, globals_only ? NULL : do_section, do_parameter);
+       return True;
 }
 
-/* Return the max number of services. */
-int lp_numservices(void)
+/* Return the max number of modules (sections). */
+int lp_num_modules(void)
 {
-       return iNumServices;
+       return section_list.count;
 }
 
-/* Return the number of the service with the given name, or -1 if it doesn't
+/* Return the number of the module with the given name, or -1 if it doesn't
  * exist. Note that this is a DIFFERENT ANIMAL from the internal function
- * getservicebyname()! This works ONLY if all services have been loaded,
- * and does not copy the found service. */
+ * getsectionbyname()! This works ONLY if all sections have been loaded,
+ * and does not copy the found section. */
 int lp_number(char *name)
 {
        int i;
 
-       for (i = iNumServices - 1; i >= 0; i--) {
+       for (i = section_list.count - 1; i >= 0; i--) {
                if (strcmp(lp_name(i), name) == 0)
                        break;
        }