Annotation of embedaddon/rsync/loadparm.c, revision 1.1
1.1 ! misho 1: /*
! 2: * This program is free software; you can redistribute it and/or modify
! 3: * it under the terms of the GNU General Public License as published by
! 4: * the Free Software Foundation; either version 3 of the License, or
! 5: * (at your option) any later version.
! 6: *
! 7: * This program is distributed in the hope that it will be useful,
! 8: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 9: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 10: * GNU General Public License for more details.
! 11: *
! 12: * You should have received a copy of the GNU General Public License along
! 13: * with this program; if not, visit the http://fsf.org website.
! 14: */
! 15:
! 16: /* This is based on loadparm.c from Samba, written by Andrew Tridgell
! 17: * and Karl Auer. Some of the changes are:
! 18: *
! 19: * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
! 20: * Copyright (C) 2003-2009 Wayne Davison <wayned@samba.org>
! 21: */
! 22:
! 23: /* Load parameters.
! 24: *
! 25: * This module provides suitable callback functions for the params
! 26: * module. It builds the internal table of service details which is
! 27: * then used by the rest of the server.
! 28: *
! 29: * To add a parameter:
! 30: *
! 31: * 1) add it to the global or service structure definition
! 32: * 2) add it to the parm_table
! 33: * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
! 34: * 4) If it's a global then initialise it in init_globals. If a local
! 35: * (ie. service) parameter then initialise it in the sDefault structure
! 36: *
! 37: *
! 38: * Notes:
! 39: * The configuration file is processed sequentially for speed. It is NOT
! 40: * accessed randomly as happens in 'real' Windows. For this reason, there
! 41: * is a fair bit of sequence-dependent code here - ie., code which assumes
! 42: * that certain things happen before others. In particular, the code which
! 43: * happens at the boundary between sections is delicately poised, so be
! 44: * careful!
! 45: *
! 46: */
! 47:
! 48: /* TODO: Parameter to set debug level on server. */
! 49:
! 50: #include "rsync.h"
! 51: #include "ifuncs.h"
! 52: #define PTR_DIFF(p1,p2) ((ptrdiff_t)(((char *)(p1)) - (char *)(p2)))
! 53: #define strequal(a,b) (strcasecmp(a,b)==0)
! 54: #define BOOLSTR(b) ((b) ? "Yes" : "No")
! 55: typedef char pstring[1024];
! 56: #define pstrcpy(a,b) strlcpy(a,b,sizeof(pstring))
! 57:
! 58: #ifndef LOG_DAEMON
! 59: #define LOG_DAEMON 0
! 60: #endif
! 61:
! 62: #define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
! 63: " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg"
! 64:
! 65: /* the following are used by loadparm for option lists */
! 66: typedef enum
! 67: {
! 68: P_BOOL,P_BOOLREV,P_CHAR,P_INTEGER,P_OCTAL,
! 69: P_PATH,P_STRING,P_GSTRING,P_ENUM,P_SEP
! 70: } parm_type;
! 71:
! 72: typedef enum
! 73: {
! 74: P_LOCAL,P_GLOBAL,P_SEPARATOR,P_NONE
! 75: } parm_class;
! 76:
! 77: struct enum_list {
! 78: int value;
! 79: char *name;
! 80: };
! 81:
! 82: struct parm_struct
! 83: {
! 84: char *label;
! 85: parm_type type;
! 86: parm_class class;
! 87: void *ptr;
! 88: struct enum_list *enum_list;
! 89: unsigned flags;
! 90: };
! 91:
! 92: #ifndef GLOBAL_NAME
! 93: #define GLOBAL_NAME "global"
! 94: #endif
! 95:
! 96: /* some helpful bits */
! 97: #define pSERVICE(i) ServicePtrs[i]
! 98: #define iSERVICE(i) (*pSERVICE(i))
! 99: #define LP_SNUM_OK(iService) (((iService) >= 0) && ((iService) < iNumServices))
! 100:
! 101: /*
! 102: * This structure describes global (ie., server-wide) parameters.
! 103: */
! 104: typedef struct
! 105: {
! 106: char *bind_address;
! 107: char *motd_file;
! 108: char *pid_file;
! 109: char *socket_options;
! 110:
! 111: int rsync_port;
! 112: } global;
! 113:
! 114: static global Globals;
! 115:
! 116:
! 117: /*
! 118: * This structure describes a single service. Their order must match the
! 119: * initializers below, which you can accomplish by keeping each sub-section
! 120: * sorted. (e.g. in vim, just visually select each subsection and use !sort.)
! 121: */
! 122: typedef struct
! 123: {
! 124: char *auth_users;
! 125: char *charset;
! 126: char *comment;
! 127: char *dont_compress;
! 128: char *exclude;
! 129: char *exclude_from;
! 130: char *filter;
! 131: char *gid;
! 132: char *hosts_allow;
! 133: char *hosts_deny;
! 134: char *include;
! 135: char *include_from;
! 136: char *incoming_chmod;
! 137: char *lock_file;
! 138: char *log_file;
! 139: char *log_format;
! 140: char *name;
! 141: char *outgoing_chmod;
! 142: char *path;
! 143: char *postxfer_exec;
! 144: char *prexfer_exec;
! 145: char *refuse_options;
! 146: char *secrets_file;
! 147: char *temp_dir;
! 148: char *uid;
! 149:
! 150: int max_connections;
! 151: int max_verbosity;
! 152: int syslog_facility;
! 153: int timeout;
! 154:
! 155: BOOL fake_super;
! 156: BOOL ignore_errors;
! 157: BOOL ignore_nonreadable;
! 158: BOOL list;
! 159: BOOL munge_symlinks;
! 160: BOOL numeric_ids;
! 161: BOOL read_only;
! 162: BOOL strict_modes;
! 163: BOOL transfer_logging;
! 164: BOOL use_chroot;
! 165: BOOL write_only;
! 166: } service;
! 167:
! 168:
! 169: /* This is a default service used to prime a services structure. In order
! 170: * to make these easy to keep sorted in the same way as the variables
! 171: * above, use the variable name in the leading comment, including a
! 172: * trailing ';' (to avoid a sorting problem with trailing digits). */
! 173: static service sDefault =
! 174: {
! 175: /* auth_users; */ NULL,
! 176: /* charset; */ NULL,
! 177: /* comment; */ NULL,
! 178: /* dont_compress; */ DEFAULT_DONT_COMPRESS,
! 179: /* exclude; */ NULL,
! 180: /* exclude_from; */ NULL,
! 181: /* filter; */ NULL,
! 182: /* gid; */ NOBODY_GROUP,
! 183: /* hosts_allow; */ NULL,
! 184: /* hosts_deny; */ NULL,
! 185: /* include; */ NULL,
! 186: /* include_from; */ NULL,
! 187: /* incoming_chmod; */ NULL,
! 188: /* lock_file; */ DEFAULT_LOCK_FILE,
! 189: /* log_file; */ NULL,
! 190: /* log_format; */ "%o %h [%a] %m (%u) %f %l",
! 191: /* name; */ NULL,
! 192: /* outgoing_chmod; */ NULL,
! 193: /* path; */ NULL,
! 194: /* postxfer_exec; */ NULL,
! 195: /* prexfer_exec; */ NULL,
! 196: /* refuse_options; */ NULL,
! 197: /* secrets_file; */ NULL,
! 198: /* temp_dir; */ NULL,
! 199: /* uid; */ NOBODY_USER,
! 200:
! 201: /* max_connections; */ 0,
! 202: /* max_verbosity; */ 1,
! 203: /* syslog_facility; */ LOG_DAEMON,
! 204: /* timeout; */ 0,
! 205:
! 206: /* fake_super; */ False,
! 207: /* ignore_errors; */ False,
! 208: /* ignore_nonreadable; */ False,
! 209: /* list; */ True,
! 210: /* munge_symlinks; */ (BOOL)-1,
! 211: /* numeric_ids; */ (BOOL)-1,
! 212: /* read_only; */ True,
! 213: /* strict_modes; */ True,
! 214: /* transfer_logging; */ False,
! 215: /* use_chroot; */ True,
! 216: /* write_only; */ False,
! 217: };
! 218:
! 219:
! 220:
! 221: /* local variables */
! 222: static service **ServicePtrs = NULL;
! 223: static int iNumServices = 0;
! 224: static int iServiceIndex = 0;
! 225: static BOOL bInGlobalSection = True;
! 226:
! 227: #define NUMPARAMETERS (sizeof(parm_table) / sizeof(struct parm_struct))
! 228:
! 229: static struct enum_list enum_facilities[] = {
! 230: #ifdef LOG_AUTH
! 231: { LOG_AUTH, "auth" },
! 232: #endif
! 233: #ifdef LOG_AUTHPRIV
! 234: { LOG_AUTHPRIV, "authpriv" },
! 235: #endif
! 236: #ifdef LOG_CRON
! 237: { LOG_CRON, "cron" },
! 238: #endif
! 239: #ifdef LOG_DAEMON
! 240: { LOG_DAEMON, "daemon" },
! 241: #endif
! 242: #ifdef LOG_FTP
! 243: { LOG_FTP, "ftp" },
! 244: #endif
! 245: #ifdef LOG_KERN
! 246: { LOG_KERN, "kern" },
! 247: #endif
! 248: #ifdef LOG_LPR
! 249: { LOG_LPR, "lpr" },
! 250: #endif
! 251: #ifdef LOG_MAIL
! 252: { LOG_MAIL, "mail" },
! 253: #endif
! 254: #ifdef LOG_NEWS
! 255: { LOG_NEWS, "news" },
! 256: #endif
! 257: #ifdef LOG_AUTH
! 258: { LOG_AUTH, "security" },
! 259: #endif
! 260: #ifdef LOG_SYSLOG
! 261: { LOG_SYSLOG, "syslog" },
! 262: #endif
! 263: #ifdef LOG_USER
! 264: { LOG_USER, "user" },
! 265: #endif
! 266: #ifdef LOG_UUCP
! 267: { LOG_UUCP, "uucp" },
! 268: #endif
! 269: #ifdef LOG_LOCAL0
! 270: { LOG_LOCAL0, "local0" },
! 271: #endif
! 272: #ifdef LOG_LOCAL1
! 273: { LOG_LOCAL1, "local1" },
! 274: #endif
! 275: #ifdef LOG_LOCAL2
! 276: { LOG_LOCAL2, "local2" },
! 277: #endif
! 278: #ifdef LOG_LOCAL3
! 279: { LOG_LOCAL3, "local3" },
! 280: #endif
! 281: #ifdef LOG_LOCAL4
! 282: { LOG_LOCAL4, "local4" },
! 283: #endif
! 284: #ifdef LOG_LOCAL5
! 285: { LOG_LOCAL5, "local5" },
! 286: #endif
! 287: #ifdef LOG_LOCAL6
! 288: { LOG_LOCAL6, "local6" },
! 289: #endif
! 290: #ifdef LOG_LOCAL7
! 291: { LOG_LOCAL7, "local7" },
! 292: #endif
! 293: { -1, NULL }};
! 294:
! 295:
! 296: /* note that we do not initialise the defaults union - it is not allowed in ANSI C */
! 297: static struct parm_struct parm_table[] =
! 298: {
! 299: {"address", P_STRING, P_GLOBAL,&Globals.bind_address, NULL,0},
! 300: {"motd file", P_STRING, P_GLOBAL,&Globals.motd_file, NULL,0},
! 301: {"pid file", P_STRING, P_GLOBAL,&Globals.pid_file, NULL,0},
! 302: {"port", P_INTEGER,P_GLOBAL,&Globals.rsync_port, NULL,0},
! 303: {"socket options", P_STRING, P_GLOBAL,&Globals.socket_options, NULL,0},
! 304:
! 305: {"auth users", P_STRING, P_LOCAL, &sDefault.auth_users, NULL,0},
! 306: {"charset", P_STRING, P_LOCAL, &sDefault.charset, NULL,0},
! 307: {"comment", P_STRING, P_LOCAL, &sDefault.comment, NULL,0},
! 308: {"dont compress", P_STRING, P_LOCAL, &sDefault.dont_compress, NULL,0},
! 309: {"exclude from", P_STRING, P_LOCAL, &sDefault.exclude_from, NULL,0},
! 310: {"exclude", P_STRING, P_LOCAL, &sDefault.exclude, NULL,0},
! 311: {"fake super", P_BOOL, P_LOCAL, &sDefault.fake_super, NULL,0},
! 312: {"filter", P_STRING, P_LOCAL, &sDefault.filter, NULL,0},
! 313: {"gid", P_STRING, P_LOCAL, &sDefault.gid, NULL,0},
! 314: {"hosts allow", P_STRING, P_LOCAL, &sDefault.hosts_allow, NULL,0},
! 315: {"hosts deny", P_STRING, P_LOCAL, &sDefault.hosts_deny, NULL,0},
! 316: {"ignore errors", P_BOOL, P_LOCAL, &sDefault.ignore_errors, NULL,0},
! 317: {"ignore nonreadable",P_BOOL, P_LOCAL, &sDefault.ignore_nonreadable,NULL,0},
! 318: {"include from", P_STRING, P_LOCAL, &sDefault.include_from, NULL,0},
! 319: {"include", P_STRING, P_LOCAL, &sDefault.include, NULL,0},
! 320: {"incoming chmod", P_STRING, P_LOCAL, &sDefault.incoming_chmod, NULL,0},
! 321: {"list", P_BOOL, P_LOCAL, &sDefault.list, NULL,0},
! 322: {"lock file", P_STRING, P_LOCAL, &sDefault.lock_file, NULL,0},
! 323: {"log file", P_STRING, P_LOCAL, &sDefault.log_file, NULL,0},
! 324: {"log format", P_STRING, P_LOCAL, &sDefault.log_format, NULL,0},
! 325: {"max connections", P_INTEGER,P_LOCAL, &sDefault.max_connections, NULL,0},
! 326: {"max verbosity", P_INTEGER,P_LOCAL, &sDefault.max_verbosity, NULL,0},
! 327: {"munge symlinks", P_BOOL, P_LOCAL, &sDefault.munge_symlinks, NULL,0},
! 328: {"name", P_STRING, P_LOCAL, &sDefault.name, NULL,0},
! 329: {"numeric ids", P_BOOL, P_LOCAL, &sDefault.numeric_ids, NULL,0},
! 330: {"outgoing chmod", P_STRING, P_LOCAL, &sDefault.outgoing_chmod, NULL,0},
! 331: {"path", P_PATH, P_LOCAL, &sDefault.path, NULL,0},
! 332: #ifdef HAVE_PUTENV
! 333: {"post-xfer exec", P_STRING, P_LOCAL, &sDefault.postxfer_exec, NULL,0},
! 334: {"pre-xfer exec", P_STRING, P_LOCAL, &sDefault.prexfer_exec, NULL,0},
! 335: #endif
! 336: {"read only", P_BOOL, P_LOCAL, &sDefault.read_only, NULL,0},
! 337: {"refuse options", P_STRING, P_LOCAL, &sDefault.refuse_options, NULL,0},
! 338: {"secrets file", P_STRING, P_LOCAL, &sDefault.secrets_file, NULL,0},
! 339: {"strict modes", P_BOOL, P_LOCAL, &sDefault.strict_modes, NULL,0},
! 340: {"syslog facility", P_ENUM, P_LOCAL, &sDefault.syslog_facility,enum_facilities,0},
! 341: {"temp dir", P_PATH, P_LOCAL, &sDefault.temp_dir, NULL,0},
! 342: {"timeout", P_INTEGER,P_LOCAL, &sDefault.timeout, NULL,0},
! 343: {"transfer logging", P_BOOL, P_LOCAL, &sDefault.transfer_logging, NULL,0},
! 344: {"uid", P_STRING, P_LOCAL, &sDefault.uid, NULL,0},
! 345: {"use chroot", P_BOOL, P_LOCAL, &sDefault.use_chroot, NULL,0},
! 346: {"write only", P_BOOL, P_LOCAL, &sDefault.write_only, NULL,0},
! 347: {NULL, P_BOOL, P_NONE, NULL, NULL,0}
! 348: };
! 349:
! 350:
! 351: /***************************************************************************
! 352: * Initialise the global parameter structure.
! 353: ***************************************************************************/
! 354: static void init_globals(void)
! 355: {
! 356: memset(&Globals, 0, sizeof Globals);
! 357: }
! 358:
! 359: /***************************************************************************
! 360: * Initialise the sDefault parameter structure.
! 361: ***************************************************************************/
! 362: static void init_locals(void)
! 363: {
! 364: }
! 365:
! 366:
! 367: /*
! 368: In this section all the functions that are used to access the
! 369: parameters from the rest of the program are defined
! 370: */
! 371:
! 372: #define FN_GLOBAL_STRING(fn_name,ptr) \
! 373: char *fn_name(void) {return(*(char **)(ptr) ? *(char **)(ptr) : "");}
! 374: #define FN_GLOBAL_BOOL(fn_name,ptr) \
! 375: BOOL fn_name(void) {return(*(BOOL *)(ptr));}
! 376: #define FN_GLOBAL_CHAR(fn_name,ptr) \
! 377: char fn_name(void) {return(*(char *)(ptr));}
! 378: #define FN_GLOBAL_INTEGER(fn_name,ptr) \
! 379: int fn_name(void) {return(*(int *)(ptr));}
! 380:
! 381: #define FN_LOCAL_STRING(fn_name,val) \
! 382: char *fn_name(int i) {return((LP_SNUM_OK(i)&&pSERVICE(i)->val)?pSERVICE(i)->val : (sDefault.val?sDefault.val:""));}
! 383: #define FN_LOCAL_BOOL(fn_name,val) \
! 384: BOOL fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
! 385: #define FN_LOCAL_CHAR(fn_name,val) \
! 386: char fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
! 387: #define FN_LOCAL_INTEGER(fn_name,val) \
! 388: int fn_name(int i) {return(LP_SNUM_OK(i)? pSERVICE(i)->val : sDefault.val);}
! 389:
! 390:
! 391: FN_GLOBAL_STRING(lp_bind_address, &Globals.bind_address)
! 392: FN_GLOBAL_STRING(lp_motd_file, &Globals.motd_file)
! 393: FN_GLOBAL_STRING(lp_pid_file, &Globals.pid_file)
! 394: FN_GLOBAL_STRING(lp_socket_options, &Globals.socket_options)
! 395:
! 396: FN_GLOBAL_INTEGER(lp_rsync_port, &Globals.rsync_port)
! 397:
! 398: FN_LOCAL_STRING(lp_auth_users, auth_users)
! 399: FN_LOCAL_STRING(lp_charset, charset)
! 400: FN_LOCAL_STRING(lp_comment, comment)
! 401: FN_LOCAL_STRING(lp_dont_compress, dont_compress)
! 402: FN_LOCAL_STRING(lp_exclude, exclude)
! 403: FN_LOCAL_STRING(lp_exclude_from, exclude_from)
! 404: FN_LOCAL_STRING(lp_filter, filter)
! 405: FN_LOCAL_STRING(lp_gid, gid)
! 406: FN_LOCAL_STRING(lp_hosts_allow, hosts_allow)
! 407: FN_LOCAL_STRING(lp_hosts_deny, hosts_deny)
! 408: FN_LOCAL_STRING(lp_include, include)
! 409: FN_LOCAL_STRING(lp_include_from, include_from)
! 410: FN_LOCAL_STRING(lp_incoming_chmod, incoming_chmod)
! 411: FN_LOCAL_STRING(lp_lock_file, lock_file)
! 412: FN_LOCAL_STRING(lp_log_file, log_file)
! 413: FN_LOCAL_STRING(lp_log_format, log_format)
! 414: FN_LOCAL_STRING(lp_name, name)
! 415: FN_LOCAL_STRING(lp_outgoing_chmod, outgoing_chmod)
! 416: FN_LOCAL_STRING(lp_path, path)
! 417: FN_LOCAL_STRING(lp_postxfer_exec, postxfer_exec)
! 418: FN_LOCAL_STRING(lp_prexfer_exec, prexfer_exec)
! 419: FN_LOCAL_STRING(lp_refuse_options, refuse_options)
! 420: FN_LOCAL_STRING(lp_secrets_file, secrets_file)
! 421: FN_LOCAL_STRING(lp_temp_dir, temp_dir)
! 422: FN_LOCAL_STRING(lp_uid, uid)
! 423:
! 424: FN_LOCAL_INTEGER(lp_max_connections, max_connections)
! 425: FN_LOCAL_INTEGER(lp_max_verbosity, max_verbosity)
! 426: FN_LOCAL_INTEGER(lp_syslog_facility, syslog_facility)
! 427: FN_LOCAL_INTEGER(lp_timeout, timeout)
! 428:
! 429: FN_LOCAL_BOOL(lp_fake_super, fake_super)
! 430: FN_LOCAL_BOOL(lp_ignore_errors, ignore_errors)
! 431: FN_LOCAL_BOOL(lp_ignore_nonreadable, ignore_nonreadable)
! 432: FN_LOCAL_BOOL(lp_list, list)
! 433: FN_LOCAL_BOOL(lp_munge_symlinks, munge_symlinks)
! 434: FN_LOCAL_BOOL(lp_numeric_ids, numeric_ids)
! 435: FN_LOCAL_BOOL(lp_read_only, read_only)
! 436: FN_LOCAL_BOOL(lp_strict_modes, strict_modes)
! 437: FN_LOCAL_BOOL(lp_transfer_logging, transfer_logging)
! 438: FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
! 439: FN_LOCAL_BOOL(lp_write_only, write_only)
! 440:
! 441: /* local prototypes */
! 442: static int strwicmp(char *psz1, char *psz2);
! 443: static int map_parameter(char *parmname);
! 444: static BOOL set_boolean(BOOL *pb, char *parmvalue);
! 445: static int getservicebyname(char *name, service *pserviceDest);
! 446: static void copy_service(service *pserviceDest, service *pserviceSource);
! 447: static BOOL do_parameter(char *parmname, char *parmvalue);
! 448: static BOOL do_section(char *sectionname);
! 449:
! 450:
! 451: /***************************************************************************
! 452: * initialise a service to the defaults
! 453: ***************************************************************************/
! 454: static void init_service(service *pservice)
! 455: {
! 456: memset((char *)pservice,0,sizeof(service));
! 457: copy_service(pservice,&sDefault);
! 458: }
! 459:
! 460:
! 461: /**
! 462: * Assign a copy of @p v to @p *s. Handles NULL strings. @p *v must
! 463: * be initialized when this is called, either to NULL or a malloc'd
! 464: * string.
! 465: *
! 466: * @fixme There is a small leak here in that sometimes the existing
! 467: * value will be dynamically allocated, and the old copy is lost.
! 468: * However, we can't always deallocate the old value, because in the
! 469: * case of sDefault, it points to a static string. It would be nice
! 470: * to have either all-strdup'd values, or to never need to free
! 471: * memory.
! 472: **/
! 473: static void string_set(char **s, const char *v)
! 474: {
! 475: if (!v) {
! 476: *s = NULL;
! 477: return;
! 478: }
! 479: *s = strdup(v);
! 480: if (!*s)
! 481: exit_cleanup(RERR_MALLOC);
! 482: }
! 483:
! 484:
! 485: /***************************************************************************
! 486: * add a new service to the services array initialising it with the given
! 487: * service
! 488: ***************************************************************************/
! 489: static int add_a_service(service *pservice, char *name)
! 490: {
! 491: int i;
! 492: service tservice;
! 493: int num_to_alloc = iNumServices+1;
! 494:
! 495: tservice = *pservice;
! 496:
! 497: /* it might already exist */
! 498: if (name)
! 499: {
! 500: i = getservicebyname(name,NULL);
! 501: if (i >= 0)
! 502: return(i);
! 503: }
! 504:
! 505: i = iNumServices;
! 506:
! 507: ServicePtrs = realloc_array(ServicePtrs, service *, num_to_alloc);
! 508:
! 509: if (ServicePtrs)
! 510: pSERVICE(iNumServices) = new(service);
! 511:
! 512: if (!ServicePtrs || !pSERVICE(iNumServices))
! 513: return(-1);
! 514:
! 515: iNumServices++;
! 516:
! 517: init_service(pSERVICE(i));
! 518: copy_service(pSERVICE(i),&tservice);
! 519: if (name)
! 520: string_set(&iSERVICE(i).name,name);
! 521:
! 522: return(i);
! 523: }
! 524:
! 525: /***************************************************************************
! 526: * Do a case-insensitive, whitespace-ignoring string compare.
! 527: ***************************************************************************/
! 528: static int strwicmp(char *psz1, char *psz2)
! 529: {
! 530: /* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
! 531: /* appropriate value. */
! 532: if (psz1 == psz2)
! 533: return (0);
! 534: else
! 535: if (psz1 == NULL)
! 536: return (-1);
! 537: else
! 538: if (psz2 == NULL)
! 539: return (1);
! 540:
! 541: /* sync the strings on first non-whitespace */
! 542: while (1)
! 543: {
! 544: while (isSpace(psz1))
! 545: psz1++;
! 546: while (isSpace(psz2))
! 547: psz2++;
! 548: if (toUpper(psz1) != toUpper(psz2) || *psz1 == '\0' || *psz2 == '\0')
! 549: break;
! 550: psz1++;
! 551: psz2++;
! 552: }
! 553: return (*psz1 - *psz2);
! 554: }
! 555:
! 556: /***************************************************************************
! 557: * Map a parameter's string representation to something we can use.
! 558: * Returns False if the parameter string is not recognised, else TRUE.
! 559: ***************************************************************************/
! 560: static int map_parameter(char *parmname)
! 561: {
! 562: int iIndex;
! 563:
! 564: if (*parmname == '-')
! 565: return(-1);
! 566:
! 567: for (iIndex = 0; parm_table[iIndex].label; iIndex++)
! 568: if (strwicmp(parm_table[iIndex].label, parmname) == 0)
! 569: return(iIndex);
! 570:
! 571: rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname);
! 572: return(-1);
! 573: }
! 574:
! 575:
! 576: /***************************************************************************
! 577: * Set a boolean variable from the text value stored in the passed string.
! 578: * Returns True in success, False if the passed string does not correctly
! 579: * represent a boolean.
! 580: ***************************************************************************/
! 581: static BOOL set_boolean(BOOL *pb, char *parmvalue)
! 582: {
! 583: BOOL bRetval;
! 584:
! 585: bRetval = True;
! 586: if (strwicmp(parmvalue, "yes") == 0 ||
! 587: strwicmp(parmvalue, "true") == 0 ||
! 588: strwicmp(parmvalue, "1") == 0)
! 589: *pb = True;
! 590: else
! 591: if (strwicmp(parmvalue, "no") == 0 ||
! 592: strwicmp(parmvalue, "False") == 0 ||
! 593: strwicmp(parmvalue, "0") == 0)
! 594: *pb = False;
! 595: else
! 596: {
! 597: rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n",
! 598: parmvalue);
! 599: bRetval = False;
! 600: }
! 601: return (bRetval);
! 602: }
! 603:
! 604: /***************************************************************************
! 605: * Find a service by name. Otherwise works like get_service.
! 606: ***************************************************************************/
! 607: static int getservicebyname(char *name, service *pserviceDest)
! 608: {
! 609: int iService;
! 610:
! 611: for (iService = iNumServices - 1; iService >= 0; iService--)
! 612: if (strwicmp(iSERVICE(iService).name, name) == 0)
! 613: {
! 614: if (pserviceDest != NULL)
! 615: copy_service(pserviceDest, pSERVICE(iService));
! 616: break;
! 617: }
! 618:
! 619: return (iService);
! 620: }
! 621:
! 622:
! 623:
! 624: /***************************************************************************
! 625: * Copy a service structure to another
! 626: ***************************************************************************/
! 627: static void copy_service(service *pserviceDest,
! 628: service *pserviceSource)
! 629: {
! 630: int i;
! 631:
! 632: for (i=0;parm_table[i].label;i++)
! 633: if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
! 634: void *def_ptr = parm_table[i].ptr;
! 635: void *src_ptr =
! 636: ((char *)pserviceSource) + PTR_DIFF(def_ptr,&sDefault);
! 637: void *dest_ptr =
! 638: ((char *)pserviceDest) + PTR_DIFF(def_ptr,&sDefault);
! 639:
! 640: switch (parm_table[i].type)
! 641: {
! 642: case P_BOOL:
! 643: case P_BOOLREV:
! 644: *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
! 645: break;
! 646:
! 647: case P_INTEGER:
! 648: case P_ENUM:
! 649: case P_OCTAL:
! 650: *(int *)dest_ptr = *(int *)src_ptr;
! 651: break;
! 652:
! 653: case P_CHAR:
! 654: *(char *)dest_ptr = *(char *)src_ptr;
! 655: break;
! 656:
! 657: case P_PATH:
! 658: case P_STRING:
! 659: string_set(dest_ptr,*(char **)src_ptr);
! 660: break;
! 661:
! 662: default:
! 663: break;
! 664: }
! 665: }
! 666: }
! 667:
! 668:
! 669: /***************************************************************************
! 670: * Process a parameter for a particular service number. If snum < 0
! 671: * then assume we are in the globals
! 672: ***************************************************************************/
! 673: static BOOL lp_do_parameter(int snum, char *parmname, char *parmvalue)
! 674: {
! 675: int parmnum, i;
! 676: void *parm_ptr=NULL; /* where we are going to store the result */
! 677: void *def_ptr=NULL;
! 678: char *cp;
! 679:
! 680: parmnum = map_parameter(parmname);
! 681:
! 682: if (parmnum < 0)
! 683: {
! 684: rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname);
! 685: return(True);
! 686: }
! 687:
! 688: def_ptr = parm_table[parmnum].ptr;
! 689:
! 690: /* we might point at a service, the default service or a global */
! 691: if (snum < 0) {
! 692: parm_ptr = def_ptr;
! 693: } else {
! 694: if (parm_table[parmnum].class == P_GLOBAL) {
! 695: rprintf(FLOG, "Global parameter %s found in service section!\n",parmname);
! 696: return(True);
! 697: }
! 698: parm_ptr = ((char *)pSERVICE(snum)) + PTR_DIFF(def_ptr,&sDefault);
! 699: }
! 700:
! 701: /* now switch on the type of variable it is */
! 702: switch (parm_table[parmnum].type)
! 703: {
! 704: case P_BOOL:
! 705: set_boolean(parm_ptr,parmvalue);
! 706: break;
! 707:
! 708: case P_BOOLREV:
! 709: set_boolean(parm_ptr,parmvalue);
! 710: *(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
! 711: break;
! 712:
! 713: case P_INTEGER:
! 714: *(int *)parm_ptr = atoi(parmvalue);
! 715: break;
! 716:
! 717: case P_CHAR:
! 718: *(char *)parm_ptr = *parmvalue;
! 719: break;
! 720:
! 721: case P_OCTAL:
! 722: sscanf(parmvalue,"%o",(int *)parm_ptr);
! 723: break;
! 724:
! 725: case P_PATH:
! 726: string_set(parm_ptr,parmvalue);
! 727: if ((cp = *(char**)parm_ptr) != NULL) {
! 728: int len = strlen(cp);
! 729: while (len > 1 && cp[len-1] == '/') len--;
! 730: cp[len] = '\0';
! 731: }
! 732: break;
! 733:
! 734: case P_STRING:
! 735: string_set(parm_ptr,parmvalue);
! 736: break;
! 737:
! 738: case P_GSTRING:
! 739: strlcpy((char *)parm_ptr,parmvalue,sizeof(pstring));
! 740: break;
! 741:
! 742: case P_ENUM:
! 743: for (i=0;parm_table[parmnum].enum_list[i].name;i++) {
! 744: if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
! 745: *(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
! 746: break;
! 747: }
! 748: }
! 749: if (!parm_table[parmnum].enum_list[i].name) {
! 750: if (atoi(parmvalue) > 0)
! 751: *(int *)parm_ptr = atoi(parmvalue);
! 752: }
! 753: break;
! 754: case P_SEP:
! 755: break;
! 756: }
! 757:
! 758: return(True);
! 759: }
! 760:
! 761: /***************************************************************************
! 762: * Process a parameter.
! 763: ***************************************************************************/
! 764: static BOOL do_parameter(char *parmname, char *parmvalue)
! 765: {
! 766: return lp_do_parameter(bInGlobalSection?-2:iServiceIndex, parmname, parmvalue);
! 767: }
! 768:
! 769: /***************************************************************************
! 770: * Process a new section (service). At this stage all sections are services.
! 771: * Later we'll have special sections that permit server parameters to be set.
! 772: * Returns True on success, False on failure.
! 773: ***************************************************************************/
! 774: static BOOL do_section(char *sectionname)
! 775: {
! 776: BOOL bRetval;
! 777: BOOL isglobal = (strwicmp(sectionname, GLOBAL_NAME) == 0);
! 778: bRetval = False;
! 779:
! 780: /* if we were in a global section then do the local inits */
! 781: if (bInGlobalSection && !isglobal)
! 782: init_locals();
! 783:
! 784: /* if we've just struck a global section, note the fact. */
! 785: bInGlobalSection = isglobal;
! 786:
! 787: /* check for multiple global sections */
! 788: if (bInGlobalSection)
! 789: {
! 790: return(True);
! 791: }
! 792:
! 793: if (strchr(sectionname, '/') != NULL) {
! 794: rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname);
! 795: return False;
! 796: }
! 797:
! 798: /* if we have a current service, tidy it up before moving on */
! 799: bRetval = True;
! 800:
! 801: if (iServiceIndex >= 0)
! 802: bRetval = True;
! 803:
! 804: /* if all is still well, move to the next record in the services array */
! 805: if (bRetval)
! 806: {
! 807: /* We put this here to avoid an odd message order if messages are */
! 808: /* issued by the post-processing of a previous section. */
! 809:
! 810: if ((iServiceIndex=add_a_service(&sDefault,sectionname)) < 0)
! 811: {
! 812: rprintf(FLOG, "Failed to add a new service\n");
! 813: return(False);
! 814: }
! 815: }
! 816:
! 817: return (bRetval);
! 818: }
! 819:
! 820:
! 821: /***************************************************************************
! 822: * Load the services array from the services file. Return True on success,
! 823: * False on failure.
! 824: ***************************************************************************/
! 825: BOOL lp_load(char *pszFname, int globals_only)
! 826: {
! 827: pstring n2;
! 828: BOOL bRetval;
! 829:
! 830: bRetval = False;
! 831:
! 832: bInGlobalSection = True;
! 833:
! 834: init_globals();
! 835:
! 836: pstrcpy(n2, pszFname);
! 837:
! 838: /* We get sections first, so have to start 'behind' to make up */
! 839: iServiceIndex = -1;
! 840: bRetval = pm_process(n2, globals_only?NULL:do_section, do_parameter);
! 841:
! 842: return (bRetval);
! 843: }
! 844:
! 845:
! 846: /***************************************************************************
! 847: * return the max number of services
! 848: ***************************************************************************/
! 849: int lp_numservices(void)
! 850: {
! 851: return(iNumServices);
! 852: }
! 853:
! 854: /***************************************************************************
! 855: * Return the number of the service with the given name, or -1 if it doesn't
! 856: * exist. Note that this is a DIFFERENT ANIMAL from the internal function
! 857: * getservicebyname()! This works ONLY if all services have been loaded, and
! 858: * does not copy the found service.
! 859: ***************************************************************************/
! 860: int lp_number(char *name)
! 861: {
! 862: int iService;
! 863:
! 864: for (iService = iNumServices - 1; iService >= 0; iService--)
! 865: if (strcmp(lp_name(iService), name) == 0)
! 866: break;
! 867:
! 868: return (iService);
! 869: }
! 870:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>