- crt-base
- cpu-map
- daemon
+ - default-path
- description
- deviceatlas-json-file
- deviceatlas-log-level
disabled by the command line "-db" argument. This option is ignored in
systemd mode.
+default-path { current | config | parent | origin <path> }
+ By default haproxy loads all files designated by a relative path from the
+ location the process is started in. In some circumstances it might be
+ desirable to force all relative paths to start from a different location
+ just as if the process was started from such locations. This is what this
+ directive is made for. Technically it will perform a temporary chdir() to
+ the designated location while processing each configuration file, and will
+ return to the original directory after processing each file. It takes an
+ argument indicating the policy to use when loading files whose path does
+ not start with a slash ('/'):
+ - "current" indicates that all relative files are to be loaded from the
+ directory the process is started in ; this is the default.
+
+ - "config" indicates that all relative files should be loaded from the
+ directory containing the configuration file. More specifically, if the
+ configuration file contains a slash ('/'), the longest part up to the
+ last slash is used as the directory to change to, otherwise the current
+ directory is used. This mode is convenient to bundle maps, errorfiles,
+ certificates and Lua scripts together as relocatable packages. When
+ multiple configuration files are loaded, the directory is updated for
+ each of them.
+
+ - "parent" indicates that all relative files should be loaded from the
+ parent of the directory containing the configuration file. More
+ specifically, if the configuration file contains a slash ('/'), ".."
+ is appended to the longest part up to the last slash is used as the
+ directory to change to, otherwise the directory is "..". This mode is
+ convenient to bundle maps, errorfiles, certificates and Lua scripts
+ together as relocatable packages, but where each part is located in a
+ different subdirectory (e.g. "config/", "certs/", "maps/", ...).
+
+ - "origin" indicates that all relative files should be loaded from the
+ designated (mandatory) path. This may be used to ease management of
+ different haproxy instances running in parallel on a system, where each
+ instance uses a different prefix but where the rest of the sections are
+ made easily relocatable.
+
+ Each "default-path" directive instantly replaces any previous one and will
+ possibly result in switching to a different directory. While this should
+ always result in the desired behavior, it is really not a good practice to
+ use multiple default-path directives, and if used, the policy ought to remain
+ consistent across all configuration files.
+
+ Warning: some configuration elements such as maps or certificates are
+ uniquely identified by their configured path. By using a relocatable layout,
+ it becomes possible for several of them to end up with the same unique name,
+ making it difficult to update them at run time, especially when multiple
+ configuration files are loaded from different directories. It is essential to
+ observe a strict collision-free file naming scheme before adopting relative
+ paths. A robust approach could consist in prefixing all files names with
+ their respective site name, or in doing so at the directory level.
+
deviceatlas-json-file <path>
Sets the path of the DeviceAtlas JSON data file to be loaded by the API.
The path must be a valid JSON data file and accessible by HAProxy process.
int cfg_maxconn = 0; /* # of simultaneous connections, (-n) */
char *cfg_scope = NULL; /* the current scope during the configuration parsing */
+/* how to handle default paths */
+static enum default_path_mode {
+ DEFAULT_PATH_CURRENT = 0, /* "current": paths are relative to CWD (this is the default) */
+ DEFAULT_PATH_CONFIG, /* "config": paths are relative to config file */
+ DEFAULT_PATH_PARENT, /* "parent": paths are relative to config file's ".." */
+ DEFAULT_PATH_ORIGIN, /* "origin": paths are relative to default_path_origin */
+} default_path_mode;
+
+static char initial_cwd[PATH_MAX];
+static char current_cwd[PATH_MAX];
+
/* List head of all known configuration keywords */
struct cfg_kw_list cfg_keywords = {
.list = LIST_HEAD_INIT(cfg_keywords.list)
}
}
+/* apply the current default_path setting for config file <file>, and
+ * optionally replace the current path to <origin> if not NULL while the
+ * default-path mode is set to "origin". Errors are returned into an
+ * allocated string passed to <err> if it's not NULL. Returns 0 on failure
+ * or non-zero on success.
+ */
+static int cfg_apply_default_path(const char *file, const char *origin, char **err)
+{
+ const char *beg, *end;
+
+ /* make path start at <beg> and end before <end>, and switch it to ""
+ * if no slash was passed.
+ */
+ beg = file;
+ end = strrchr(beg, '/');
+ if (!end)
+ end = beg;
+
+ if (!*initial_cwd) {
+ if (getcwd(initial_cwd, sizeof(initial_cwd)) == NULL) {
+ if (err)
+ memprintf(err, "Impossible to retrieve startup directory name: %s", strerror(errno));
+ return 0;
+ }
+ }
+ else if (chdir(initial_cwd) == -1) {
+ if (err)
+ memprintf(err, "Impossible to get back to initial directory '%s': %s", initial_cwd, strerror(errno));
+ return 0;
+ }
+
+ /* OK now we're (back) to initial_cwd */
+
+ switch (default_path_mode) {
+ case DEFAULT_PATH_CURRENT:
+ /* current_cwd never set, nothing to do */
+ return 1;
+
+ case DEFAULT_PATH_ORIGIN:
+ /* current_cwd set in the config */
+ if (origin &&
+ snprintf(current_cwd, sizeof(current_cwd), "%s", origin) > sizeof(current_cwd)) {
+ if (err)
+ memprintf(err, "Absolute path too long: '%s'", origin);
+ return 0;
+ }
+ break;
+
+ case DEFAULT_PATH_CONFIG:
+ if (end - beg >= sizeof(current_cwd)) {
+ if (err)
+ memprintf(err, "Config file path too long, cannot use for relative paths: '%s'", file);
+ return 0;
+ }
+ memcpy(current_cwd, beg, end - beg);
+ current_cwd[end - beg] = 0;
+ break;
+
+ case DEFAULT_PATH_PARENT:
+ if (end - beg + 3 >= sizeof(current_cwd)) {
+ if (err)
+ memprintf(err, "Config file path too long, cannot use for relative paths: '%s'", file);
+ return 0;
+ }
+ memcpy(current_cwd, beg, end - beg);
+ if (end > beg)
+ memcpy(current_cwd + (end - beg), "/..\0", 4);
+ else
+ memcpy(current_cwd + (end - beg), "..\0", 3);
+ break;
+ }
+
+ if (*current_cwd && chdir(current_cwd) == -1) {
+ if (err)
+ memprintf(err, "Impossible to get back to directory '%s': %s", initial_cwd, strerror(errno));
+ return 0;
+ }
+
+ return 1;
+}
+
+/* parses a global "default-path" directive. */
+static int cfg_parse_global_def_path(char **args, int section_type, struct proxy *curpx,
+ const struct proxy *defpx, const char *file, int line,
+ char **err)
+{
+ int ret = -1;
+
+ /* "current", "config", "parent", "origin <path>" */
+
+ if (strcmp(args[1], "current") == 0)
+ default_path_mode = DEFAULT_PATH_CURRENT;
+ else if (strcmp(args[1], "config") == 0)
+ default_path_mode = DEFAULT_PATH_CONFIG;
+ else if (strcmp(args[1], "parent") == 0)
+ default_path_mode = DEFAULT_PATH_PARENT;
+ else if (strcmp(args[1], "origin") == 0)
+ default_path_mode = DEFAULT_PATH_ORIGIN;
+ else {
+ memprintf(err, "%s default-path mode '%s' for '%s', supported modes include 'current', 'config', 'parent', and 'origin'.", *args[1] ? "unsupported" : "missing", args[1], args[0]);
+ goto end;
+ }
+
+ if (default_path_mode == DEFAULT_PATH_ORIGIN) {
+ if (!*args[2]) {
+ memprintf(err, "'%s %s' expects a directory as an argument.", args[0], args[1]);
+ goto end;
+ }
+ if (!cfg_apply_default_path(file, args[2], err)) {
+ memprintf(err, "couldn't set '%s' to origin '%s': %s.", args[0], args[2], *err);
+ goto end;
+ }
+ }
+ else if (!cfg_apply_default_path(file, NULL, err)) {
+ memprintf(err, "couldn't set '%s' to '%s': %s.", args[0], args[1], *err);
+ goto end;
+ }
+
+ /* note that once applied, the path is immediately updated */
+
+ ret = 0;
+ end:
+ return ret;
+}
+
+
/*
* This function reads and parses the configuration file given in the argument.
* Returns the error code, 0 if OK, -1 if the config file couldn't be opened,
int nested_cond_lvl = 0;
enum nested_cond_state nested_conds[MAXNESTEDCONDS];
int non_global_section_parsed = 0;
+ char *errmsg = NULL;
if ((thisline = malloc(sizeof(*thisline) * linesize)) == NULL) {
ha_alert("Out of memory trying to allocate a buffer for a configuration line.\n");
goto err;
}
+ /* change to the new dir if required */
+ if (!cfg_apply_default_path(file, NULL, &errmsg)) {
+ ha_alert("parsing [%s:%d]: failed to apply default-path: %s.\n", file, linenum, errmsg);
+ free(errmsg);
+ err_code = -1;
+ goto err;
+ }
+
next_line:
while (fgets(thisline + readbytes, linesize - readbytes, f) != NULL) {
int arg, kwm = KWM_STD;
ha_alert("parsing [%s:%d]: non-terminated '.if' block.\n", file, linenum);
err_code |= ERR_ALERT | ERR_FATAL | ERR_ABORT;
}
+
+ if (*initial_cwd && chdir(initial_cwd) == -1) {
+ ha_alert("Impossible to get back to initial directory '%s' : %s\n", initial_cwd, strerror(errno));
+ err_code |= ERR_ALERT | ERR_FATAL;
+ }
+
err:
ha_free(&cfg_scope);
cursection = NULL;
REGISTER_CONFIG_SECTION("mailers", cfg_parse_mailers, NULL);
REGISTER_CONFIG_SECTION("namespace_list", cfg_parse_netns, NULL);
+static struct cfg_kw_list cfg_kws = {{ },{
+ { CFG_GLOBAL, "default-path", cfg_parse_global_def_path },
+ { /* END */ }
+}};
+
+INITCALL1(STG_REGISTER, cfg_register_keywords, &cfg_kws);
+
/*
* Local variables:
* c-indent-level: 8