Added a per-module "temp dir" setting.
[rsync/rsync.git] / loadparm.c
1 /* This is based on loadparm.c from Samba, written by Andrew Tridgell
2    and Karl Auer */
3
4 /* some fixes
5  *
6  * Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
7  */
8
9 /*
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 */
24
25 /*
26  *  Load parameters.
27  *
28  *  This module provides suitable callback functions for the params
29  *  module. It builds the internal table of service details which is
30  *  then used by the rest of the server.
31  *
32  * To add a parameter:
33  *
34  * 1) add it to the global or service structure definition
35  * 2) add it to the parm_table
36  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
37  * 4) If it's a global then initialise it in init_globals. If a local
38  *    (ie. service) parameter then initialise it in the sDefault structure
39  *
40  *
41  * Notes:
42  *   The configuration file is processed sequentially for speed. It is NOT
43  *   accessed randomly as happens in 'real' Windows. For this reason, there
44  *   is a fair bit of sequence-dependent code here - ie., code which assumes
45  *   that certain things happen before others. In particular, the code which
46  *   happens at the boundary between sections is delicately poised, so be
47  *   careful!
48  *
49  */
50
51 /* TODO: Parameter to set debug level on server. */
52
53 #include "rsync.h"
54 #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
55 #define strequal(a,b) (strcasecmp(a,b)==0)
56 #define BOOLSTR(b) ((b) ? "Yes" : "No")
57 typedef char pstring[1024];
58 #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))
59
60 /* the following are used by loadparm for option lists */
61 typedef enum
62 {
63         P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
64         P_PATH,P_STRING,P_GSTRING,P_ENUM,P_SEP
65 } parm_type;
66
67 typedef enum
68 {
69         P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
70 } parm_class;
71
72 struct enum_list {
73         int value;
74         char *name;
75 };
76
77 struct parm_struct
78 {
79         char *label;
80         parm_type type;
81         parm_class class;
82         void *ptr;
83         struct enum_list *enum_list;
84         unsigned flags;
85 };
86
87 #ifndef GLOBAL_NAME
88 #define GLOBAL_NAME "global"
89 #endif
90
91 /* some helpful bits */
92 #define pSERVICE(i) ServicePtrs[i]
93 #define iSERVICE(i) (*pSERVICE(i))
94 #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
95
96 /*
97  * This structure describes global (ie., server-wide) parameters.
98  */
99 typedef struct
100 {
101         char *bind_address;
102         char *log_file;
103         char *motd_file;
104         char *pid_file;
105         char *socket_options;
106
107         int rsync_port;
108         int syslog_facility;
109 } global;
110
111 static global Globals;
112
113
114 /*
115  * This structure describes a single service.  Their order must match the
116  * initializers below, which you can accomplish by keeping each sub-section
117  * sorted.  (e.g. in vim, just visually select the subsection and use !sort.)
118  */
119 typedef struct
120 {
121         char *auth_users;
122         char *comment;
123         char *dont_compress;
124         char *exclude;
125         char *exclude_from;
126         char *filter;
127         char *gid;
128         char *hosts_allow;
129         char *hosts_deny;
130         char *include;
131         char *include_from;
132         char *lock_file;
133         char *log_format;
134         char *name;
135         char *path;
136         char *postxfer_exec;
137         char *prexfer_exec;
138         char *refuse_options;
139         char *secrets_file;
140         char *temp_dir;
141         char *uid;
142
143         int max_connections;
144         int max_verbosity;
145         int timeout;
146
147         BOOL ignore_errors;
148         BOOL ignore_nonreadable;
149         BOOL list;
150         BOOL read_only;
151         BOOL strict_modes;
152         BOOL transfer_logging;
153         BOOL use_chroot;
154         BOOL write_only;
155 } service;
156
157
158 /* This is a default service used to prime a services structure */
159 static service sDefault =
160 {
161  /* auth users */       NULL,
162  /* comment */          NULL,
163  /* dont compress */    "*.gz *.tgz *.zip *.z *.rpm *.deb *.iso *.bz2 *.tbz",
164  /* exclude */          NULL,
165  /* exclude from */     NULL,
166  /* filter */           NULL,
167  /* gid */              NOBODY_GROUP,
168  /* hosts allow */      NULL,
169  /* hosts deny */       NULL,
170  /* include */          NULL,
171  /* include from */     NULL,
172  /* lock file */        DEFAULT_LOCK_FILE,
173  /* log format */       "%o %h [%a] %m (%u) %f %l",
174  /* name */             NULL,
175  /* path */             NULL,
176  /* postxfer_exec */    NULL,
177  /* prexfer_exec */     NULL,
178  /* refuse options */   NULL,
179  /* secrets file */     NULL,
180  /* temp_dir */         NULL,
181  /* uid */              NOBODY_USER,
182
183  /* max connections */  0,
184  /* max verbosity */    1,
185  /* timeout */          0,
186
187  /* ignore errors */      False,
188  /* ignore nonreadable */ False,
189  /* list */               True,
190  /* read only */          True,
191  /* strict modes */       True,
192  /* transfer logging */   False,
193  /* use chroot */         True,
194  /* write only */         False,
195 };
196
197
198
199 /* local variables */
200 static service **ServicePtrs = NULL;
201 static int iNumServices = 0;
202 static int iServiceIndex = 0;
203 static BOOL bInGlobalSection = True;
204
205 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
206
207 static struct enum_list enum_facilities[] = {
208 #ifdef LOG_AUTH
209         { LOG_AUTH, "auth" },
210 #endif
211 #ifdef LOG_AUTHPRIV
212         { LOG_AUTHPRIV, "authpriv" },
213 #endif
214 #ifdef LOG_CRON
215         { LOG_CRON, "cron" },
216 #endif
217 #ifdef LOG_DAEMON
218         { LOG_DAEMON, "daemon" },
219 #endif
220 #ifdef LOG_FTP
221         { LOG_FTP, "ftp" },
222 #endif
223 #ifdef LOG_KERN
224         { LOG_KERN, "kern" },
225 #endif
226 #ifdef LOG_LPR
227         { LOG_LPR, "lpr" },
228 #endif
229 #ifdef LOG_MAIL
230         { LOG_MAIL, "mail" },
231 #endif
232 #ifdef LOG_NEWS
233         { LOG_NEWS, "news" },
234 #endif
235 #ifdef LOG_AUTH
236         { LOG_AUTH, "security" },
237 #endif
238 #ifdef LOG_SYSLOG
239         { LOG_SYSLOG, "syslog" },
240 #endif
241 #ifdef LOG_USER
242         { LOG_USER, "user" },
243 #endif
244 #ifdef LOG_UUCP
245         { LOG_UUCP, "uucp" },
246 #endif
247 #ifdef LOG_LOCAL0
248         { LOG_LOCAL0, "local0" },
249 #endif
250 #ifdef LOG_LOCAL1
251         { LOG_LOCAL1, "local1" },
252 #endif
253 #ifdef LOG_LOCAL2
254         { LOG_LOCAL2, "local2" },
255 #endif
256 #ifdef LOG_LOCAL3
257         { LOG_LOCAL3, "local3" },
258 #endif
259 #ifdef LOG_LOCAL4
260         { LOG_LOCAL4, "local4" },
261 #endif
262 #ifdef LOG_LOCAL5
263         { LOG_LOCAL5, "local5" },
264 #endif
265 #ifdef LOG_LOCAL6
266         { LOG_LOCAL6, "local6" },
267 #endif
268 #ifdef LOG_LOCAL7
269         { LOG_LOCAL7, "local7" },
270 #endif
271         { -1, NULL }};
272
273
274 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
275 static struct parm_struct parm_table[] =
276 {
277  {"address",           P_STRING, P_GLOBAL,&Globals.bind_address,       NULL,0},
278  {"log file",          P_STRING, P_GLOBAL,&Globals.log_file,           NULL,0},
279  {"motd file",         P_STRING, P_GLOBAL,&Globals.motd_file,          NULL,0},
280  {"pid file",          P_STRING, P_GLOBAL,&Globals.pid_file,           NULL,0},
281  {"port",              P_INTEGER,P_GLOBAL,&Globals.rsync_port,         NULL,0},
282  {"socket options",    P_STRING, P_GLOBAL,&Globals.socket_options,     NULL,0},
283  {"syslog facility",   P_ENUM,   P_GLOBAL,&Globals.syslog_facility,enum_facilities,0},
284
285  {"auth users",        P_STRING, P_LOCAL, &sDefault.auth_users,        NULL,0},
286  {"comment",           P_STRING, P_LOCAL, &sDefault.comment,           NULL,0},
287  {"dont compress",     P_STRING, P_LOCAL, &sDefault.dont_compress,     NULL,0},
288  {"exclude from",      P_STRING, P_LOCAL, &sDefault.exclude_from,      NULL,0},
289  {"exclude",           P_STRING, P_LOCAL, &sDefault.exclude,           NULL,0},
290  {"filter",            P_STRING, P_LOCAL, &sDefault.filter,            NULL,0},
291  {"gid",               P_STRING, P_LOCAL, &sDefault.gid,               NULL,0},
292  {"hosts allow",       P_STRING, P_LOCAL, &sDefault.hosts_allow,       NULL,0},
293  {"hosts deny",        P_STRING, P_LOCAL, &sDefault.hosts_deny,        NULL,0},
294  {"ignore errors",     P_BOOL,   P_LOCAL, &sDefault.ignore_errors,     NULL,0},
295  {"ignore nonreadable",P_BOOL,   P_LOCAL, &sDefault.ignore_nonreadable,NULL,0},
296  {"include from",      P_STRING, P_LOCAL, &sDefault.include_from,      NULL,0},
297  {"include",           P_STRING, P_LOCAL, &sDefault.include,           NULL,0},
298  {"list",              P_BOOL,   P_LOCAL, &sDefault.list,              NULL,0},
299  {"lock file",         P_STRING, P_LOCAL, &sDefault.lock_file,         NULL,0},
300  {"log format",        P_STRING, P_LOCAL, &sDefault.log_format,        NULL,0},
301  {"max connections",   P_INTEGER,P_LOCAL, &sDefault.max_connections,   NULL,0},
302  {"max verbosity",     P_INTEGER,P_LOCAL, &sDefault.max_verbosity,     NULL,0},
303  {"name",              P_STRING, P_LOCAL, &sDefault.name,              NULL,0},
304  {"path",              P_PATH,   P_LOCAL, &sDefault.path,              NULL,0},
305 #ifdef HAVE_PUTENV
306  {"post-xfer exec",    P_STRING, P_LOCAL, &sDefault.postxfer_exec,     NULL,0},
307  {"pre-xfer exec",     P_STRING, P_LOCAL, &sDefault.prexfer_exec,      NULL,0},
308 #endif
309  {"read only",         P_BOOL,   P_LOCAL, &sDefault.read_only,         NULL,0},
310  {"refuse options",    P_STRING, P_LOCAL, &sDefault.refuse_options,    NULL,0},
311  {"secrets file",      P_STRING, P_LOCAL, &sDefault.secrets_file,      NULL,0},
312  {"strict modes",      P_BOOL,   P_LOCAL, &sDefault.strict_modes,      NULL,0},
313  {"temp dir",          P_PATH,   P_LOCAL, &sDefault.temp_dir,          NULL,0},
314  {"timeout",           P_INTEGER,P_LOCAL, &sDefault.timeout,           NULL,0},
315  {"transfer logging",  P_BOOL,   P_LOCAL, &sDefault.transfer_logging,  NULL,0},
316  {"uid",               P_STRING, P_LOCAL, &sDefault.uid,               NULL,0},
317  {"use chroot",        P_BOOL,   P_LOCAL, &sDefault.use_chroot,        NULL,0},
318  {"write only",        P_BOOL,   P_LOCAL, &sDefault.write_only,        NULL,0},
319  {NULL,                P_BOOL,   P_NONE,  NULL,                        NULL,0}
320 };
321
322
323 /***************************************************************************
324 Initialise the global parameter structure.
325 ***************************************************************************/
326 static void init_globals(void)
327 {
328         memset(&Globals, 0, sizeof Globals);
329 #ifdef LOG_DAEMON
330         Globals.syslog_facility = LOG_DAEMON;
331 #endif
332 }
333
334 /***************************************************************************
335 Initialise the sDefault parameter structure.
336 ***************************************************************************/
337 static void init_locals(void)
338 {
339 }
340
341
342 /*
343    In this section all the functions that are used to access the
344    parameters from the rest of the program are defined
345 */
346
347 #define FN_GLOBAL_STRING(fn_name,ptr) \
348  char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
349 #define FN_GLOBAL_BOOL(fn_name,ptr) \
350  BOOL fn_name(void) {return(*(BOOL *)(ptr));}
351 #define FN_GLOBAL_CHAR(fn_name,ptr) \
352  char fn_name(void) {return(*(char *)(ptr));}
353 #define FN_GLOBAL_INTEGER(fn_name,ptr) \
354  int fn_name(void) {return(*(int *)(ptr));}
355
356 #define FN_LOCAL_STRING(fn_name,val) \
357  char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
358 #define FN_LOCAL_BOOL(fn_name,val) \
359  BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
360 #define FN_LOCAL_CHAR(fn_name,val) \
361  char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
362 #define FN_LOCAL_INTEGER(fn_name,val) \
363  int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
364
365
366 FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
367 FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
368 FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
369 FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
370 FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
371
372 FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
373 FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
374
375 FN_LOCAL_STRING(lp_auth_users, auth_users)
376 FN_LOCAL_STRING(lp_comment, comment)
377 FN_LOCAL_STRING(lp_dont_compress, dont_compress)
378 FN_LOCAL_STRING(lp_exclude, exclude)
379 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
380 FN_LOCAL_STRING(lp_filter, filter)
381 FN_LOCAL_STRING(lp_gid, gid)
382 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
383 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
384 FN_LOCAL_STRING(lp_include, include)
385 FN_LOCAL_STRING(lp_include_from, include_from)
386 FN_LOCAL_STRING(lp_lock_file, lock_file)
387 FN_LOCAL_STRING(lp_log_format, log_format)
388 FN_LOCAL_STRING(lp_name, name)
389 FN_LOCAL_STRING(lp_path, path)
390 FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
391 FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
392 FN_LOCAL_STRING(lp_refuse_options, refuse_options)
393 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
394 FN_LOCAL_STRING(lp_temp_dir, temp_dir)
395 FN_LOCAL_STRING(lp_uid, uid)
396
397 FN_LOCAL_INTEGER(lp_max_connections, max_connections)
398 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
399 FN_LOCAL_INTEGER(lp_timeout, timeout)
400
401 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
402 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
403 FN_LOCAL_BOOL(lp_list, list)
404 FN_LOCAL_BOOL(lp_read_only, read_only)
405 FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
406 FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
407 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
408 FN_LOCAL_BOOL(lp_write_only, write_only)
409
410 /* local prototypes */
411 static int    strwicmp(char *psz1, char *psz2);
412 static int    map_parameter(char *parmname);
413 static BOOL   set_boolean(BOOL *pb, char *parmvalue);
414 static int    getservicebyname(char *name, service *pserviceDest);
415 static void   copy_service(service *pserviceDest, service *pserviceSource);
416 static BOOL   do_parameter(char *parmname, char *parmvalue);
417 static BOOL   do_section(char *sectionname);
418
419
420 /***************************************************************************
421 initialise a service to the defaults
422 ***************************************************************************/
423 static void init_service(service *pservice)
424 {
425         memset((char *)pservice,0,sizeof(service));
426         copy_service(pservice,&sDefault);
427 }
428
429
430 /**
431  * Assign a copy of @p v to @p *s.  Handles NULL strings.  @p *v must
432  * be initialized when this is called, either to NULL or a malloc'd
433  * string.
434  *
435  * @fixme There is a small leak here in that sometimes the existing
436  * value will be dynamically allocated, and the old copy is lost.
437  * However, we can't always deallocate the old value, because in the
438  * case of sDefault, it points to a static string.  It would be nice
439  * to have either all-strdup'd values, or to never need to free
440  * memory.
441  **/
442 static void string_set(char **s, const char *v)
443 {
444         if (!v) {
445                 *s = NULL;
446                 return;
447         }
448         *s = strdup(v);
449         if (!*s)
450                 exit_cleanup(RERR_MALLOC);
451 }
452
453
454 /***************************************************************************
455 add a new service to the services array initialising it with the given
456 service
457 ***************************************************************************/
458 static int add_a_service(service *pservice, char *name)
459 {
460   int i;
461   service tservice;
462   int num_to_alloc = iNumServices+1;
463
464   tservice = *pservice;
465
466   /* it might already exist */
467   if (name)
468     {
469       i = getservicebyname(name,NULL);
470       if (i >= 0)
471         return(i);
472     }
473
474   i = iNumServices;
475
476   ServicePtrs = realloc_array(ServicePtrs, service *, num_to_alloc);
477
478   if (ServicePtrs)
479           pSERVICE(iNumServices) = new(service);
480
481   if (!ServicePtrs || !pSERVICE(iNumServices))
482           return(-1);
483
484   iNumServices++;
485
486   init_service(pSERVICE(i));
487   copy_service(pSERVICE(i),&tservice);
488   if (name)
489     string_set(&iSERVICE(i).name,name);
490
491   return(i);
492 }
493
494 /***************************************************************************
495 Do a case-insensitive, whitespace-ignoring string compare.
496 ***************************************************************************/
497 static int strwicmp(char *psz1, char *psz2)
498 {
499    /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
500    /* appropriate value. */
501    if (psz1 == psz2)
502       return (0);
503    else
504       if (psz1 == NULL)
505          return (-1);
506       else
507           if (psz2 == NULL)
508               return (1);
509
510    /* sync the strings on first non-whitespace */
511    while (1)
512    {
513       while (isspace(* (unsigned char *) psz1))
514          psz1++;
515       while (isspace(* (unsigned char *) psz2))
516          psz2++;
517       if (toupper(* (unsigned char *) psz1) != toupper(* (unsigned char *) psz2)
518           || *psz1 == '\0' || *psz2 == '\0')
519          break;
520       psz1++;
521       psz2++;
522    }
523    return (*psz1 - *psz2);
524 }
525
526 /***************************************************************************
527 Map a parameter's string representation to something we can use.
528 Returns False if the parameter string is not recognised, else TRUE.
529 ***************************************************************************/
530 static int map_parameter(char *parmname)
531 {
532    int iIndex;
533
534    if (*parmname == '-')
535      return(-1);
536
537    for (iIndex = 0; parm_table[iIndex].label; iIndex++)
538       if (strwicmp(parm_table[iIndex].label, parmname) == 0)
539          return(iIndex);
540
541    rprintf(FERROR, "Unknown Parameter encountered: \"%s\"\n", parmname);
542    return(-1);
543 }
544
545
546 /***************************************************************************
547 Set a boolean variable from the text value stored in the passed string.
548 Returns True in success, False if the passed string does not correctly
549 represent a boolean.
550 ***************************************************************************/
551 static BOOL set_boolean(BOOL *pb, char *parmvalue)
552 {
553    BOOL bRetval;
554
555    bRetval = True;
556    if (strwicmp(parmvalue, "yes") == 0 ||
557        strwicmp(parmvalue, "true") == 0 ||
558        strwicmp(parmvalue, "1") == 0)
559       *pb = True;
560    else
561       if (strwicmp(parmvalue, "no") == 0 ||
562           strwicmp(parmvalue, "False") == 0 ||
563           strwicmp(parmvalue, "0") == 0)
564          *pb = False;
565       else
566       {
567          rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
568                parmvalue);
569          bRetval = False;
570       }
571    return (bRetval);
572 }
573
574 /***************************************************************************
575 Find a service by name. Otherwise works like get_service.
576 ***************************************************************************/
577 static int getservicebyname(char *name, service *pserviceDest)
578 {
579    int iService;
580
581    for (iService = iNumServices - 1; iService >= 0; iService--)
582       if (strwicmp(iSERVICE(iService).name, name) == 0)
583       {
584          if (pserviceDest != NULL)
585            copy_service(pserviceDest, pSERVICE(iService));
586          break;
587       }
588
589    return (iService);
590 }
591
592
593
594 /***************************************************************************
595 Copy a service structure to another
596
597 ***************************************************************************/
598 static void copy_service(service *pserviceDest,
599                          service *pserviceSource)
600 {
601   int i;
602
603   for (i=0;parm_table[i].label;i++)
604     if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
605         void *def_ptr = parm_table[i].ptr;
606         void *src_ptr =
607           ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
608         void *dest_ptr =
609           ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
610
611         switch (parm_table[i].type)
612           {
613           case P_BOOL:
614           case P_BOOLREV:
615             *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
616             break;
617
618           case P_INTEGER:
619           case P_ENUM:
620           case P_OCTAL:
621             *(int *)dest_ptr = *(int *)src_ptr;
622             break;
623
624           case P_CHAR:
625             *(char *)dest_ptr = *(char *)src_ptr;
626             break;
627
628           case P_PATH:
629           case P_STRING:
630             string_set(dest_ptr,*(char **)src_ptr);
631             break;
632
633           default:
634             break;
635           }
636       }
637 }
638
639
640 /***************************************************************************
641 Process a parameter for a particular service number. If snum < 0
642 then assume we are in the globals
643 ***************************************************************************/
644 static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
645 {
646    int parmnum, i;
647    void *parm_ptr=NULL; /* where we are going to store the result */
648    void *def_ptr=NULL;
649    char *cp;
650
651    parmnum = map_parameter(parmname);
652
653    if (parmnum < 0)
654      {
655        rprintf(FERROR, "IGNORING unknown parameter \"%s\"\n", parmname);
656        return(True);
657      }
658
659    def_ptr = parm_table[parmnum].ptr;
660
661    /* we might point at a service, the default service or a global */
662    if (snum < 0) {
663      parm_ptr = def_ptr;
664    } else {
665        if (parm_table[parmnum].class == P_GLOBAL) {
666            rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
667            return(True);
668          }
669        parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
670    }
671
672    /* now switch on the type of variable it is */
673    switch (parm_table[parmnum].type)
674      {
675      case P_BOOL:
676        set_boolean(parm_ptr,parmvalue);
677        break;
678
679      case P_BOOLREV:
680        set_boolean(parm_ptr,parmvalue);
681        *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
682        break;
683
684      case P_INTEGER:
685        *(int *)parm_ptr = atoi(parmvalue);
686        break;
687
688      case P_CHAR:
689        *(char *)parm_ptr = *parmvalue;
690        break;
691
692      case P_OCTAL:
693        sscanf(parmvalue,"%o",(int *)parm_ptr);
694        break;
695
696      case P_PATH:
697        string_set(parm_ptr,parmvalue);
698        if ((cp = *(char**)parm_ptr) != NULL) {
699            int len = strlen(cp);
700            while (len > 1 && cp[len-1] == '/') len--;
701            cp[len] = '\0';
702        }
703        break;
704
705      case P_STRING:
706        string_set(parm_ptr,parmvalue);
707        break;
708
709      case P_GSTRING:
710        strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));
711        break;
712
713      case P_ENUM:
714              for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
715                      if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
716                              *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
717                              break;
718                      }
719              }
720              if (!parm_table[parmnum].enum_list[i].name) {
721                      if (atoi(parmvalue) > 0)
722                              *(int *)parm_ptr = atoi(parmvalue);
723              }
724              break;
725      case P_SEP:
726              break;
727      }
728
729    return(True);
730 }
731
732 /***************************************************************************
733 Process a parameter.
734 ***************************************************************************/
735 static BOOL do_parameter(char *parmname, char *parmvalue)
736 {
737    return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
738 }
739
740 /***************************************************************************
741 Process a new section (service). At this stage all sections are services.
742 Later we'll have special sections that permit server parameters to be set.
743 Returns True on success, False on failure.
744 ***************************************************************************/
745 static BOOL do_section(char *sectionname)
746 {
747    BOOL bRetval;
748    BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
749    bRetval = False;
750
751    /* if we were in a global section then do the local inits */
752    if (bInGlobalSection && !isglobal)
753      init_locals();
754
755    /* if we've just struck a global section, note the fact. */
756    bInGlobalSection = isglobal;
757
758    /* check for multiple global sections */
759    if (bInGlobalSection)
760    {
761      return(True);
762    }
763
764    /* if we have a current service, tidy it up before moving on */
765    bRetval = True;
766
767    if (iServiceIndex >= 0)
768      bRetval = True;
769
770    /* if all is still well, move to the next record in the services array */
771    if (bRetval)
772      {
773        /* We put this here to avoid an odd message order if messages are */
774        /* issued by the post-processing of a previous section. */
775
776        if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
777          {
778            rprintf(FERROR,"Failed to add a new service\n");
779            return(False);
780          }
781      }
782
783    return (bRetval);
784 }
785
786
787 /***************************************************************************
788 Load the services array from the services file. Return True on success,
789 False on failure.
790 ***************************************************************************/
791 BOOL lp_load(char *pszFname, int globals_only)
792 {
793         extern int am_server;
794         extern int am_daemon;
795         extern int am_root;
796         pstring n2;
797         BOOL bRetval;
798
799         bRetval = False;
800
801         bInGlobalSection = True;
802
803         init_globals();
804
805         if (pszFname)
806             pstrcpy(n2,pszFname);
807         else if (am_server && am_daemon && !am_root)
808             pstrcpy(n2,RSYNCD_USERCONF);
809         else
810             pstrcpy(n2,RSYNCD_SYSCONF);
811
812         /* We get sections first, so have to start 'behind' to make up */
813         iServiceIndex = -1;
814         bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
815
816         return (bRetval);
817 }
818
819
820 /***************************************************************************
821 return the max number of services
822 ***************************************************************************/
823 int lp_numservices(void)
824 {
825   return(iNumServices);
826 }
827
828 /***************************************************************************
829 Return the number of the service with the given name, or -1 if it doesn't
830 exist. Note that this is a DIFFERENT ANIMAL from the internal function
831 getservicebyname()! This works ONLY if all services have been loaded, and
832 does not copy the found service.
833 ***************************************************************************/
834 int lp_number(char *name)
835 {
836    int iService;
837
838    for (iService = iNumServices - 1; iService >= 0; iService--)
839       if (strcmp(lp_name(iService), name) == 0)
840          break;
841
842    return (iService);
843 }
844