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