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