File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / rsync / loadparm.c
Revision 1.1.1.4 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 00:32:36 2021 UTC (3 years, 3 months ago) by misho
Branches: rsync, MAIN
CVS tags: v3_2_3, HEAD
rsync 3.2.3

    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:  * This is based on loadparm.c from Samba, written by Andrew Tridgell
   16:  * and Karl Auer.  Some of the changes are:
   17:  *
   18:  * Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org>
   19:  * Copyright (C) 2003-2020 Wayne Davison
   20:  */
   21: 
   22: /* Load parameters.
   23:  *
   24:  *  This module provides suitable callback functions for the params
   25:  *  module. It builds the internal table of section details which is
   26:  *  then used by the rest of the server.
   27:  *
   28:  * To add a parameter:
   29:  *
   30:  * 1) add it to the global_vars or local_vars structure definition
   31:  * 2) add it to the parm_table
   32:  * 3) add it to the list of available functions (eg: using FN_GLOBAL_STRING())
   33:  * 4) initialise it in the Defaults static structure
   34:  *
   35:  * Notes:
   36:  *   The configuration file is processed sequentially for speed. For this
   37:  *   reason, there is a fair bit of sequence-dependent code here - ie., code
   38:  *   which assumes that certain things happen before others. In particular, the
   39:  *   code which happens at the boundary between sections is delicately poised,
   40:  *   so be careful!
   41:  */
   42: 
   43: #include "rsync.h"
   44: #include "itypes.h"
   45: #include "ifuncs.h"
   46: #include "default-dont-compress.h"
   47: 
   48: extern item_list dparam_list;
   49: 
   50: #define strequal(a, b) (strcasecmp(a, b)==0)
   51: 
   52: #ifndef LOG_DAEMON
   53: #define LOG_DAEMON 0
   54: #endif
   55: 
   56: /* the following are used by loadparm for option lists */
   57: typedef enum {
   58: 	P_BOOL, P_BOOLREV, P_BOOL3, P_CHAR, P_INTEGER,
   59: 	P_OCTAL, P_PATH, P_STRING, P_ENUM
   60: } parm_type;
   61: 
   62: typedef enum {
   63: 	P_LOCAL, P_GLOBAL, P_NONE
   64: } parm_class;
   65: 
   66: struct enum_list {
   67: 	int value;
   68: 	char *name;
   69: };
   70: 
   71: 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;
   78: };
   79: 
   80: #ifndef GLOBAL_NAME
   81: #define GLOBAL_NAME "global"
   82: #endif
   83: 
   84: /* some helpful bits */
   85: #define iSECTION(i) ((local_vars*)section_list.items)[i]
   86: #define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count)
   87: #define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char*)(p))-(char*)&Vars.l))
   88: 
   89: /* Stack of "Vars" values used by the &include directive. */
   90: static item_list Vars_stack = EMPTY_ITEM_LIST;
   91: 
   92: /* The array of section values that holds all the defined modules. */
   93: static item_list section_list = EMPTY_ITEM_LIST;
   94: 
   95: static int iSectionIndex = -1;
   96: static BOOL bInGlobalSection = True;
   97: 
   98: static struct enum_list enum_syslog_facility[] = {
   99: #ifdef LOG_AUTH
  100: 	{ LOG_AUTH, "auth" },
  101: #endif
  102: #ifdef LOG_AUTHPRIV
  103: 	{ LOG_AUTHPRIV, "authpriv" },
  104: #endif
  105: #ifdef LOG_CRON
  106: 	{ LOG_CRON, "cron" },
  107: #endif
  108: #ifdef LOG_DAEMON
  109: 	{ LOG_DAEMON, "daemon" },
  110: #endif
  111: #ifdef LOG_FTP
  112: 	{ LOG_FTP, "ftp" },
  113: #endif
  114: #ifdef LOG_KERN
  115: 	{ LOG_KERN, "kern" },
  116: #endif
  117: #ifdef LOG_LPR
  118: 	{ LOG_LPR, "lpr" },
  119: #endif
  120: #ifdef LOG_MAIL
  121: 	{ LOG_MAIL, "mail" },
  122: #endif
  123: #ifdef LOG_NEWS
  124: 	{ LOG_NEWS, "news" },
  125: #endif
  126: #ifdef LOG_AUTH
  127: 	{ LOG_AUTH, "security" },
  128: #endif
  129: #ifdef LOG_SYSLOG
  130: 	{ LOG_SYSLOG, "syslog" },
  131: #endif
  132: #ifdef LOG_USER
  133: 	{ LOG_USER, "user" },
  134: #endif
  135: #ifdef LOG_UUCP
  136: 	{ LOG_UUCP, "uucp" },
  137: #endif
  138: #ifdef LOG_LOCAL0
  139: 	{ LOG_LOCAL0, "local0" },
  140: #endif
  141: #ifdef LOG_LOCAL1
  142: 	{ LOG_LOCAL1, "local1" },
  143: #endif
  144: #ifdef LOG_LOCAL2
  145: 	{ LOG_LOCAL2, "local2" },
  146: #endif
  147: #ifdef LOG_LOCAL3
  148: 	{ LOG_LOCAL3, "local3" },
  149: #endif
  150: #ifdef LOG_LOCAL4
  151: 	{ LOG_LOCAL4, "local4" },
  152: #endif
  153: #ifdef LOG_LOCAL5
  154: 	{ LOG_LOCAL5, "local5" },
  155: #endif
  156: #ifdef LOG_LOCAL6
  157: 	{ LOG_LOCAL6, "local6" },
  158: #endif
  159: #ifdef LOG_LOCAL7
  160: 	{ LOG_LOCAL7, "local7" },
  161: #endif
  162: 	{ -1, NULL }
  163: };
  164: 
  165: static struct enum_list enum_checksum_files[] = {
  166: 	{ CSF_IGNORE_FILES, "none" },
  167: 	{ CSF_LAX_MODE, "lax" },
  168: 	{ CSF_STRICT_MODE, "strict" },
  169: 	{ CSF_LAX_MODE|CSF_UPDATE, "+lax" },
  170: 	{ CSF_STRICT_MODE|CSF_UPDATE, "+strict" },
  171: 	{ CSF_LAX_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++lax" },
  172: 	{ CSF_STRICT_MODE|CSF_UPDATE|CSF_AFFECT_DRYRUN, "++strict" },
  173: 	{ -1, NULL }
  174: };
  175: 
  176: /* Expand %VAR% references.  Any unknown vars or unrecognized
  177:  * syntax leaves the raw chars unchanged. */
  178: static char *expand_vars(const char *str)
  179: {
  180: 	char *buf, *t;
  181: 	const char *f;
  182: 	int bufsize;
  183: 
  184: 	if (!str || !strchr(str, '%'))
  185: 		return (char *)str; /* TODO change return value to const char* at some point. */
  186: 
  187: 	bufsize = strlen(str) + 2048;
  188: 	buf = new_array(char, bufsize+1); /* +1 for trailing '\0' */
  189: 
  190: 	for (t = buf, f = str; bufsize && *f; ) {
  191: 		if (*f == '%' && isUpper(f+1)) {
  192: 			char *percent = strchr(f+1, '%');
  193: 			if (percent && percent - f < bufsize) {
  194: 				char *val;
  195: 				strlcpy(t, f+1, percent - f);
  196: 				val = getenv(t);
  197: 				if (val) {
  198: 					int len = strlcpy(t, val, bufsize+1);
  199: 					if (len > bufsize)
  200: 						break;
  201: 					bufsize -= len;
  202: 					t += len;
  203: 					f = percent + 1;
  204: 					continue;
  205: 				}
  206: 			}
  207: 		}
  208: 		*t++ = *f++;
  209: 		bufsize--;
  210: 	}
  211: 	*t = '\0';
  212: 
  213: 	if (*f) {
  214: 		rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str);
  215: 		exit_cleanup(RERR_MALLOC);
  216: 	}
  217: 
  218: 	if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL)
  219: 		out_of_memory("expand_vars");
  220: 
  221: 	return buf;
  222: }
  223: 
  224: /* Each "char* foo" has an associated "BOOL foo_EXP" that tracks if the string has been expanded yet or not. */
  225: 
  226: /* NOTE: use this function and all the FN_{GLOBAL,LOCAL} ones WITHOUT a trailing semicolon! */
  227: #define RETURN_EXPANDED(val) {if (!val ## _EXP) {val = expand_vars(val); val ## _EXP = True;} return val ? val : "";}
  228: 
  229: /* In this section all the functions that are used to access the
  230:  * parameters from the rest of the program are defined. */
  231: 
  232: #define FN_GLOBAL_STRING(fn_name, val) \
  233:  char *fn_name(void) RETURN_EXPANDED(Vars.g.val)
  234: #define FN_GLOBAL_BOOL(fn_name, val) \
  235:  BOOL fn_name(void) {return Vars.g.val;}
  236: #define FN_GLOBAL_CHAR(fn_name, val) \
  237:  char fn_name(void) {return Vars.g.val;}
  238: #define FN_GLOBAL_INTEGER(fn_name, val) \
  239:  int fn_name(void) {return Vars.g.val;}
  240: 
  241: #define FN_LOCAL_STRING(fn_name, val) \
  242:  char *fn_name(int i) {if (LP_SNUM_OK(i) && iSECTION(i).val) RETURN_EXPANDED(iSECTION(i).val) else RETURN_EXPANDED(Vars.l.val)}
  243: #define FN_LOCAL_BOOL(fn_name, val) \
  244:  BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
  245: #define FN_LOCAL_CHAR(fn_name, val) \
  246:  char fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
  247: #define FN_LOCAL_INTEGER(fn_name, val) \
  248:  int fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
  249: 
  250: /* The following include file contains:
  251:  *
  252:  * typedef global_vars - describes global (ie., server-wide) parameters.
  253:  * typedef local_vars - describes a single section.
  254:  * typedef all_vars - a combination of global_vars & local_vars.
  255:  * all_vars Defaults - the default values for all the variables.
  256:  * all_vars Vars - the currently configured values for all the variables.
  257:  * struct parm_struct parm_table - the strings & variables for the parser.
  258:  * FN_{LOCAL,GLOBAL}_{TYPE}() definition for all the lp_var_name() accessors.
  259:  */
  260: 
  261: #include "daemon-parm.h"
  262: 
  263: /* Initialise the Default all_vars structure. */
  264: void reset_daemon_vars(void)
  265: {
  266: 	memcpy(&Vars, &Defaults, sizeof Vars);
  267: }
  268: 
  269: /* Assign a copy of v to *s.  Handles NULL strings.  We don't worry
  270:  * about overwriting a malloc'd string because the long-running
  271:  * (port-listening) daemon only loads the config file once, and the
  272:  * per-job (forked or xinitd-ran) daemon only re-reads the file at
  273:  * the start, so any lost memory is inconsequential. */
  274: static inline void string_set(char **s, const char *v)
  275: {
  276: 	*s = v ? strdup(v) : NULL;
  277: }
  278: 
  279: /* Copy local_vars into a new section. No need to strdup since we don't free. */
  280: static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
  281: {
  282: 	memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
  283: }
  284: 
  285: /* Initialise a section to the defaults. */
  286: static void init_section(local_vars *psection)
  287: {
  288: 	memset(psection, 0, sizeof (local_vars));
  289: 	copy_section(psection, &Vars.l);
  290: }
  291: 
  292: /* Do a case-insensitive, whitespace-ignoring string equality check. */
  293: static int strwiEQ(char *psz1, char *psz2)
  294: {
  295: 	/* If one or both strings are NULL, we return equality right away. */
  296: 	if (psz1 == psz2)
  297: 		return 1;
  298: 	if (psz1 == NULL || psz2 == NULL)
  299: 		return 0;
  300: 
  301: 	/* sync the strings on first non-whitespace */
  302: 	while (1) {
  303: 		while (isSpace(psz1))
  304: 			psz1++;
  305: 		while (isSpace(psz2))
  306: 			psz2++;
  307: 		if (*psz1 == '\0' || *psz2 == '\0')
  308: 			break;
  309: 		if (toUpper(psz1) != toUpper(psz2))
  310: 			break;
  311: 		psz1++;
  312: 		psz2++;
  313: 	}
  314: 	return *psz1 == *psz2;
  315: }
  316: 
  317: /* Find a section by name. Otherwise works like get_section. */
  318: static int getsectionbyname(char *name)
  319: {
  320: 	int i;
  321: 
  322: 	for (i = section_list.count - 1; i >= 0; i--) {
  323: 		if (strwiEQ(iSECTION(i).name, name))
  324: 			break;
  325: 	}
  326: 
  327: 	return i;
  328: }
  329: 
  330: /* Add a new section to the sections array w/the default values. */
  331: static int add_a_section(char *name)
  332: {
  333: 	int i;
  334: 	local_vars *s;
  335: 
  336: 	/* it might already exist */
  337: 	if (name) {
  338: 		i = getsectionbyname(name);
  339: 		if (i >= 0)
  340: 			return i;
  341: 	}
  342: 
  343: 	i = section_list.count;
  344: 	s = EXPAND_ITEM_LIST(&section_list, local_vars, 2);
  345: 
  346: 	init_section(s);
  347: 	if (name)
  348: 		string_set(&s->name, name);
  349: 
  350: 	return i;
  351: }
  352: 
  353: /* Map a parameter's string representation to something we can use.
  354:  * Returns False if the parameter string is not recognised, else TRUE. */
  355: static int map_parameter(char *parmname)
  356: {
  357: 	int iIndex;
  358: 
  359: 	if (*parmname == '-')
  360: 		return -1;
  361: 
  362: 	for (iIndex = 0; parm_table[iIndex].label; iIndex++) {
  363: 		if (strwiEQ(parm_table[iIndex].label, parmname))
  364: 			return iIndex;
  365: 	}
  366: 
  367: 	rprintf(FLOG, "Unknown Parameter encountered: \"%s\"\n", parmname);
  368: 	return -1;
  369: }
  370: 
  371: /* Set a boolean variable from the text value stored in the passed string.
  372:  * Returns True in success, False if the passed string does not correctly
  373:  * represent a boolean. */
  374: static BOOL set_boolean(BOOL *pb, char *parmvalue, int allow_unset)
  375: {
  376: 	if (strwiEQ(parmvalue, "yes") || strwiEQ(parmvalue, "true") || strwiEQ(parmvalue, "1"))
  377: 		*pb = True;
  378: 	else if (strwiEQ(parmvalue, "no") || strwiEQ(parmvalue, "false") || strwiEQ(parmvalue, "0"))
  379: 		*pb = False;
  380: 	else if (allow_unset && (strwiEQ(parmvalue, "unset") || strwiEQ(parmvalue, "-1")))
  381: 		*pb = Unset;
  382: 	else {
  383: 		rprintf(FLOG, "Badly formed boolean in configuration file: \"%s\".\n", parmvalue);
  384: 		return False;
  385: 	}
  386: 	return True;
  387: }
  388: 
  389: /* Process a parameter. */
  390: static BOOL do_parameter(char *parmname, char *parmvalue)
  391: {
  392: 	int parmnum, i;
  393: 	void *parm_ptr; /* where we are going to store the result */
  394: 	void *def_ptr;
  395: 	char *cp;
  396: 
  397: 	parmnum = map_parameter(parmname);
  398: 
  399: 	if (parmnum < 0) {
  400: 		rprintf(FLOG, "IGNORING unknown parameter \"%s\"\n", parmname);
  401: 		return True;
  402: 	}
  403: 
  404: 	def_ptr = parm_table[parmnum].ptr;
  405: 
  406: 	if (bInGlobalSection)
  407: 		parm_ptr = def_ptr;
  408: 	else {
  409: 		if (parm_table[parmnum].class == P_GLOBAL) {
  410: 			rprintf(FLOG, "Global parameter %s found in module section!\n", parmname);
  411: 			return True;
  412: 		}
  413: 		parm_ptr = SECTION_PTR(&iSECTION(iSectionIndex), def_ptr);
  414: 	}
  415: 
  416: 	/* now switch on the type of variable it is */
  417: 	switch (parm_table[parmnum].type) {
  418: 	case P_PATH:
  419: 	case P_STRING:
  420: 		/* delay expansion of %VAR% strings */
  421: 		break;
  422: 	default:
  423: 		/* expand any %VAR% strings now */
  424: 		parmvalue = expand_vars(parmvalue);
  425: 		break;
  426: 	}
  427: 
  428: 	switch (parm_table[parmnum].type) {
  429: 	case P_BOOL:
  430: 		set_boolean(parm_ptr, parmvalue, False);
  431: 		break;
  432: 
  433: 	case P_BOOL3:
  434: 		set_boolean(parm_ptr, parmvalue, True);
  435: 		break;
  436: 
  437: 	case P_BOOLREV:
  438: 		set_boolean(parm_ptr, parmvalue, False);
  439: 		*(BOOL *)parm_ptr = ! *(BOOL *)parm_ptr;
  440: 		break;
  441: 
  442: 	case P_INTEGER:
  443: 		*(int *)parm_ptr = atoi(parmvalue);
  444: 		break;
  445: 
  446: 	case P_CHAR:
  447: 		*(char *)parm_ptr = *parmvalue;
  448: 		break;
  449: 
  450: 	case P_OCTAL:
  451: 		sscanf(parmvalue, "%o", (int *)parm_ptr);
  452: 		break;
  453: 
  454: 	case P_PATH:
  455: 		string_set(parm_ptr, parmvalue);
  456: 		if ((cp = *(char**)parm_ptr) != NULL) {
  457: 			int len = strlen(cp);
  458: 			while (len > 1 && cp[len-1] == '/') len--;
  459: 			cp[len] = '\0';
  460: 		}
  461: 		break;
  462: 
  463: 	case P_STRING:
  464: 		string_set(parm_ptr, parmvalue);
  465: 		break;
  466: 
  467: 	case P_ENUM:
  468: 		for (i=0; parm_table[parmnum].enum_list[i].name; i++) {
  469: 			if (strequal(parmvalue, parm_table[parmnum].enum_list[i].name)) {
  470: 				*(int *)parm_ptr = parm_table[parmnum].enum_list[i].value;
  471: 				break;
  472: 			}
  473: 		}
  474: 		if (!parm_table[parmnum].enum_list[i].name) {
  475: 			if (atoi(parmvalue) > 0)
  476: 				*(int *)parm_ptr = atoi(parmvalue);
  477: 		}
  478: 		break;
  479: 	}
  480: 
  481: 	return True;
  482: }
  483: 
  484: /* Process a new section (rsync module).
  485:  * Returns True on success, False on failure. */
  486: static BOOL do_section(char *sectionname)
  487: {
  488: 	BOOL isglobal;
  489: 
  490: 	if (*sectionname == ']') { /* A special push/pop/reset directive from params.c */
  491: 		bInGlobalSection = 1;
  492: 		if (strcmp(sectionname+1, "push") == 0) {
  493: 			all_vars *vp = EXPAND_ITEM_LIST(&Vars_stack, all_vars, 2);
  494: 			memcpy(vp, &Vars, sizeof Vars);
  495: 		} else if (strcmp(sectionname+1, "pop") == 0
  496: 		 || strcmp(sectionname+1, "reset") == 0) {
  497: 			all_vars *vp = ((all_vars*)Vars_stack.items) + Vars_stack.count - 1;
  498: 			if (!Vars_stack.count)
  499: 				return False;
  500: 			memcpy(&Vars, vp, sizeof Vars);
  501: 			if (sectionname[1] == 'p')
  502: 				Vars_stack.count--;
  503: 		} else
  504: 			return False;
  505: 		return True;
  506: 	}
  507: 
  508: 	isglobal = strwiEQ(sectionname, GLOBAL_NAME);
  509: 
  510: 	/* At the end of the global section, add any --dparam items. */
  511: 	if (bInGlobalSection && !isglobal) {
  512: 		if (!section_list.count)
  513: 			set_dparams(0);
  514: 	}
  515: 
  516: 	/* if we've just struck a global section, note the fact. */
  517: 	bInGlobalSection = isglobal;
  518: 
  519: 	/* check for multiple global sections */
  520: 	if (bInGlobalSection)
  521: 		return True;
  522: 
  523: #if 0
  524: 	/* If we have a current section, tidy it up before moving on. */
  525: 	if (iSectionIndex >= 0) {
  526: 		/* Add any tidy work as needed ... */
  527: 		if (problem)
  528: 			return False;
  529: 	}
  530: #endif
  531: 
  532: 	if (strchr(sectionname, '/') != NULL) {
  533: 		rprintf(FLOG, "Warning: invalid section name in configuration file: %s\n", sectionname);
  534: 		return False;
  535: 	}
  536: 
  537: 	if ((iSectionIndex = add_a_section(sectionname)) < 0) {
  538: 		rprintf(FLOG, "Failed to add a new module\n");
  539: 		bInGlobalSection = True;
  540: 		return False;
  541: 	}
  542: 
  543: 	return True;
  544: }
  545: 
  546: /* Load the modules from the config file. Return True on success,
  547:  * False on failure. */
  548: int lp_load(char *pszFname, int globals_only)
  549: {
  550: 	bInGlobalSection = True;
  551: 
  552: 	reset_daemon_vars();
  553: 
  554: 	/* We get sections first, so have to start 'behind' to make up. */
  555: 	iSectionIndex = -1;
  556: 	return pm_process(pszFname, globals_only ? NULL : do_section, do_parameter);
  557: }
  558: 
  559: BOOL set_dparams(int syntax_check_only)
  560: {
  561: 	char *equal, *val, **params = dparam_list.items;
  562: 	unsigned j;
  563: 
  564: 	for (j = 0; j < dparam_list.count; j++) {
  565: 		equal = strchr(params[j], '='); /* options.c verified this */
  566: 		*equal = '\0';
  567: 		if (syntax_check_only) {
  568: 			if (map_parameter(params[j]) < 0) {
  569: 				rprintf(FERROR, "Unknown parameter \"%s\"\n", params[j]);
  570: 				*equal = '=';
  571: 				return False;
  572: 			}
  573: 		} else {
  574: 			for (val = equal+1; isSpace(val); val++) {}
  575: 			do_parameter(params[j], val);
  576: 		}
  577: 		*equal = '=';
  578: 	}
  579: 
  580: 	return True;
  581: }
  582: 
  583: /* Return the max number of modules (sections). */
  584: int lp_num_modules(void)
  585: {
  586: 	return section_list.count;
  587: }
  588: 
  589: /* Return the number of the module with the given name, or -1 if it doesn't
  590:  * exist. Note that this is a DIFFERENT ANIMAL from the internal function
  591:  * getsectionbyname()! This works ONLY if all sections have been loaded,
  592:  * and does not copy the found section. */
  593: int lp_number(char *name)
  594: {
  595: 	int i;
  596: 
  597: 	for (i = section_list.count - 1; i >= 0; i--) {
  598: 		if (strcmp(lp_name(i), name) == 0)
  599: 			break;
  600: 	}
  601: 
  602: 	return i;
  603: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>