Closed cederlys closed 4 years ago
Note: setenv()
has an override parameter, but this function is not necessarily thread-safe. The best implementation would be to check **environmen whether the extra argument exists and replace that inside envp.
@Al2Klimov
Summary
Icinga 2 tries to enforce
LC_NUMERIC=C
inProcessSpawnImpl()
inlib/base/process.cpp
, but it fails ifLC_NUMERIC
is already present in the environment.LC_NUMERIC=C
is appended to the environment, without checking if it already exists. You might end up with twoLC_NUMERIC
variables. In my testing,getenv(3)
on Ubuntu 18.04 returns the first value it finds, so the override made by Icinga is ignored.Expected Behavior
Check commands should always see exactly one
LC_NUMERIC
environment variable, and it should be set toC
.Current Behavior
If
LC_NUMERIC
already exists in the environment when Icinga is started, check commands will see twoLC_NUMERIC
variables, and will typically not use the value that Icinga put into the environment.Possible Solution
Change the way the environment is built up, so that it never adds the same variable twice.
Note: this probably also affects environment variables set via extraEnvironment. They should override the inherited environment, but unless I misread the code the inherited environment will take precedence.
The easiest way to fix this would be to just reverse the order in which the environment is built up, so that
LC_NUMERIC
is set first, then the extraEnvironment, and finally the inherited environment. But the GNU C Library says:So I think a more advanced implementation is needed. Perhaps put all the values into an
std::map
so that the finalLC_NUMERIC
setting would override any pre-existing variable of that name?Steps to Reproduce (for bugs)
/usr/local/bin/adhoc
dua
to suite your environment):/tmp/adhoc.out
file. My file looks like this (I've removed a few irrelevant environment variables):As you can see,
LC_NUMERIC
is included twice, andgetenv("LC_NUMERIC")
picks the wrong one.Context
Background: I'm using the check_ntp_time plugin via the built-in ntp_time check-command. In my environment, LC_NUMERIC is set to sv_SE.utf-8. If I run the check_ntp_time plugin with that value, it predictably fails, since it parses the "-w 0.5" argument as 0 seconds, as you can see here:
Because of this issue, my
ntp_time
check is constantly in a warning state.Workaround: I could change the warning threshold to 1 and the critical threshold to 2, but I want to be notified long before the clock is that much out of sync.
Your Environment
icinga2 --version
):Copyright (c) 2012-2019 Icinga GmbH (https://icinga.com/) License GPLv2+: GNU GPL version 2 or later http://gnu.org/licenses/gpl2.html This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
System information: Platform: Ubuntu Platform version: 18.04.3 LTS (Bionic Beaver) Kernel: Linux Kernel version: 4.15.0-64-generic Architecture: x86_64
Build information: Compiler: GNU 8.3.0 Build host: runner-LTrJQZ9N-project-298-concurrent-0
Application information:
General paths: Config directory: /etc/icinga2 Data directory: /var/lib/icinga2 Log directory: /var/log/icinga2 Cache directory: /var/cache/icinga2 Spool directory: /var/spool/icinga2 Run directory: /run/icinga2
Old paths (deprecated): Installation root: /usr Sysconf directory: /etc Run directory (base): /run Local state directory: /var
Internal paths: Package data directory: /usr/share/icinga2 State path: /var/lib/icinga2/icinga2.state Modified attributes path: /var/lib/icinga2/modified-attributes.conf Objects path: /var/cache/icinga2/icinga2.debug Vars path: /var/cache/icinga2/icinga2.vars PID path: /run/icinga2/icinga2.pid
define _GNU_SOURCE
include
include
include
int main() { FILE *fp = fopen("/tmp/adhoc.out", "w"); char *e = environ; while (e) { char c = e; while (c) { if (c > 32 && c < 127 && c != '\') { fputc(c, fp); putchar(c); } else { fprintf(fp, "\x%02x", c); printf("\x%02x", c); } c++; } printf("\0\n"); fprintf(fp, "\0\n"); e++; } fprintf(fp, "And now the getenv result: %s\n", getenv("LC_NUMERIC")); fclose(fp); }