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