home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / rsync221.zip / loadparm.c < prev    next >
C/C++ Source or Header  |  1999-03-04  |  23KB  |  762 lines

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