hanle null strings in -vvv output
[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
4/*
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18*/
19
20/*
21 * Load parameters.
22 *
23 * This module provides suitable callback functions for the params
24 * module. It builds the internal table of service details which is
25 * then used by the rest of the server.
26 *
27 * To add a parameter:
28 *
29 * 1) add it to the global or service structure definition
30 * 2) add it to the parm_table
31 * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
32 * 4) If it's a global then initialise it in init_globals. If a local
33 * (ie. service) parameter then initialise it in the sDefault structure
34 *
35 *
36 * Notes:
37 * The configuration file is processed sequentially for speed. It is NOT
38 * accessed randomly as happens in 'real' Windows. For this reason, there
39 * is a fair bit of sequence-dependent code here - ie., code which assumes
40 * that certain things happen before others. In particular, the code which
41 * happens at the boundary between sections is delicately poised, so be
42 * careful!
43 *
44 */
45
46#include "rsync.h"
47#define BOOL int
48#define False 0
49#define True 1
0b76cd63
AT
50#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
51#define strequal(a,b) (strcasecmp(a,b)==0)
52#define BOOLSTR(b) ((b) ? "Yes" : "No")
53typedef char pstring[1024];
e45e0093 54#define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring)-1)
0b76cd63
AT
55
56/* the following are used by loadparm for option lists */
57typedef enum
58{
31593dd6
AT
59 P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
60 P_STRING,P_GSTRING,P_ENUM,P_SEP
0b76cd63
AT
61} parm_type;
62
63typedef enum
64{
31593dd6 65 P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
0b76cd63
AT
66} parm_class;
67
68struct enum_list {
69 int value;
70 char *name;
71};
72
73struct parm_struct
74{
75 char *label;
76 parm_type type;
77 parm_class class;
78 void *ptr;
79 struct enum_list *enum_list;
80 unsigned flags;
81};
82
83static BOOL bLoaded = False;
84
85#ifndef GLOBAL_NAME
86#define GLOBAL_NAME "global"
87#endif
88
89/* some helpful bits */
90#define pSERVICE(i) ServicePtrs[i]
91#define iSERVICE(i) (*pSERVICE(i))
92#define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
93
94/*
95 * This structure describes global (ie., server-wide) parameters.
96 */
97typedef struct
98{
99 char *motd_file;
0c515f17 100 char *lock_file;
4f6325c3 101 char *log_file;
8638dd48 102 char *pid_file;
851dbdb7 103 int syslog_facility;
0c515f17 104 int max_connections;
a6801c39 105 char *socket_options;
0b76cd63
AT
106} global;
107
108static global Globals;
109
110
111
112/*
113 * This structure describes a single service.
114 */
115typedef struct
116{
117 char *name;
118 char *path;
119 char *comment;
120 BOOL read_only;
121 BOOL list;
8638dd48 122 BOOL use_chroot;
11a5a3c7 123 BOOL transfer_logging;
8ef4ffd6
AT
124 char *uid;
125 char *gid;
56c473b7
AT
126 char *hosts_allow;
127 char *hosts_deny;
31593dd6
AT
128 char *auth_users;
129 char *secrets_file;
8f3a2d54
AT
130 char *exclude;
131 char *exclude_from;
0b76cd63
AT
132} service;
133
134
135/* This is a default service used to prime a services structure */
136static service sDefault =
137{
138 NULL, /* name */
139 NULL, /* path */
140 NULL, /* comment */
141 True, /* read only */
142 True, /* list */
8638dd48 143 True, /* use chroot */
11a5a3c7 144 False, /* transfer logging */
8ef4ffd6
AT
145 "nobody",/* uid */
146 "nobody",/* gid */
56c473b7
AT
147 NULL, /* hosts allow */
148 NULL, /* hosts deny */
31593dd6
AT
149 NULL, /* auth users */
150 NULL, /* secrets file */
8f3a2d54
AT
151 NULL, /* exclude */
152 NULL, /* exclude from */
0b76cd63
AT
153};
154
155
156
157/* local variables */
158static service **ServicePtrs = NULL;
159static int iNumServices = 0;
160static int iServiceIndex = 0;
161static BOOL bInGlobalSection = True;
162
163#define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
164
09e13ae2
AT
165static struct enum_list enum_facilities[] = {
166#ifdef LOG_AUTH
167 { LOG_AUTH, "auth" },
168#endif
169#ifdef LOG_AUTHPRIV
170 { LOG_AUTHPRIV, "authpriv" },
171#endif
172#ifdef LOG_CRON
173 { LOG_CRON, "cron" },
174#endif
175#ifdef LOG_DAEMON
176 { LOG_DAEMON, "daemon" },
177#endif
178#ifdef LOG_FTP
179 { LOG_FTP, "ftp" },
180#endif
181#ifdef LOG_KERN
182 { LOG_KERN, "kern" },
183#endif
184#ifdef LOG_LPR
185 { LOG_LPR, "lpr" },
186#endif
187#ifdef LOG_MAIL
188 { LOG_MAIL, "mail" },
189#endif
190#ifdef LOG_NEWS
191 { LOG_NEWS, "news" },
192#endif
193#ifdef LOG_AUTH
194 { LOG_AUTH, "security" },
195#endif
196#ifdef LOG_SYSLOG
197 { LOG_SYSLOG, "syslog" },
198#endif
199#ifdef LOG_USER
200 { LOG_USER, "user" },
201#endif
202#ifdef LOG_UUCP
203 { LOG_UUCP, "uucp" },
204#endif
205#ifdef LOG_LOCAL0
206 { LOG_LOCAL0, "local0" },
207#endif
208#ifdef LOG_LOCAL1
209 { LOG_LOCAL1, "local1" },
210#endif
211#ifdef LOG_LOCAL2
212 { LOG_LOCAL2, "local2" },
213#endif
214#ifdef LOG_LOCAL3
215 { LOG_LOCAL3, "local3" },
216#endif
217#ifdef LOG_LOCAL4
218 { LOG_LOCAL4, "local4" },
219#endif
220#ifdef LOG_LOCAL5
221 { LOG_LOCAL5, "local5" },
222#endif
223#ifdef LOG_LOCAL6
224 { LOG_LOCAL6, "local6" },
225#endif
226#ifdef LOG_LOCAL7
227 { LOG_LOCAL7, "local7" },
228#endif
229 { -1, NULL }};
230
0b76cd63
AT
231
232/* note that we do not initialise the defaults union - it is not allowed in ANSI C */
233static struct parm_struct parm_table[] =
234{
0c515f17 235 {"max connections", P_INTEGER, P_GLOBAL, &Globals.max_connections,NULL, 0},
0b76cd63 236 {"motd file", P_STRING, P_GLOBAL, &Globals.motd_file, NULL, 0},
0c515f17 237 {"lock file", P_STRING, P_GLOBAL, &Globals.lock_file, NULL, 0},
09e13ae2 238 {"syslog facility", P_ENUM, P_GLOBAL, &Globals.syslog_facility, enum_facilities,0},
a6801c39 239 {"socket options", P_STRING, P_GLOBAL, &Globals.socket_options,NULL, 0},
4f6325c3 240 {"log file", P_STRING, P_GLOBAL, &Globals.log_file, NULL, 0},
8638dd48 241 {"pid file", P_STRING, P_GLOBAL, &Globals.pid_file, NULL, 0},
41059f75 242
0b76cd63
AT
243 {"name", P_STRING, P_LOCAL, &sDefault.name, NULL, 0},
244 {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL, 0},
245 {"path", P_STRING, P_LOCAL, &sDefault.path, NULL, 0},
246 {"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL, 0},
247 {"list", P_BOOL, P_LOCAL, &sDefault.list, NULL, 0},
8638dd48 248 {"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL, 0},
8ef4ffd6
AT
249 {"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL, 0},
250 {"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL, 0},
56c473b7
AT
251 {"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL, 0},
252 {"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL, 0},
31593dd6
AT
253 {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL, 0},
254 {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file,NULL, 0},
8f3a2d54
AT
255 {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL, 0},
256 {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from,NULL, 0},
11a5a3c7 257 {"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging,NULL,0},
0b76cd63
AT
258 {NULL, P_BOOL, P_NONE, NULL, NULL, 0}
259};
260
261
262/***************************************************************************
263Initialise the global parameter structure.
264***************************************************************************/
265static void init_globals(void)
266{
f9e940ef 267 memset(&Globals, 0, sizeof(Globals));
851dbdb7
AT
268#ifdef LOG_DAEMON
269 Globals.syslog_facility = LOG_DAEMON;
270#endif
0c515f17 271 Globals.lock_file = "/var/run/rsyncd.lock";
0b76cd63
AT
272}
273
274/***************************************************************************
275Initialise the sDefault parameter structure.
276***************************************************************************/
277static void init_locals(void)
278{
279}
280
281
282/*
283 In this section all the functions that are used to access the
284 parameters from the rest of the program are defined
285*/
286
287#define FN_GLOBAL_STRING(fn_name,ptr) \
288 char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
289#define FN_GLOBAL_BOOL(fn_name,ptr) \
290 BOOL fn_name(void) {return(*(BOOL *)(ptr));}
291#define FN_GLOBAL_CHAR(fn_name,ptr) \
292 char fn_name(void) {return(*(char *)(ptr));}
293#define FN_GLOBAL_INTEGER(fn_name,ptr) \
294 int fn_name(void) {return(*(int *)(ptr));}
295
296#define FN_LOCAL_STRING(fn_name,val) \
297 char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
298#define FN_LOCAL_BOOL(fn_name,val) \
299 BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
300#define FN_LOCAL_CHAR(fn_name,val) \
301 char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
302#define FN_LOCAL_INTEGER(fn_name,val) \
303 int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
304
305
306FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
0c515f17 307FN_GLOBAL_STRING(lp_lock_file, &Globals.lock_file)
4f6325c3 308FN_GLOBAL_STRING(lp_log_file, &Globals.log_file)
8638dd48 309FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
a6801c39 310FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
0c515f17 311FN_GLOBAL_INTEGER(lp_max_connections, &Globals.max_connections)
851dbdb7 312FN_GLOBAL_INTEGER(lp_syslog_facility, &Globals.syslog_facility)
a6801c39 313
0b76cd63
AT
314FN_LOCAL_STRING(lp_name, name)
315FN_LOCAL_STRING(lp_comment, comment)
316FN_LOCAL_STRING(lp_path, path)
317FN_LOCAL_BOOL(lp_read_only, read_only)
318FN_LOCAL_BOOL(lp_list, list)
8638dd48 319FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
11a5a3c7 320FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
8ef4ffd6
AT
321FN_LOCAL_STRING(lp_uid, uid)
322FN_LOCAL_STRING(lp_gid, gid)
56c473b7
AT
323FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
324FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
31593dd6
AT
325FN_LOCAL_STRING(lp_auth_users, auth_users)
326FN_LOCAL_STRING(lp_secrets_file, secrets_file)
8f3a2d54
AT
327FN_LOCAL_STRING(lp_exclude, exclude)
328FN_LOCAL_STRING(lp_exclude_from, exclude_from)
0b76cd63
AT
329
330/* local prototypes */
331static int strwicmp( char *psz1, char *psz2 );
332static int map_parameter( char *parmname);
333static BOOL set_boolean( BOOL *pb, char *parmvalue );
334static int getservicebyname(char *name, service *pserviceDest);
335static void copy_service( service *pserviceDest,
336 service *pserviceSource);
337static BOOL do_parameter(char *parmname, char *parmvalue);
338static BOOL do_section(char *sectionname);
339
340
341/***************************************************************************
342initialise a service to the defaults
343***************************************************************************/
344static void init_service(service *pservice)
345{
f5780433 346 memset((char *)pservice,0,sizeof(service));
45ccc5c0 347 copy_service(pservice,&sDefault);
0b76cd63
AT
348}
349
350static void string_set(char **s, char *v)
351{
0b76cd63
AT
352 if (!v) {
353 *s = NULL;
354 return;
355 }
356 *s = strdup(v);
357 if (!*s) exit_cleanup(1);
358}
359
360
361/***************************************************************************
362add a new service to the services array initialising it with the given
363service
364***************************************************************************/
365static int add_a_service(service *pservice, char *name)
366{
367 int i;
368 service tservice;
369 int num_to_alloc = iNumServices+1;
370
371 tservice = *pservice;
372
373 /* it might already exist */
374 if (name)
375 {
376 i = getservicebyname(name,NULL);
377 if (i >= 0)
378 return(i);
379 }
380
381 i = iNumServices;
382
fe8c0a98 383 ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
6cdc6b13 384
0b76cd63
AT
385 if (ServicePtrs)
386 pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
387
388 if (!ServicePtrs || !pSERVICE(iNumServices))
389 return(-1);
390
391 iNumServices++;
392
393 init_service(pSERVICE(i));
394 copy_service(pSERVICE(i),&tservice);
395 if (name)
396 string_set(&iSERVICE(i).name,name);
397
398 return(i);
399}
400
401/***************************************************************************
402Do a case-insensitive, whitespace-ignoring string compare.
403***************************************************************************/
404static int strwicmp(char *psz1, char *psz2)
405{
406 /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
407 /* appropriate value. */
408 if (psz1 == psz2)
409 return (0);
410 else
411 if (psz1 == NULL)
412 return (-1);
413 else
414 if (psz2 == NULL)
415 return (1);
416
417 /* sync the strings on first non-whitespace */
418 while (1)
419 {
420 while (isspace(*psz1))
421 psz1++;
422 while (isspace(*psz2))
423 psz2++;
424 if (toupper(*psz1) != toupper(*psz2) || *psz1 == '\0' || *psz2 == '\0')
425 break;
426 psz1++;
427 psz2++;
428 }
429 return (*psz1 - *psz2);
430}
431
432/***************************************************************************
433Map a parameter's string representation to something we can use.
434Returns False if the parameter string is not recognised, else TRUE.
435***************************************************************************/
436static int map_parameter(char *parmname)
437{
438 int iIndex;
439
440 if (*parmname == '-')
441 return(-1);
442
443 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
444 if (strwicmp(parm_table[iIndex].label, parmname) == 0)
445 return(iIndex);
446
447 rprintf(FERROR, "Unknown parameter encountered: \"%s\"\n", parmname);
448 return(-1);
449}
450
451
452/***************************************************************************
453Set a boolean variable from the text value stored in the passed string.
454Returns True in success, False if the passed string does not correctly
455represent a boolean.
456***************************************************************************/
457static BOOL set_boolean(BOOL *pb, char *parmvalue)
458{
459 BOOL bRetval;
460
461 bRetval = True;
462 if (strwicmp(parmvalue, "yes") == 0 ||
463 strwicmp(parmvalue, "true") == 0 ||
464 strwicmp(parmvalue, "1") == 0)
465 *pb = True;
466 else
467 if (strwicmp(parmvalue, "no") == 0 ||
468 strwicmp(parmvalue, "False") == 0 ||
469 strwicmp(parmvalue, "0") == 0)
470 *pb = False;
471 else
472 {
473 rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
474 parmvalue);
475 bRetval = False;
476 }
477 return (bRetval);
478}
479
480/***************************************************************************
481Find a service by name. Otherwise works like get_service.
482***************************************************************************/
483static int getservicebyname(char *name, service *pserviceDest)
484{
485 int iService;
486
487 for (iService = iNumServices - 1; iService >= 0; iService--)
488 if (strwicmp(iSERVICE(iService).name, name) == 0)
489 {
490 if (pserviceDest != NULL)
491 copy_service(pserviceDest, pSERVICE(iService));
492 break;
493 }
494
495 return (iService);
496}
497
498
499
500/***************************************************************************
501Copy a service structure to another
502
503***************************************************************************/
504static void copy_service(service *pserviceDest,
505 service *pserviceSource)
506{
507 int i;
508
509 for (i=0;parm_table[i].label;i++)
510 if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
511 void *def_ptr = parm_table[i].ptr;
512 void *src_ptr =
513 ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
514 void *dest_ptr =
515 ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
516
517 switch (parm_table[i].type)
518 {
519 case P_BOOL:
520 case P_BOOLREV:
521 *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
522 break;
523
524 case P_INTEGER:
525 case P_ENUM:
526 case P_OCTAL:
527 *(int *)dest_ptr = *(int *)src_ptr;
528 break;
529
530 case P_CHAR:
531 *(char *)dest_ptr = *(char *)src_ptr;
532 break;
533
534 case P_STRING:
535 string_set(dest_ptr,*(char **)src_ptr);
536 break;
537
538 default:
539 break;
540 }
541 }
542}
543
544
545/***************************************************************************
546Process a parameter for a particular service number. If snum < 0
547then assume we are in the globals
548***************************************************************************/
549static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
550{
551 int parmnum, i;
552 void *parm_ptr=NULL; /* where we are going to store the result */
553 void *def_ptr=NULL;
554
555 parmnum = map_parameter(parmname);
556
557 if (parmnum < 0)
558 {
559 rprintf(FERROR, "Ignoring unknown parameter \"%s\"\n", parmname);
560 return(True);
561 }
562
563 def_ptr = parm_table[parmnum].ptr;
564
565 /* we might point at a service, the default service or a global */
566 if (snum < 0) {
567 parm_ptr = def_ptr;
568 } else {
569 if (parm_table[parmnum].class == P_GLOBAL) {
570 rprintf(FERROR, "Global parameter %s found in service section!\n",parmname);
571 return(True);
572 }
573 parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
574 }
575
576 /* now switch on the type of variable it is */
577 switch (parm_table[parmnum].type)
578 {
579 case P_BOOL:
580 set_boolean(parm_ptr,parmvalue);
581 break;
582
583 case P_BOOLREV:
584 set_boolean(parm_ptr,parmvalue);
585 *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
586 break;
587
588 case P_INTEGER:
589 *(int *)parm_ptr = atoi(parmvalue);
590 break;
591
592 case P_CHAR:
593 *(char *)parm_ptr = *parmvalue;
594 break;
595
596 case P_OCTAL:
597 sscanf(parmvalue,"%o",(int *)parm_ptr);
598 break;
599
600 case P_STRING:
601 string_set(parm_ptr,parmvalue);
602 break;
603
604 case P_GSTRING:
1a016bfd 605 strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring)-1);
0b76cd63
AT
606 break;
607
608 case P_ENUM:
609 for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
610 if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
611 *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
612 break;
613 }
614 }
fabf5ea7 615 if (!parm_table[parmnum].enum_list[i].name) {
41059f75
AT
616 if (atoi(parmvalue) > 0)
617 *(int *)parm_ptr = atoi(parmvalue);
fabf5ea7 618 }
0b76cd63
AT
619 break;
620 case P_SEP:
621 break;
622 }
623
624 return(True);
625}
626
627/***************************************************************************
628Process a parameter.
629***************************************************************************/
630static BOOL do_parameter(char *parmname, char *parmvalue)
631{
632 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
633}
634
635/***************************************************************************
636Process a new section (service). At this stage all sections are services.
637Later we'll have special sections that permit server parameters to be set.
638Returns True on success, False on failure.
639***************************************************************************/
640static BOOL do_section(char *sectionname)
641{
642 BOOL bRetval;
643 BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
644 bRetval = False;
645
646 /* if we were in a global section then do the local inits */
647 if (bInGlobalSection && !isglobal)
648 init_locals();
649
650 /* if we've just struck a global section, note the fact. */
651 bInGlobalSection = isglobal;
652
653 /* check for multiple global sections */
654 if (bInGlobalSection)
655 {
656 return(True);
657 }
658
659 /* if we have a current service, tidy it up before moving on */
660 bRetval = True;
661
662 if (iServiceIndex >= 0)
663 bRetval = True;
664
665 /* if all is still well, move to the next record in the services array */
666 if (bRetval)
667 {
668 /* We put this here to avoid an odd message order if messages are */
669 /* issued by the post-processing of a previous section. */
670
671 if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
672 {
673 rprintf(FERROR,"Failed to add a new service\n");
674 return(False);
675 }
676 }
677
678 return (bRetval);
679}
680
681
682/***************************************************************************
683Load the services array from the services file. Return True on success,
684False on failure.
685***************************************************************************/
f9e940ef 686BOOL lp_load(char *pszFname, int globals_only)
0b76cd63 687{
f9e940ef
AT
688 pstring n2;
689 BOOL bRetval;
0b76cd63 690
f9e940ef 691 bRetval = False;
0b76cd63 692
f9e940ef 693 bInGlobalSection = True;
0b76cd63 694
f9e940ef 695 init_globals();
0b76cd63 696
f9e940ef 697 pstrcpy(n2,pszFname);
0b76cd63 698
f9e940ef
AT
699 /* We get sections first, so have to start 'behind' to make up */
700 iServiceIndex = -1;
701 bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
0b76cd63 702
f9e940ef 703 bLoaded = True;
0b76cd63 704
f9e940ef 705 return (bRetval);
0b76cd63
AT
706}
707
708
709/***************************************************************************
710return the max number of services
711***************************************************************************/
712int lp_numservices(void)
713{
714 return(iNumServices);
715}
716
717/***************************************************************************
718Return the number of the service with the given name, or -1 if it doesn't
719exist. Note that this is a DIFFERENT ANIMAL from the internal function
720getservicebyname()! This works ONLY if all services have been loaded, and
721does not copy the found service.
722***************************************************************************/
723int lp_number(char *name)
724{
725 int iService;
726
727 for (iService = iNumServices - 1; iService >= 0; iService--)
728 if (strequal(lp_name(iService), name))
729 break;
730
731 return (iService);
732}
733