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