save another couple of round trip latencies. This set of changes is
[rsync/rsync.git] / loadparm.c
1 /* This is based on loadparm.c from Samba, written by Andrew Tridgell
2    and Karl Auer */
3
4 /* 
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9    
10    This program is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13    GNU General Public License for more details.
14    
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 /*
21  *  Load parameters.
22  *
23  *  This module provides suitable callback functions for the params
24  *  module. It builds the internal table of service details which is
25  *  then used by the rest of the server.
26  *
27  * To add a parameter:
28  *
29  * 1) add it to the global or service structure definition
30  * 2) add it to the parm_table
31  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
32  * 4) If it's a global then initialise it in init_globals. If a local
33  *    (ie. service) parameter then initialise it in the sDefault structure
34  *  
35  *
36  * Notes:
37  *   The configuration file is processed sequentially for speed. It is NOT
38  *   accessed randomly as happens in 'real' Windows. For this reason, there
39  *   is a fair bit of sequence-dependent code here - ie., code which assumes
40  *   that certain things happen before others. In particular, the code which
41  *   happens at the boundary between sections is delicately poised, so be
42  *   careful!
43  *
44  */
45
46 #include "rsync.h"
47 #define BOOL int
48 #define False 0
49 #define True 1
50 #define Realloc realloc
51 #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
52 #define strequal(a,b) (strcasecmp(a,b)==0)
53 #define BOOLSTR(b) ((b) ? "Yes" : "No")
54 typedef char pstring[1024];
55 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
56
57 /* the following are used by loadparm for option lists */
58 typedef enum
59 {
60   P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
61   P_STRING,P_GSTRING,P_ENUM,P_SEP
62 } parm_type;
63
64 typedef enum
65 {
66   P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
67 } parm_class;
68
69 struct enum_list {
70         int value;
71         char *name;
72 };
73
74 struct parm_struct
75 {
76         char *label;
77         parm_type type;
78         parm_class class;
79         void *ptr;
80         struct enum_list *enum_list;
81         unsigned flags;
82 };
83
84 static BOOL bLoaded = False;
85
86 #ifndef GLOBAL_NAME
87 #define GLOBAL_NAME "global"
88 #endif
89
90 /* some helpful bits */
91 #define pSERVICE(i) ServicePtrs[i]
92 #define iSERVICE(i) (*pSERVICE(i))
93 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
94
95 /* 
96  * This structure describes global (ie., server-wide) parameters.
97  */
98 typedef struct
99 {
100         char *motd_file;
101         char *lock_file;
102         int syslog_facility;
103         int max_connections;
104 } global;
105
106 static global Globals;
107
108
109
110 /* 
111  * This structure describes a single service. 
112  */
113 typedef struct
114 {
115         char *name;
116         char *path;
117         char *comment;
118         BOOL read_only;
119         BOOL list;
120         char *uid;
121         char *gid;
122         char *hosts_allow;
123         char *hosts_deny;
124 } service;
125
126
127 /* This is a default service used to prime a services structure */
128 static service sDefault = 
129 {
130         NULL,    /* name */
131         NULL,    /* path */
132         NULL,    /* comment */
133         True,    /* read only */
134         True,    /* list */
135         "nobody",/* uid */
136         "nobody",/* gid */
137         NULL,    /* hosts allow */
138         NULL,    /* hosts deny */
139 };
140
141
142
143 /* local variables */
144 static service **ServicePtrs = NULL;
145 static int iNumServices = 0;
146 static int iServiceIndex = 0;
147 static BOOL bInGlobalSection = True;
148
149 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
150
151
152 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
153 static struct parm_struct parm_table[] =
154 {
155   {"max connections",  P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
156   {"motd file",        P_STRING,  P_GLOBAL, &Globals.motd_file,    NULL,   0},
157   {"lock file",        P_STRING,  P_GLOBAL, &Globals.lock_file,    NULL,   0},
158   {"syslog facility",  P_INTEGER, P_GLOBAL, &Globals.syslog_facility, NULL,0},
159   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
160   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
161   {"path",             P_STRING,  P_LOCAL,  &sDefault.path,        NULL,   0},
162   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
163   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
164   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
165   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
166   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
167   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.hosts_deny,  NULL,   0},
168   {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
169 };
170
171
172 /***************************************************************************
173 Initialise the global parameter structure.
174 ***************************************************************************/
175 static void init_globals(void)
176 {
177 #ifdef LOG_DAEMON
178         Globals.syslog_facility = LOG_DAEMON;
179 #endif
180         Globals.lock_file = "/var/run/rsyncd.lock";
181 }
182
183 /***************************************************************************
184 Initialise the sDefault parameter structure.
185 ***************************************************************************/
186 static void init_locals(void)
187 {
188 }
189
190
191 /*
192    In this section all the functions that are used to access the 
193    parameters from the rest of the program are defined 
194 */
195
196 #define FN_GLOBAL_STRING(fn_name,ptr) \
197  char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
198 #define FN_GLOBAL_BOOL(fn_name,ptr) \
199  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
200 #define FN_GLOBAL_CHAR(fn_name,ptr) \
201  char fn_name(void) {return(*(char *)(ptr));}
202 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
203  int fn_name(void) {return(*(int *)(ptr));}
204
205 #define FN_LOCAL_STRING(fn_name,val) \
206  char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
207 #define FN_LOCAL_BOOL(fn_name,val) \
208  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
209 #define FN_LOCAL_CHAR(fn_name,val) \
210  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
211 #define FN_LOCAL_INTEGER(fn_name,val) \
212  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
213
214
215 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
216 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
217 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
218 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
219 FN_LOCAL_STRING(lp_name, name)
220 FN_LOCAL_STRING(lp_comment, comment)
221 FN_LOCAL_STRING(lp_path, path)
222 FN_LOCAL_BOOL(lp_read_only, read_only)
223 FN_LOCAL_BOOL(lp_list, list)
224 FN_LOCAL_STRING(lp_uid, uid)
225 FN_LOCAL_STRING(lp_gid, gid)
226 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
227 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
228
229 /* local prototypes */
230 static int    strwicmp( char *psz1, char *psz2 );
231 static int    map_parameter( char *parmname);
232 static BOOL   set_boolean( BOOL *pb, char *parmvalue );
233 static int    getservicebyname(char *name, service *pserviceDest);
234 static void   copy_service( service *pserviceDest, 
235                             service *pserviceSource);
236 static BOOL   do_parameter(char *parmname, char *parmvalue);
237 static BOOL   do_section(char *sectionname);
238
239
240 /***************************************************************************
241 initialise a service to the defaults
242 ***************************************************************************/
243 static void init_service(service *pservice)
244 {
245         bzero((char *)pservice,sizeof(service));
246         copy_service(pservice,&sDefault);
247 }
248
249 static void string_set(char **s, char *v)
250 {
251         if (!v) {
252                 *s = NULL;
253                 return;
254         }
255         *s = strdup(v);
256         if (!*s) exit_cleanup(1);
257 }
258
259
260 /***************************************************************************
261 add a new service to the services array initialising it with the given 
262 service
263 ***************************************************************************/
264 static int add_a_service(service *pservice, char *name)
265 {
266   int i;
267   service tservice;
268   int num_to_alloc = iNumServices+1;
269
270   tservice = *pservice;
271
272   /* it might already exist */
273   if (name) 
274     {
275       i = getservicebyname(name,NULL);
276       if (i >= 0)
277         return(i);
278     }
279
280   i = iNumServices;
281
282   ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
283   if (ServicePtrs)
284           pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
285
286   if (!ServicePtrs || !pSERVICE(iNumServices))
287           return(-1);
288
289   iNumServices++;
290
291   init_service(pSERVICE(i));
292   copy_service(pSERVICE(i),&tservice);
293   if (name)
294     string_set(&iSERVICE(i).name,name);  
295
296   return(i);
297 }
298
299 /***************************************************************************
300 Do a case-insensitive, whitespace-ignoring string compare.
301 ***************************************************************************/
302 static int strwicmp(char *psz1, char *psz2)
303 {
304    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
305    /* appropriate value. */
306    if (psz1 == psz2)
307       return (0);
308    else
309       if (psz1 == NULL)
310          return (-1);
311       else
312           if (psz2 == NULL)
313               return (1);
314
315    /* sync the strings on first non-whitespace */
316    while (1)
317    {
318       while (isspace(*psz1))
319          psz1++;
320       while (isspace(*psz2))
321          psz2++;
322       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
323          break;
324       psz1++;
325       psz2++;
326    }
327    return (*psz1 - *psz2);
328 }
329
330 /***************************************************************************
331 Map a parameter's string representation to something we can use. 
332 Returns False if the parameter string is not recognised, else TRUE.
333 ***************************************************************************/
334 static int map_parameter(char *parmname)
335 {
336    int iIndex;
337
338    if (*parmname == '-')
339      return(-1);
340
341    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
342       if (strwicmp(parm_table[iIndex].label, parmname) == 0)
343          return(iIndex);
344
345    rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
346    return(-1);
347 }
348
349
350 /***************************************************************************
351 Set a boolean variable from the text value stored in the passed string.
352 Returns True in success, False if the passed string does not correctly 
353 represent a boolean.
354 ***************************************************************************/
355 static BOOL set_boolean(BOOL *pb, char *parmvalue)
356 {
357    BOOL bRetval;
358
359    bRetval = True;
360    if (strwicmp(parmvalue, "yes") == 0 ||
361        strwicmp(parmvalue, "true") == 0 ||
362        strwicmp(parmvalue, "1") == 0)
363       *pb = True;
364    else
365       if (strwicmp(parmvalue, "no") == 0 ||
366           strwicmp(parmvalue, "False") == 0 ||
367           strwicmp(parmvalue, "0") == 0)
368          *pb = False;
369       else
370       {
371          rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
372                parmvalue);
373          bRetval = False;
374       }
375    return (bRetval);
376 }
377
378 /***************************************************************************
379 Find a service by name. Otherwise works like get_service.
380 ***************************************************************************/
381 static int getservicebyname(char *name, service *pserviceDest)
382 {
383    int iService;
384
385    for (iService = iNumServices - 1; iService >= 0; iService--)
386       if (strwicmp(iSERVICE(iService).name, name) == 0) 
387       {
388          if (pserviceDest != NULL)
389            copy_service(pserviceDest, pSERVICE(iService));
390          break;
391       }
392
393    return (iService);
394 }
395
396
397
398 /***************************************************************************
399 Copy a service structure to another
400
401 ***************************************************************************/
402 static void copy_service(service *pserviceDest, 
403                          service *pserviceSource)
404 {
405   int i;
406
407   for (i=0;parm_table[i].label;i++)
408     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
409         void *def_ptr = parm_table[i].ptr;
410         void *src_ptr = 
411           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
412         void *dest_ptr = 
413           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
414
415         switch (parm_table[i].type)
416           {
417           case P_BOOL:
418           case P_BOOLREV:
419             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
420             break;
421
422           case P_INTEGER:
423           case P_ENUM:
424           case P_OCTAL:
425             *(int *)dest_ptr = *(int *)src_ptr;
426             break;
427
428           case P_CHAR:
429             *(char *)dest_ptr = *(char *)src_ptr;
430             break;
431
432           case P_STRING:
433             string_set(dest_ptr,*(char **)src_ptr);
434             break;
435
436           default:
437             break;
438           }
439       }
440 }
441
442
443 /***************************************************************************
444 Process a parameter for a particular service number. If snum < 0
445 then assume we are in the globals
446 ***************************************************************************/
447 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
448 {
449    int parmnum, i;
450    void *parm_ptr=NULL; /* where we are going to store the result */
451    void *def_ptr=NULL;
452
453    parmnum = map_parameter(parmname);
454
455    if (parmnum < 0)
456      {
457        rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
458        return(True);
459      }
460
461    def_ptr = parm_table[parmnum].ptr;
462
463    /* we might point at a service, the default service or a global */
464    if (snum < 0) {
465      parm_ptr = def_ptr;
466    } else {
467        if (parm_table[parmnum].class == P_GLOBAL) {
468            rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
469            return(True);
470          }
471        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
472    }
473
474    /* now switch on the type of variable it is */
475    switch (parm_table[parmnum].type)
476      {
477      case P_BOOL:
478        set_boolean(parm_ptr,parmvalue);
479        break;
480
481      case P_BOOLREV:
482        set_boolean(parm_ptr,parmvalue);
483        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
484        break;
485
486      case P_INTEGER:
487        *(int *)parm_ptr = atoi(parmvalue);
488        break;
489
490      case P_CHAR:
491        *(char *)parm_ptr = *parmvalue;
492        break;
493
494      case P_OCTAL:
495        sscanf(parmvalue,"%o",(int *)parm_ptr);
496        break;
497
498      case P_STRING:
499        string_set(parm_ptr,parmvalue);
500        break;
501
502      case P_GSTRING:
503        strcpy((char *)parm_ptr,parmvalue);
504        break;
505
506      case P_ENUM:
507              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
508                      if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
509                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
510                              break;
511                      }
512              }
513              break;
514      case P_SEP:
515              break;
516      }
517
518    return(True);
519 }
520
521 /***************************************************************************
522 Process a parameter.
523 ***************************************************************************/
524 static BOOL do_parameter(char *parmname, char *parmvalue)
525 {
526    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
527 }
528
529 /***************************************************************************
530 Process a new section (service). At this stage all sections are services.
531 Later we'll have special sections that permit server parameters to be set.
532 Returns True on success, False on failure.
533 ***************************************************************************/
534 static BOOL do_section(char *sectionname)
535 {
536    BOOL bRetval;
537    BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
538    bRetval = False;
539
540    /* if we were in a global section then do the local inits */
541    if (bInGlobalSection && !isglobal)
542      init_locals();
543
544    /* if we've just struck a global section, note the fact. */
545    bInGlobalSection = isglobal;   
546
547    /* check for multiple global sections */
548    if (bInGlobalSection)
549    {
550      return(True);
551    }
552
553    /* if we have a current service, tidy it up before moving on */
554    bRetval = True;
555
556    if (iServiceIndex >= 0)
557      bRetval = True;
558
559    /* if all is still well, move to the next record in the services array */
560    if (bRetval)
561      {
562        /* We put this here to avoid an odd message order if messages are */
563        /* issued by the post-processing of a previous section. */
564
565        if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
566          {
567            rprintf(FERROR,"Failed to add a new service\n");
568            return(False);
569          }
570      }
571
572    return (bRetval);
573 }
574
575
576 /***************************************************************************
577 Load the services array from the services file. Return True on success, 
578 False on failure.
579 ***************************************************************************/
580 BOOL lp_load(char *pszFname)
581 {
582   pstring n2;
583   BOOL bRetval;
584  
585   bRetval = False;
586
587   bInGlobalSection = True;
588   
589   init_globals();
590
591   pstrcpy(n2,pszFname);
592
593   /* We get sections first, so have to start 'behind' to make up */
594   iServiceIndex = -1;
595   bRetval = pm_process(n2, do_section, do_parameter);
596   
597   bLoaded = True;
598
599   return (bRetval);
600 }
601
602
603 /***************************************************************************
604 return the max number of services
605 ***************************************************************************/
606 int lp_numservices(void)
607 {
608   return(iNumServices);
609 }
610
611 /***************************************************************************
612 Return the number of the service with the given name, or -1 if it doesn't
613 exist. Note that this is a DIFFERENT ANIMAL from the internal function
614 getservicebyname()! This works ONLY if all services have been loaded, and
615 does not copy the found service.
616 ***************************************************************************/
617 int lp_number(char *name)
618 {
619    int iService;
620
621    for (iService = iNumServices - 1; iService >= 0; iService--)
622       if (strequal(lp_name(iService), name)) 
623          break;
624
625    return (iService);
626 }
627