mirror of
http://git.haproxy.org/git/haproxy.git/
synced 2025-02-16 10:36:55 +00:00
MINOR: tools: add helpers to backup/clean/restore env
'setenv', 'presetenv', 'unsetenv', 'resetenv' keywords in configuration could modify the process runtime environment. In case of master-worker mode this creates a problem, as the configuration is read only once before the forking a worker and then the master process does the reexec without reading any config files, just to free the memory. So, during the reload a new worker process will be created, but it will inherited the previous unchanged environment from the master in wait mode, thus it won't benefit the changes in configuration, related to '*env' keywords. This may cause unexpected behavior or some parser errors in master-worker mode. So, let's add a helper to backup all process env variables just before it will read its configuration. And let's also add helpers to clean up the current runtime environment and to restore it to its initial state (as it was before parsing the config).
This commit is contained in:
parent
960d68a5af
commit
1811d2a6ba
@ -1220,4 +1220,9 @@ void vma_set_name_id(void *addr, size_t size, const char *type, const char *name
|
||||
/* cfgparse helpers */
|
||||
char *fgets_from_mem(char* buf, int size, const char **position, const char *end);
|
||||
|
||||
/* helpers to backup/clean/restore process env */
|
||||
int backup_env(void);
|
||||
int clean_env(void);
|
||||
int restore_env(void);
|
||||
|
||||
#endif /* _HAPROXY_TOOLS_H */
|
||||
|
121
src/tools.c
121
src/tools.c
@ -6706,6 +6706,127 @@ char *fgets_from_mem(char* buf, int size, const char **position, const char *end
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Does a backup of the process environment variables. Returns 0 on success and
|
||||
* -1 on failure, which can happen only due to the lack of memory.
|
||||
*/
|
||||
int backup_env(void)
|
||||
{
|
||||
char **env = environ;
|
||||
char **tmp;
|
||||
|
||||
/* get size of **environ */
|
||||
while (*env++)
|
||||
;
|
||||
|
||||
init_env = malloc((env - environ) * sizeof(*env));
|
||||
if (init_env == NULL) {
|
||||
ha_alert("Cannot allocate memory to backup env variables.\n");
|
||||
return -1;
|
||||
}
|
||||
tmp = init_env;
|
||||
for (env = environ; *env; env++) {
|
||||
*tmp = strdup(*env);
|
||||
if (*tmp == NULL) {
|
||||
ha_alert("Cannot allocate memory to backup env variable '%s'.\n",
|
||||
*env);
|
||||
return -1;
|
||||
}
|
||||
tmp++;
|
||||
}
|
||||
/* last entry */
|
||||
*tmp = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Unsets all variables presented in **environ. Returns 0 on success and -1 on
|
||||
* failure, when the process has run out of memory. Emits warnings and continues
|
||||
* if unsetenv() fails (it fails only with EINVAL) or if the parsed string
|
||||
* doesn't contain "=" (the latter is mandatory format for strings kept in
|
||||
* **environ). This allows to terminate the process at the startup stage, if it
|
||||
* was launched in zero-warning mode and there are some problems with
|
||||
* environment.
|
||||
*/
|
||||
int clean_env(void)
|
||||
{
|
||||
char **env = environ;
|
||||
char *name, *pos;
|
||||
size_t name_len;
|
||||
|
||||
while (*env) {
|
||||
pos = strchr(*env, '=');
|
||||
if (pos)
|
||||
name_len = pos - *env;
|
||||
else {
|
||||
ha_warning("Unsupported env variable format '%s' "
|
||||
"(doesn't contain '='), won't be unset.\n",
|
||||
*env);
|
||||
continue;
|
||||
}
|
||||
name = my_strndup(*env, name_len);
|
||||
if (name == NULL) {
|
||||
ha_alert("Cannot allocate memory to parse env variable: '%s'.\n",
|
||||
*env);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (unsetenv(name) != 0)
|
||||
ha_warning("unsetenv() fails for '%s': %s.\n",
|
||||
name, strerror(errno));
|
||||
free(name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Restores **environ from backup created by backup_env(). Must be always
|
||||
* preceded by clean_env() in order to properly restore the process environment.
|
||||
* global init_env ptr array must be freed by the upper layers.
|
||||
* Returns 0 on sucess and -1 in case if the process has run out of memory. If
|
||||
* setenv() fails with EINVAL or the parsed string doesn't contain '=' (the
|
||||
* latter is mandatory format for strings kept in **environ), emits warning and
|
||||
* continues. This allows to terminate the process at the startup stage, if it
|
||||
* was launched in zero-warning mode and there are some problems with
|
||||
* environment.
|
||||
*/
|
||||
int restore_env(void)
|
||||
{
|
||||
char **env = init_env;
|
||||
char *pos;
|
||||
char *value;
|
||||
|
||||
BUG_ON(!init_env, "Triggered in restore_env(): must be preceded by "
|
||||
"backup_env(), which allocates init_env.\n");
|
||||
|
||||
while (*env) {
|
||||
pos = strchr(*env, '=');
|
||||
if (!pos) {
|
||||
ha_warning("Unsupported env variable format '%s' "
|
||||
"(doesn't contain '='), won't be restored.\n",
|
||||
*env);
|
||||
env++;
|
||||
continue;
|
||||
}
|
||||
/* replace '=' with /0 to split on 'NAME' and 'VALUE' tokens */
|
||||
*pos = '\0';
|
||||
pos++;
|
||||
value = pos;
|
||||
if (setenv(*env, value, 1) != 0) {
|
||||
if (errno == EINVAL)
|
||||
ha_warning("setenv() fails for '%s'='%s': %s.\n",
|
||||
*env, value, strerror(errno));
|
||||
else {
|
||||
ha_alert("Cannot allocate memory to set env variable: '%s'.\n",
|
||||
*env);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
env++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 8
|
||||
|
Loading…
Reference in New Issue
Block a user