Optimize server for special case of a long list of includes ("+") followed
[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 PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
51 #define strequal(a,b) (strcasecmp(a,b)==0)
52 #define BOOLSTR(b) ((b) ? "Yes" : "No")
53 typedef char pstring[1024];
54 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
55
56 /* the following are used by loadparm for option lists */
57 typedef enum
58 {
59         P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
60         P_STRING,P_GSTRING,P_ENUM,P_SEP
61 } parm_type;
62
63 typedef enum
64 {
65         P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
66 } parm_class;
67
68 struct enum_list {
69         int value;
70         char *name;
71 };
72
73 struct parm_struct
74 {
75         char *label;
76         parm_type type;
77         parm_class class;
78         void *ptr;
79         struct enum_list *enum_list;
80         unsigned flags;
81 };
82
83 static BOOL bLoaded = False;
84
85 #ifndef GLOBAL_NAME
86 #define GLOBAL_NAME "global"
87 #endif
88
89 /* some helpful bits */
90 #define pSERVICE(i) ServicePtrs[i]
91 #define iSERVICE(i) (*pSERVICE(i))
92 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
93
94 /* 
95  * This structure describes global (ie., server-wide) parameters.
96  */
97 typedef struct
98 {
99         char *motd_file;
100         char *lock_file;
101         char *log_file;
102         int syslog_facility;
103         int max_connections;
104         char *socket_options;
105 } global;
106
107 static global Globals;
108
109
110
111 /* 
112  * This structure describes a single service. 
113  */
114 typedef struct
115 {
116         char *name;
117         char *path;
118         char *comment;
119         BOOL read_only;
120         BOOL list;
121         char *uid;
122         char *gid;
123         char *hosts_allow;
124         char *hosts_deny;
125         char *auth_users;
126         char *secrets_file;
127         char *exclude;
128         char *exclude_from;
129 } service;
130
131
132 /* This is a default service used to prime a services structure */
133 static service sDefault = 
134 {
135         NULL,    /* name */
136         NULL,    /* path */
137         NULL,    /* comment */
138         True,    /* read only */
139         True,    /* list */
140         "nobody",/* uid */
141         "nobody",/* gid */
142         NULL,    /* hosts allow */
143         NULL,    /* hosts deny */
144         NULL,    /* auth users */
145         NULL,    /* secrets file */
146         NULL,    /* exclude */
147         NULL,    /* exclude from */
148 };
149
150
151
152 /* local variables */
153 static service **ServicePtrs = NULL;
154 static int iNumServices = 0;
155 static int iServiceIndex = 0;
156 static BOOL bInGlobalSection = True;
157
158 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
159
160 static struct enum_list enum_facilities[] = {
161 #ifdef LOG_AUTH
162         { LOG_AUTH, "auth" },
163 #endif
164 #ifdef LOG_AUTHPRIV
165         { LOG_AUTHPRIV, "authpriv" },
166 #endif
167 #ifdef LOG_CRON
168         { LOG_CRON, "cron" },
169 #endif
170 #ifdef LOG_DAEMON
171         { LOG_DAEMON, "daemon" },
172 #endif
173 #ifdef LOG_FTP
174         { LOG_FTP, "ftp" },
175 #endif
176 #ifdef LOG_KERN
177         { LOG_KERN, "kern" },
178 #endif
179 #ifdef LOG_LPR
180         { LOG_LPR, "lpr" },
181 #endif
182 #ifdef LOG_MAIL
183         { LOG_MAIL, "mail" },
184 #endif
185 #ifdef LOG_NEWS
186         { LOG_NEWS, "news" },
187 #endif
188 #ifdef LOG_AUTH
189         { LOG_AUTH, "security" },               
190 #endif
191 #ifdef LOG_SYSLOG
192         { LOG_SYSLOG, "syslog" },
193 #endif
194 #ifdef LOG_USER
195         { LOG_USER, "user" },
196 #endif
197 #ifdef LOG_UUCP
198         { LOG_UUCP, "uucp" },
199 #endif
200 #ifdef LOG_LOCAL0
201         { LOG_LOCAL0, "local0" },
202 #endif
203 #ifdef LOG_LOCAL1
204         { LOG_LOCAL1, "local1" },
205 #endif
206 #ifdef LOG_LOCAL2
207         { LOG_LOCAL2, "local2" },
208 #endif
209 #ifdef LOG_LOCAL3
210         { LOG_LOCAL3, "local3" },
211 #endif
212 #ifdef LOG_LOCAL4
213         { LOG_LOCAL4, "local4" },
214 #endif
215 #ifdef LOG_LOCAL5
216         { LOG_LOCAL5, "local5" },
217 #endif
218 #ifdef LOG_LOCAL6
219         { LOG_LOCAL6, "local6" },
220 #endif
221 #ifdef LOG_LOCAL7
222         { LOG_LOCAL7, "local7" },
223 #endif
224         { -1, NULL }};
225
226
227 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
228 static struct parm_struct parm_table[] =
229 {
230   {"max connections",  P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
231   {"motd file",        P_STRING,  P_GLOBAL, &Globals.motd_file,    NULL,   0},
232   {"lock file",        P_STRING,  P_GLOBAL, &Globals.lock_file,    NULL,   0},
233   {"syslog facility",  P_ENUM,    P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
234   {"socket options",   P_STRING,  P_GLOBAL, &Globals.socket_options,NULL,  0},
235   {"log file",         P_STRING,  P_GLOBAL, &Globals.log_file,      NULL,  0},
236
237   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
238   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
239   {"path",             P_STRING,  P_LOCAL,  &sDefault.path,        NULL,   0},
240   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
241   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
242   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
243   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
244   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
245   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.hosts_deny,  NULL,   0},
246   {"auth users",       P_STRING,  P_LOCAL,  &sDefault.auth_users,  NULL,   0},
247   {"secrets file",     P_STRING,  P_LOCAL,  &sDefault.secrets_file,NULL,   0},
248   {"exclude",          P_STRING,  P_LOCAL,  &sDefault.exclude,     NULL,   0},
249   {"exclude from",     P_STRING,  P_LOCAL,  &sDefault.exclude_from,NULL,   0},
250   {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
251 };
252
253
254 /***************************************************************************
255 Initialise the global parameter structure.
256 ***************************************************************************/
257 static void init_globals(void)
258 {
259         memset(&Globals, 0, sizeof(Globals));
260 #ifdef LOG_DAEMON
261         Globals.syslog_facility = LOG_DAEMON;
262 #endif
263         Globals.lock_file = "/var/run/rsyncd.lock";
264 }
265
266 /***************************************************************************
267 Initialise the sDefault parameter structure.
268 ***************************************************************************/
269 static void init_locals(void)
270 {
271 }
272
273
274 /*
275    In this section all the functions that are used to access the 
276    parameters from the rest of the program are defined 
277 */
278
279 #define FN_GLOBAL_STRING(fn_name,ptr) \
280  char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
281 #define FN_GLOBAL_BOOL(fn_name,ptr) \
282  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
283 #define FN_GLOBAL_CHAR(fn_name,ptr) \
284  char fn_name(void) {return(*(char *)(ptr));}
285 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
286  int fn_name(void) {return(*(int *)(ptr));}
287
288 #define FN_LOCAL_STRING(fn_name,val) \
289  char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
290 #define FN_LOCAL_BOOL(fn_name,val) \
291  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
292 #define FN_LOCAL_CHAR(fn_name,val) \
293  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
294 #define FN_LOCAL_INTEGER(fn_name,val) \
295  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
296
297
298 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
299 FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
300 FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
301 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
302 FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
303 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
304
305 FN_LOCAL_STRING(lp_name, name)
306 FN_LOCAL_STRING(lp_comment, comment)
307 FN_LOCAL_STRING(lp_path, path)
308 FN_LOCAL_BOOL(lp_read_only, read_only)
309 FN_LOCAL_BOOL(lp_list, list)
310 FN_LOCAL_STRING(lp_uid, uid)
311 FN_LOCAL_STRING(lp_gid, gid)
312 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
313 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
314 FN_LOCAL_STRING(lp_auth_users, auth_users)
315 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
316 FN_LOCAL_STRING(lp_exclude, exclude)
317 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
318
319 /* local prototypes */
320 static int    strwicmp( char *psz1, char *psz2 );
321 static int    map_parameter( char *parmname);
322 static BOOL   set_boolean( BOOL *pb, char *parmvalue );
323 static int    getservicebyname(char *name, service *pserviceDest);
324 static void   copy_service( service *pserviceDest, 
325                             service *pserviceSource);
326 static BOOL   do_parameter(char *parmname, char *parmvalue);
327 static BOOL   do_section(char *sectionname);
328
329
330 /***************************************************************************
331 initialise a service to the defaults
332 ***************************************************************************/
333 static void init_service(service *pservice)
334 {
335         memset((char *)pservice,0,sizeof(service));
336         copy_service(pservice,&sDefault);
337 }
338
339 static void string_set(char **s, char *v)
340 {
341         if (!v) {
342                 *s = NULL;
343                 return;
344         }
345         *s = strdup(v);
346         if (!*s) exit_cleanup(1);
347 }
348
349
350 /***************************************************************************
351 add a new service to the services array initialising it with the given 
352 service
353 ***************************************************************************/
354 static int add_a_service(service *pservice, char *name)
355 {
356   int i;
357   service tservice;
358   int num_to_alloc = iNumServices+1;
359
360   tservice = *pservice;
361
362   /* it might already exist */
363   if (name) 
364     {
365       i = getservicebyname(name,NULL);
366       if (i >= 0)
367         return(i);
368     }
369
370   i = iNumServices;
371
372   ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
373
374   if (ServicePtrs)
375           pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
376
377   if (!ServicePtrs || !pSERVICE(iNumServices))
378           return(-1);
379
380   iNumServices++;
381
382   init_service(pSERVICE(i));
383   copy_service(pSERVICE(i),&tservice);
384   if (name)
385     string_set(&iSERVICE(i).name,name);  
386
387   return(i);
388 }
389
390 /***************************************************************************
391 Do a case-insensitive, whitespace-ignoring string compare.
392 ***************************************************************************/
393 static int strwicmp(char *psz1, char *psz2)
394 {
395    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
396    /* appropriate value. */
397    if (psz1 == psz2)
398       return (0);
399    else
400       if (psz1 == NULL)
401          return (-1);
402       else
403           if (psz2 == NULL)
404               return (1);
405
406    /* sync the strings on first non-whitespace */
407    while (1)
408    {
409       while (isspace(*psz1))
410          psz1++;
411       while (isspace(*psz2))
412          psz2++;
413       if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
414          break;
415       psz1++;
416       psz2++;
417    }
418    return (*psz1 - *psz2);
419 }
420
421 /***************************************************************************
422 Map a parameter's string representation to something we can use. 
423 Returns False if the parameter string is not recognised, else TRUE.
424 ***************************************************************************/
425 static int map_parameter(char *parmname)
426 {
427    int iIndex;
428
429    if (*parmname == '-')
430      return(-1);
431
432    for (iIndex = 0; parm_table[iIndex].label; iIndex++) 
433       if (strwicmp(parm_table[iIndex].label, parmname) == 0)
434          return(iIndex);
435
436    rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
437    return(-1);
438 }
439
440
441 /***************************************************************************
442 Set a boolean variable from the text value stored in the passed string.
443 Returns True in success, False if the passed string does not correctly 
444 represent a boolean.
445 ***************************************************************************/
446 static BOOL set_boolean(BOOL *pb, char *parmvalue)
447 {
448    BOOL bRetval;
449
450    bRetval = True;
451    if (strwicmp(parmvalue, "yes") == 0 ||
452        strwicmp(parmvalue, "true") == 0 ||
453        strwicmp(parmvalue, "1") == 0)
454       *pb = True;
455    else
456       if (strwicmp(parmvalue, "no") == 0 ||
457           strwicmp(parmvalue, "False") == 0 ||
458           strwicmp(parmvalue, "0") == 0)
459          *pb = False;
460       else
461       {
462          rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
463                parmvalue);
464          bRetval = False;
465       }
466    return (bRetval);
467 }
468
469 /***************************************************************************
470 Find a service by name. Otherwise works like get_service.
471 ***************************************************************************/
472 static int getservicebyname(char *name, service *pserviceDest)
473 {
474    int iService;
475
476    for (iService = iNumServices - 1; iService >= 0; iService--)
477       if (strwicmp(iSERVICE(iService).name, name) == 0) 
478       {
479          if (pserviceDest != NULL)
480            copy_service(pserviceDest, pSERVICE(iService));
481          break;
482       }
483
484    return (iService);
485 }
486
487
488
489 /***************************************************************************
490 Copy a service structure to another
491
492 ***************************************************************************/
493 static void copy_service(service *pserviceDest, 
494                          service *pserviceSource)
495 {
496   int i;
497
498   for (i=0;parm_table[i].label;i++)
499     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
500         void *def_ptr = parm_table[i].ptr;
501         void *src_ptr = 
502           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
503         void *dest_ptr = 
504           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
505
506         switch (parm_table[i].type)
507           {
508           case P_BOOL:
509           case P_BOOLREV:
510             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
511             break;
512
513           case P_INTEGER:
514           case P_ENUM:
515           case P_OCTAL:
516             *(int *)dest_ptr = *(int *)src_ptr;
517             break;
518
519           case P_CHAR:
520             *(char *)dest_ptr = *(char *)src_ptr;
521             break;
522
523           case P_STRING:
524             string_set(dest_ptr,*(char **)src_ptr);
525             break;
526
527           default:
528             break;
529           }
530       }
531 }
532
533
534 /***************************************************************************
535 Process a parameter for a particular service number. If snum < 0
536 then assume we are in the globals
537 ***************************************************************************/
538 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
539 {
540    int parmnum, i;
541    void *parm_ptr=NULL; /* where we are going to store the result */
542    void *def_ptr=NULL;
543
544    parmnum = map_parameter(parmname);
545
546    if (parmnum < 0)
547      {
548        rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
549        return(True);
550      }
551
552    def_ptr = parm_table[parmnum].ptr;
553
554    /* we might point at a service, the default service or a global */
555    if (snum < 0) {
556      parm_ptr = def_ptr;
557    } else {
558        if (parm_table[parmnum].class == P_GLOBAL) {
559            rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
560            return(True);
561          }
562        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
563    }
564
565    /* now switch on the type of variable it is */
566    switch (parm_table[parmnum].type)
567      {
568      case P_BOOL:
569        set_boolean(parm_ptr,parmvalue);
570        break;
571
572      case P_BOOLREV:
573        set_boolean(parm_ptr,parmvalue);
574        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
575        break;
576
577      case P_INTEGER:
578        *(int *)parm_ptr = atoi(parmvalue);
579        break;
580
581      case P_CHAR:
582        *(char *)parm_ptr = *parmvalue;
583        break;
584
585      case P_OCTAL:
586        sscanf(parmvalue,"%o",(int *)parm_ptr);
587        break;
588
589      case P_STRING:
590        string_set(parm_ptr,parmvalue);
591        break;
592
593      case P_GSTRING:
594        strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
595        break;
596
597      case P_ENUM:
598              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
599                      if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
600                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
601                              break;
602                      }
603              }
604              if (!parm_table[parmnum].enum_list[i].name) {
605                      if (atoi(parmvalue) > 0)
606                              *(int *)parm_ptr = atoi(parmvalue);
607              }
608              break;
609      case P_SEP:
610              break;
611      }
612
613    return(True);
614 }
615
616 /***************************************************************************
617 Process a parameter.
618 ***************************************************************************/
619 static BOOL do_parameter(char *parmname, char *parmvalue)
620 {
621    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
622 }
623
624 /***************************************************************************
625 Process a new section (service). At this stage all sections are services.
626 Later we'll have special sections that permit server parameters to be set.
627 Returns True on success, False on failure.
628 ***************************************************************************/
629 static BOOL do_section(char *sectionname)
630 {
631    BOOL bRetval;
632    BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
633    bRetval = False;
634
635    /* if we were in a global section then do the local inits */
636    if (bInGlobalSection && !isglobal)
637      init_locals();
638
639    /* if we've just struck a global section, note the fact. */
640    bInGlobalSection = isglobal;   
641
642    /* check for multiple global sections */
643    if (bInGlobalSection)
644    {
645      return(True);
646    }
647
648    /* if we have a current service, tidy it up before moving on */
649    bRetval = True;
650
651    if (iServiceIndex >= 0)
652      bRetval = True;
653
654    /* if all is still well, move to the next record in the services array */
655    if (bRetval)
656      {
657        /* We put this here to avoid an odd message order if messages are */
658        /* issued by the post-processing of a previous section. */
659
660        if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
661          {
662            rprintf(FERROR,"Failed to add a new service\n");
663            return(False);
664          }
665      }
666
667    return (bRetval);
668 }
669
670
671 /***************************************************************************
672 Load the services array from the services file. Return True on success, 
673 False on failure.
674 ***************************************************************************/
675 BOOL lp_load(char *pszFname, int globals_only)
676 {
677         pstring n2;
678         BOOL bRetval;
679  
680         bRetval = False;
681
682         bInGlobalSection = True;
683   
684         init_globals();
685
686         pstrcpy(n2,pszFname);
687
688         /* We get sections first, so have to start 'behind' to make up */
689         iServiceIndex = -1;
690         bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
691   
692         bLoaded = True;
693
694         return (bRetval);
695 }
696
697
698 /***************************************************************************
699 return the max number of services
700 ***************************************************************************/
701 int lp_numservices(void)
702 {
703   return(iNumServices);
704 }
705
706 /***************************************************************************
707 Return the number of the service with the given name, or -1 if it doesn't
708 exist. Note that this is a DIFFERENT ANIMAL from the internal function
709 getservicebyname()! This works ONLY if all services have been loaded, and
710 does not copy the found service.
711 ***************************************************************************/
712 int lp_number(char *name)
713 {
714    int iService;
715
716    for (iService = iNumServices - 1; iService >= 0; iService--)
717       if (strequal(lp_name(iService), name)) 
718          break;
719
720    return (iService);
721 }
722