#endif
#define DEFAULT_DONT_COMPRESS "*.gz *.zip *.z *.rpm *.deb *.iso *.bz2" \
- " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg"
+ " *.t[gb]z *.7z *.mp[34] *.mov *.avi *.ogg *.jpg *.jpeg" \
+ " *.lzo *.rzip *.lzma *.rar *.ace *.gpg"
/* the following are used by loadparm for option lists */
typedef enum {
#define LP_SNUM_OK(i) ((i) >= 0 && (i) < (int)section_list.count)
#define SECTION_PTR(s, p) (((char*)(s)) + (ptrdiff_t)(((char*)(p))-(char*)&Vars.l))
-/*
- * This structure describes global (ie., server-wide) parameters.
- */
+/* This structure describes global (ie., server-wide) parameters. */
typedef struct {
char *bind_address;
char *motd_file;
int rsync_port;
} global_vars;
-/*
- * This structure describes a single section. Their order must match the
+/* This structure describes a single section. Their order must match the
* initializers below, which you can accomplish by keeping each sub-section
* sorted. (e.g. in vim, just visually select each subsection and use !sort.)
- */
+ * NOTE: the char* variables MUST all remain at the start of the stuct! */
typedef struct {
char *auth_users;
char *charset;
char *secrets_file;
char *temp_dir;
char *uid;
+/* NOTE: update this macro if the last char* variable changes! */
+#define LOCAL_STRING_COUNT() (offsetof(local_vars, uid) / sizeof (char*) + 1)
int max_connections;
int max_verbosity;
/* exclude; */ NULL,
/* exclude_from; */ NULL,
/* filter; */ NULL,
- /* gid; */ NOBODY_GROUP,
+ /* gid; */ NULL,
/* hosts_allow; */ NULL,
/* hosts_deny; */ NULL,
/* include; */ NULL,
/* refuse_options; */ NULL,
/* secrets_file; */ NULL,
/* temp_dir; */ NULL,
- /* uid; */ NOBODY_USER,
+ /* uid; */ NULL,
/* max_connections; */ 0,
/* max_verbosity; */ 1,
memcpy(&Vars, &Defaults, sizeof Vars);
}
+/* Expand %VAR% references. Any unknown vars or unrecognized
+ * syntax leaves the raw chars unchanged. */
+static char *expand_vars(char *str)
+{
+ char *buf, *t, *f;
+ int bufsize;
+
+ if (strchr(str, '%') == NULL)
+ return str;
+
+ bufsize = strlen(str) + 2048;
+ if ((buf = new_array(char, bufsize+1)) == NULL) /* +1 for trailing '\0' */
+ out_of_memory("expand_vars");
+
+ for (t = buf, f = str; bufsize && *f; ) {
+ if (*f == '%' && *++f != '%') {
+ char *percent = strchr(f, '%');
+ if (percent) {
+ char *val;
+ *percent = '\0';
+ val = getenv(f);
+ *percent = '%';
+ if (val) {
+ int len = strlcpy(t, val, bufsize+1);
+ if (len > bufsize)
+ break;
+ bufsize -= len;
+ t += len;
+ f = percent + 1;
+ continue;
+ }
+ }
+ f--;
+ }
+ *t++ = *f++;
+ bufsize--;
+ }
+ *t = '\0';
+
+ if (*f) {
+ rprintf(FLOG, "Overflowed buf in expand_vars() trying to expand: %s\n", str);
+ exit_cleanup(RERR_MALLOC);
+ }
+
+ if (bufsize && (buf = realloc(buf, t - buf + 1)) == NULL)
+ out_of_memory("expand_vars");
+
+ return buf;
+}
+
/* In this section all the functions that are used to access the
* parameters from the rest of the program are defined. */
#define FN_GLOBAL_STRING(fn_name, ptr) \
- char *fn_name(void) {return *(char **)(ptr) ? *(char **)(ptr) : "";}
+ char *fn_name(void) {return expand_vars(*(char **)(ptr) ? *(char **)(ptr) : "");}
#define FN_GLOBAL_BOOL(fn_name, ptr) \
BOOL fn_name(void) {return *(BOOL *)(ptr);}
#define FN_GLOBAL_CHAR(fn_name, ptr) \
int fn_name(void) {return *(int *)(ptr);}
#define FN_LOCAL_STRING(fn_name, val) \
- char *fn_name(int i) {return LP_SNUM_OK(i) && iSECTION(i).val? iSECTION(i).val : (Vars.l.val? Vars.l.val : "");}
+ char *fn_name(int i) {return expand_vars(LP_SNUM_OK(i) && iSECTION(i).val ? iSECTION(i).val : Vars.l.val ? Vars.l.val : "");}
#define FN_LOCAL_BOOL(fn_name, val) \
BOOL fn_name(int i) {return LP_SNUM_OK(i)? iSECTION(i).val : Vars.l.val;}
#define FN_LOCAL_CHAR(fn_name, val) \
FN_LOCAL_BOOL(lp_use_chroot, use_chroot)
FN_LOCAL_BOOL(lp_write_only, write_only)
-/* Assign a copy of v to *s. Handles NULL strings. *v must
- * be initialized when this is called, either to NULL or a malloc'd
- * string.
- *
- * FIXME There is a small leak here in that sometimes the existing
- * value will be dynamically allocated, and the old copy is lost.
- * However, we can't always deallocate the old value, because the
- * initial values in Defaults.l are static strings. It would be nice
- * to have either all-strdup'd values, or to never need to free
- * memory. */
-static void string_set(char **s, const char *v)
+/* Assign a copy of v to *s. Handles NULL strings. We don't worry
+ * about overwriting a malloc'd string because the long-running
+ * (port-listening) daemon only loads the config file once, and the
+ * per-job (forked or xinitd-ran) daemon only re-reads the file at
+ * the start, so any lost memory is inconsequential. */
+static inline void string_set(char **s, const char *v)
{
- if (!v) {
+ if (!v)
*s = NULL;
- return;
- }
- if (!(*s = strdup(v)))
+ else if (!(*s = strdup(v)))
out_of_memory("string_set");
}
-/* Copy the local_vars, duplicating any strings in the source. */
+/* Copy the local_vars, strdup'ing any strings. NOTE: this depends on
+ * the structure starting with a contiguous list of the char* variables,
+ * and having an accurate count in the LOCAL_STRING_COUNT() macro. */
static void copy_section(local_vars *psectionDest, local_vars *psectionSource)
{
- int i;
-
- for (i = 0; parm_table[i].label; i++) {
- if (parm_table[i].ptr && parm_table[i].class == P_LOCAL) {
- void *def_ptr = parm_table[i].ptr;
- void *src_ptr = SECTION_PTR(psectionSource, def_ptr);
- void *dest_ptr = SECTION_PTR(psectionDest, def_ptr);
+ int count = LOCAL_STRING_COUNT();
+ char **strings = (char**)psectionDest;
- switch (parm_table[i].type) {
- case P_BOOL:
- case P_BOOLREV:
- *(BOOL *)dest_ptr = *(BOOL *)src_ptr;
- break;
-
- case P_INTEGER:
- case P_ENUM:
- case P_OCTAL:
- *(int *)dest_ptr = *(int *)src_ptr;
- break;
-
- case P_CHAR:
- *(char *)dest_ptr = *(char *)src_ptr;
- break;
-
- case P_PATH:
- case P_STRING:
- string_set(dest_ptr, *(char **)src_ptr);
- break;
-
- default:
- break;
- }
- }
+ memcpy(psectionDest, psectionSource, sizeof psectionDest[0]);
+ while (count--) {
+ if (strings[count] && !(strings[count] = strdup(strings[count])))
+ out_of_memory("copy_section");
}
}
}
/* now switch on the type of variable it is */
+ switch (parm_table[parmnum].type) {
+ case P_PATH:
+ case P_STRING:
+ /* delay expansion of vars */
+ break;
+ default:
+ /* expand any %VARS% now */
+ parmvalue = expand_vars(parmvalue);
+ break;
+ }
+
switch (parm_table[parmnum].type) {
case P_BOOL:
set_boolean(parm_ptr, parmvalue);