preparing for release of 2.4.5
[rsync.git] / loadparm.c
blob0083d1e94cd9376a43f70fa44b130cfb45eb46d7
1 /* This is based on loadparm.c from Samba, written by Andrew Tridgell
2 and Karl Auer */
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.
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.
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.
21 * Load parameters.
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.
27 * To add a parameter:
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
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!
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))
53 /* the following are used by loadparm for option lists */
54 typedef enum
56 P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
57 P_STRING,P_GSTRING,P_ENUM,P_SEP
58 } parm_type;
60 typedef enum
62 P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
63 } parm_class;
65 struct enum_list {
66 int value;
67 char *name;
70 struct parm_struct
72 char *label;
73 parm_type type;
74 parm_class class;
75 void *ptr;
76 struct enum_list *enum_list;
77 unsigned flags;
80 static BOOL bLoaded = False;
82 #ifndef GLOBAL_NAME
83 #define GLOBAL_NAME "global"
84 #endif
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))
91 /*
92 * This structure describes global (ie., server-wide) parameters.
94 typedef struct
96 char *motd_file;
97 char *log_file;
98 char *pid_file;
99 int syslog_facility;
100 char *socket_options;
101 } global;
103 static global Globals;
108 * This structure describes a single service.
110 typedef struct
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;
141 /* This is a default service used to prime a services structure */
142 static service sDefault =
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 */
174 /* local variables */
175 static service **ServicePtrs = NULL;
176 static int iNumServices = 0;
177 static int iServiceIndex = 0;
178 static BOOL bInGlobalSection = True;
180 #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
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 }};
249 /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
250 static struct parm_struct parm_table[] =
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},
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}
288 /***************************************************************************
289 Initialise the global parameter structure.
290 ***************************************************************************/
291 static void init_globals(void)
293 memset(&Globals, 0, sizeof(Globals));
294 #ifdef LOG_DAEMON
295 Globals.syslog_facility = LOG_DAEMON;
296 #endif
299 /***************************************************************************
300 Initialise the sDefault parameter structure.
301 ***************************************************************************/
302 static void init_locals(void)
308 In this section all the functions that are used to access the
309 parameters from the rest of the program are defined
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));}
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);}
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)
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)
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);
375 /***************************************************************************
376 initialise a service to the defaults
377 ***************************************************************************/
378 static void init_service(service *pservice)
380 memset((char *)pservice,0,sizeof(service));
381 copy_service(pservice,&sDefault);
384 static void string_set(char **s, char *v)
386 if (!v) {
387 *s = NULL;
388 return;
390 *s = strdup(v);
391 if (!*s) exit_cleanup(RERR_MALLOC);
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)
401 int i;
402 service tservice;
403 int num_to_alloc = iNumServices+1;
405 tservice = *pservice;
407 /* it might already exist */
408 if (name)
410 i = getservicebyname(name,NULL);
411 if (i >= 0)
412 return(i);
415 i = iNumServices;
417 ServicePtrs = (service **)Realloc(ServicePtrs,sizeof(service *)*num_to_alloc);
419 if (ServicePtrs)
420 pSERVICE(iNumServices) = (service *)malloc(sizeof(service));
422 if (!ServicePtrs || !pSERVICE(iNumServices))
423 return(-1);
425 iNumServices++;
427 init_service(pSERVICE(i));
428 copy_service(pSERVICE(i),&tservice);
429 if (name)
430 string_set(&iSERVICE(i).name,name);
432 return(i);
435 /***************************************************************************
436 Do a case-insensitive, whitespace-ignoring string compare.
437 ***************************************************************************/
438 static int strwicmp(char *psz1, char *psz2)
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);
451 /* sync the strings on first non-whitespace */
452 while (1)
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++;
463 return (*psz1 - *psz2);
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)
472 int iIndex;
474 if (*parmname == '-')
475 return(-1);
477 for (iIndex = 0; parm_table[iIndex].label; iIndex++)
478 if (strwicmp(parm_table[iIndex].label, parmname) == 0)
479 return(iIndex);
481 rprintf(FERROR, "Unknown Parameter encountered: \"%s\"\n", parmname);
482 return(-1);
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)
493 BOOL bRetval;
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
507 rprintf(FERROR, "Badly formed boolean in configuration file: \"%s\".\n",
508 parmvalue);
509 bRetval = False;
511 return (bRetval);
514 /***************************************************************************
515 Find a service by name. Otherwise works like get_service.
516 ***************************************************************************/
517 static int getservicebyname(char *name, service *pserviceDest)
519 int iService;
521 for (iService = iNumServices - 1; iService >= 0; iService--)
522 if (strwicmp(iSERVICE(iService).name, name) == 0)
524 if (pserviceDest != NULL)
525 copy_service(pserviceDest, pSERVICE(iService));
526 break;
529 return (iService);
534 /***************************************************************************
535 Copy a service structure to another
537 ***************************************************************************/
538 static void copy_service(service *pserviceDest,
539 service *pserviceSource)
541 int i;
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);
551 switch (parm_table[i].type)
553 case P_BOOL:
554 case P_BOOLREV:
555 *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
556 break;
558 case P_INTEGER:
559 case P_ENUM:
560 case P_OCTAL:
561 *(int *)dest_ptr = *(int *)src_ptr;
562 break;
564 case P_CHAR:
565 *(char *)dest_ptr = *(char *)src_ptr;
566 break;
568 case P_STRING:
569 string_set(dest_ptr,*(char **)src_ptr);
570 break;
572 default:
573 break;
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)
585 int parmnum, i;
586 void *parm_ptr=NULL; /* where we are going to store the result */
587 void *def_ptr=NULL;
589 parmnum = map_parameter(parmname);
591 if (parmnum < 0)
593 rprintf(FERROR, "IGNORING unknown parameter \"%s\"\n", parmname);
594 return(True);
597 def_ptr = parm_table[parmnum].ptr;
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);
607 parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
610 /* now switch on the type of variable it is */
611 switch (parm_table[parmnum].type)
613 case P_BOOL:
614 set_boolean(parm_ptr,parmvalue);
615 break;
617 case P_BOOLREV:
618 set_boolean(parm_ptr,parmvalue);
619 *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
620 break;
622 case P_INTEGER:
623 *(int *)parm_ptr = atoi(parmvalue);
624 break;
626 case P_CHAR:
627 *(char *)parm_ptr = *parmvalue;
628 break;
630 case P_OCTAL:
631 sscanf(parmvalue,"%o",(int *)parm_ptr);
632 break;
634 case P_STRING:
635 string_set(parm_ptr,parmvalue);
636 break;
638 case P_GSTRING:
639 strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));
640 break;
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;
649 if (!parm_table[parmnum].enum_list[i].name) {
650 if (atoi(parmvalue) > 0)
651 *(int *)parm_ptr = atoi(parmvalue);
653 break;
654 case P_SEP:
655 break;
658 return(True);
661 /***************************************************************************
662 Process a parameter.
663 ***************************************************************************/
664 static BOOL do_parameter(char *parmname, char *parmvalue)
666 return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
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)
676 BOOL bRetval;
677 BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
678 bRetval = False;
680 /* if we were in a global section then do the local inits */
681 if (bInGlobalSection && !isglobal)
682 init_locals();
684 /* if we've just struck a global section, note the fact. */
685 bInGlobalSection = isglobal;
687 /* check for multiple global sections */
688 if (bInGlobalSection)
690 return(True);
693 /* if we have a current service, tidy it up before moving on */
694 bRetval = True;
696 if (iServiceIndex >= 0)
697 bRetval = True;
699 /* if all is still well, move to the next record in the services array */
700 if (bRetval)
702 /* We put this here to avoid an odd message order if messages are */
703 /* issued by the post-processing of a previous section. */
705 if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
707 rprintf(FERROR,"Failed to add a new service\n");
708 return(False);
712 return (bRetval);
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)
722 pstring n2;
723 BOOL bRetval;
725 bRetval = False;
727 bInGlobalSection = True;
729 init_globals();
731 pstrcpy(n2,pszFname);
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);
737 bLoaded = True;
739 return (bRetval);
743 /***************************************************************************
744 return the max number of services
745 ***************************************************************************/
746 int lp_numservices(void)
748 return(iNumServices);
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)
759 int iService;
761 for (iService = iNumServices - 1; iService >= 0; iService--)
762 if (strequal(lp_name(iService), name))
763 break;
765 return (iService);