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