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