Changed the "max verbosity" setting from global to per-module.
[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 rsync_port;
108 } global;
109
110 static global Globals;
111
112
113 /*
114  * This structure describes a single service.
115  */
116 typedef struct
117 {
118         char *name;
119         char *path;
120         char *comment;
121         char *lock_file;
122         BOOL read_only;
123         BOOL write_only;
124         BOOL list;
125         BOOL use_chroot;
126         BOOL transfer_logging;
127         BOOL ignore_errors;
128         char *uid;
129         char *gid;
130         char *hosts_allow;
131         char *hosts_deny;
132         char *auth_users;
133         char *secrets_file;
134         BOOL strict_modes;
135         char *filter;
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         int max_verbosity;
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         1,        /* max verbosity */
181         False     /* ignore nonreadable */
182 };
183
184
185
186 /* local variables */
187 static service **ServicePtrs = NULL;
188 static int iNumServices = 0;
189 static int iServiceIndex = 0;
190 static BOOL bInGlobalSection = True;
191
192 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
193
194 static struct enum_list enum_facilities[] = {
195 #ifdef LOG_AUTH
196         { LOG_AUTH, "auth" },
197 #endif
198 #ifdef LOG_AUTHPRIV
199         { LOG_AUTHPRIV, "authpriv" },
200 #endif
201 #ifdef LOG_CRON
202         { LOG_CRON, "cron" },
203 #endif
204 #ifdef LOG_DAEMON
205         { LOG_DAEMON, "daemon" },
206 #endif
207 #ifdef LOG_FTP
208         { LOG_FTP, "ftp" },
209 #endif
210 #ifdef LOG_KERN
211         { LOG_KERN, "kern" },
212 #endif
213 #ifdef LOG_LPR
214         { LOG_LPR, "lpr" },
215 #endif
216 #ifdef LOG_MAIL
217         { LOG_MAIL, "mail" },
218 #endif
219 #ifdef LOG_NEWS
220         { LOG_NEWS, "news" },
221 #endif
222 #ifdef LOG_AUTH
223         { LOG_AUTH, "security" },
224 #endif
225 #ifdef LOG_SYSLOG
226         { LOG_SYSLOG, "syslog" },
227 #endif
228 #ifdef LOG_USER
229         { LOG_USER, "user" },
230 #endif
231 #ifdef LOG_UUCP
232         { LOG_UUCP, "uucp" },
233 #endif
234 #ifdef LOG_LOCAL0
235         { LOG_LOCAL0, "local0" },
236 #endif
237 #ifdef LOG_LOCAL1
238         { LOG_LOCAL1, "local1" },
239 #endif
240 #ifdef LOG_LOCAL2
241         { LOG_LOCAL2, "local2" },
242 #endif
243 #ifdef LOG_LOCAL3
244         { LOG_LOCAL3, "local3" },
245 #endif
246 #ifdef LOG_LOCAL4
247         { LOG_LOCAL4, "local4" },
248 #endif
249 #ifdef LOG_LOCAL5
250         { LOG_LOCAL5, "local5" },
251 #endif
252 #ifdef LOG_LOCAL6
253         { LOG_LOCAL6, "local6" },
254 #endif
255 #ifdef LOG_LOCAL7
256         { LOG_LOCAL7, "local7" },
257 #endif
258         { -1, NULL }};
259
260
261 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
262 static struct parm_struct parm_table[] =
263 {
264   {"motd file",        P_STRING,  P_GLOBAL, &Globals.motd_file,    NULL,   0},
265   {"syslog facility",  P_ENUM,    P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
266   {"socket options",   P_STRING,  P_GLOBAL, &Globals.socket_options,NULL,  0},
267   {"log file",         P_STRING,  P_GLOBAL, &Globals.log_file,      NULL,  0},
268   {"pid file",         P_STRING,  P_GLOBAL, &Globals.pid_file,      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   {"max verbosity",    P_INTEGER, P_LOCAL,  &sDefault.max_verbosity,NULL,  0},
275   {"name",             P_STRING,  P_LOCAL,  &sDefault.name,        NULL,   0},
276   {"comment",          P_STRING,  P_LOCAL,  &sDefault.comment,     NULL,   0},
277   {"lock file",        P_STRING,  P_LOCAL,  &sDefault.lock_file,   NULL,   0},
278   {"path",             P_PATH,    P_LOCAL,  &sDefault.path,        NULL,   0},
279   {"read only",        P_BOOL,    P_LOCAL,  &sDefault.read_only,   NULL,   0},
280   {"write only",       P_BOOL,    P_LOCAL,  &sDefault.write_only,  NULL,   0},
281   {"list",             P_BOOL,    P_LOCAL,  &sDefault.list,        NULL,   0},
282   {"use chroot",       P_BOOL,    P_LOCAL,  &sDefault.use_chroot,  NULL,   0},
283   {"ignore nonreadable",P_BOOL,   P_LOCAL,  &sDefault.ignore_nonreadable,  NULL,   0},
284   {"uid",              P_STRING,  P_LOCAL,  &sDefault.uid,         NULL,   0},
285   {"gid",              P_STRING,  P_LOCAL,  &sDefault.gid,         NULL,   0},
286   {"hosts allow",      P_STRING,  P_LOCAL,  &sDefault.hosts_allow, NULL,   0},
287   {"hosts deny",       P_STRING,  P_LOCAL,  &sDefault.hosts_deny,  NULL,   0},
288   {"auth users",       P_STRING,  P_LOCAL,  &sDefault.auth_users,  NULL,   0},
289   {"secrets file",     P_STRING,  P_LOCAL,  &sDefault.secrets_file,NULL,   0},
290   {"strict modes",     P_BOOL,    P_LOCAL,  &sDefault.strict_modes,NULL,   0},
291   {"filter",           P_STRING,  P_LOCAL,  &sDefault.filter,      NULL,   0},
292   {"exclude",          P_STRING,  P_LOCAL,  &sDefault.exclude,     NULL,   0},
293   {"exclude from",     P_STRING,  P_LOCAL,  &sDefault.exclude_from,NULL,   0},
294   {"include",          P_STRING,  P_LOCAL,  &sDefault.include,     NULL,   0},
295   {"include from",     P_STRING,  P_LOCAL,  &sDefault.include_from,NULL,   0},
296   {"transfer logging", P_BOOL,    P_LOCAL,  &sDefault.transfer_logging,NULL,0},
297   {"ignore errors",    P_BOOL,    P_LOCAL,  &sDefault.ignore_errors,NULL,0},
298   {"log format",       P_STRING,  P_LOCAL,  &sDefault.log_format,  NULL,   0},
299   {"refuse options",   P_STRING,  P_LOCAL,  &sDefault.refuse_options,NULL, 0},
300   {"dont compress",    P_STRING,  P_LOCAL,  &sDefault.dont_compress,NULL,  0},
301   {NULL,               P_BOOL,    P_NONE,   NULL,                  NULL,   0}
302 };
303
304
305 /***************************************************************************
306 Initialise the global parameter structure.
307 ***************************************************************************/
308 static void init_globals(void)
309 {
310         memset(&Globals, 0, sizeof Globals);
311 #ifdef LOG_DAEMON
312         Globals.syslog_facility = LOG_DAEMON;
313 #endif
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_rsync_port, &Globals.rsync_port)
354 FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
355
356 FN_LOCAL_STRING(lp_name, name)
357 FN_LOCAL_STRING(lp_comment, comment)
358 FN_LOCAL_STRING(lp_path, path)
359 FN_LOCAL_STRING(lp_lock_file, lock_file)
360 FN_LOCAL_BOOL(lp_read_only, read_only)
361 FN_LOCAL_BOOL(lp_write_only, write_only)
362 FN_LOCAL_BOOL(lp_list, list)
363 FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
364 FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
365 FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
366 FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
367 FN_LOCAL_STRING(lp_uid, uid)
368 FN_LOCAL_STRING(lp_gid, gid)
369 FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
370 FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
371 FN_LOCAL_STRING(lp_auth_users, auth_users)
372 FN_LOCAL_STRING(lp_secrets_file, secrets_file)
373 FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
374 FN_LOCAL_STRING(lp_filter, filter)
375 FN_LOCAL_STRING(lp_exclude, exclude)
376 FN_LOCAL_STRING(lp_exclude_from, exclude_from)
377 FN_LOCAL_STRING(lp_include, include)
378 FN_LOCAL_STRING(lp_include_from, include_from)
379 FN_LOCAL_STRING(lp_log_format, log_format)
380 FN_LOCAL_STRING(lp_refuse_options, refuse_options)
381 FN_LOCAL_STRING(lp_dont_compress, dont_compress)
382 FN_LOCAL_INTEGER(lp_timeout, timeout)
383 FN_LOCAL_INTEGER(lp_max_connections, max_connections)
384 FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
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