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