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