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