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