libpromises: future syntax support, draft PoC implementation

When deploying the same masterfiles to a herd with mixed CFEngine
versions, these masterfiles shall validate against all "cf-promises".

But this would stop us from using features not found in earlier vers.

Promise bundles can overcome that, because they can be conditionally
included, depending on the CFEngine version

Control bodies cannot. They would have to use only the classic keywords.

With this patch, we can explicitly define a list of keywords that will
pass as valid syntax and be skipped in parsers. libpromises will first
lookup the body/bundle/constraint in the supported ones, and then fall
over to the "future syntax" list.

Future syntax is defined in control body, because this is the first to
ever get parsed. It is a stringlist, because that is the only possible
collection item in that context. These future-syntax strings are free,
meaning that they could have any form (so far, one dot is mandatory).
That is, future syntax is designed to be future-compatible itself, by
allowing strings that the parser will not use at the moment.

So far, only body constraints are covered.

Example input file:

body common control {
    future_syntax => { "body.common.control.bwlimitw",
                    "body.agent.control.foo_bar"};
    bwlimitw => "4M";
}

body agent control {
    foo_bar => "bar";
}
libpromises: propagate "future" elements to validation vs. classes

"future" elements are declared early in control promises and will pass
the parser check.
But then, we want to verify that they are class-limited NOT to run in
our version.
That is, a future element mentioned in our promise files is OK,
but a future element used in promises we run is an error.

Example:
body common control {
    future_syntax => { "body.agent.control.foo_1",
                       "body.agent.control.foo_2"};
}

body agent control {
 cfengine_4_0::
   foo_1 => {}; # OK, we are not 4.0 yet

 cfengine_3_6::
   foo_2 => "";  # error, this class is active and "touches" this elem.
}
libpromises: some constraints may not exist at all

Not all constraints are legal or future.
libpromises: more future syntax checks, for bodies, promises, bundles

We can now define new promise types and new bundle or body types
Refine debug log output in hopes of clues to why test fails on Aches.

(cherry picked from commit 349c77433f71489a9dc55c0f8ce46bdca329aa4e)
Add some debug output to laterthan.cf

... so we have some clue as to what's failing.

(cherry picked from commit 2483a513a056c11e65e5724ea90ba6f992dddd6a)
Advance ap if socket(2) fails

In the case where socket(2) fails in SocketConnect, ap will advance,
causing an infinite loop.

https://dev.cfengine.com/issues/6560
(cherry picked from commit d119322e0b6ad5061670839dffb954b4708331ef)
Redmine #6558: Fix LookupAccountName error message on Windows.

Don't report error for user name "root" on Windows, since it is not
expected to exist.

(cherry picked from commit fb72b05d47b8f5d08b8ac2c3c1b2ee8d4157062b)
Change: Fix laterthan test

The or() function returns a string, not a boolean.
https://docs.cfengine.com/latest/reference-functions-or.html

(cherry picked from commit 95e31650aa324b94287ffcc2ae5234f41c885f62)
Document change to input validation for integer ranges
Building 3.6.2 packages
Add le32toh macro & friends to platform that lack it, like Windows.

Macros are preferable, because Linux internally uses macros, and
attempting to use a function messes with that.

(cherry picked from commit 3f2510803e6751893e5b4be982d6e8eee42894c3)
Wrap HACKING.md where lines exceed 78 columns.

(cherry picked from commit b10f1eba3dbfe0014c192c98fff8733e2346b658)
HACKING.md: add do-while exception, and rewrap some text around it.

(cherry picked from commit 83b579d51824b06778a6495f3b62f96d71d5e13a)
Fixing LocalExec in cf-execd-runner.c

The premature return was only doing most of the tidy-up needed, so
make it a break instead and add a flag for whether the command
actually completed; use that to condition the one Log() after the loop
that wasn't appropriate to run after this failure.  The alternate
branch to that return's if was in fact the only path out of the loop
for which the Log() was relevant, so made it set the flag for that
Log().  Made the Log() say something sensible as an alternative when
the work isn't complete.  Simplified the code to detect a non-blank
string.

Code skipping spaces at the start of a string could be simplified to
avoid the need for a bool flag to say whether we found anything else.

(cherry picked from commit 0f31fe051f0e8917938055296f497af687738e36)
Kill some stray apostrophes.

Some function names were formatted using '%s'' with two dangling
apostrophes; there should only be one before and one after !
Also: split a long line, purged dangling hspace, added braces demanded
by coding style.

(cherry picked from commit 2cd2a2d35ca96dbf6690b2688958f96ea098827c)
Leak-fixes and clean-up in FnCallPackagesMatching().

Move computation of regex outside the loop - no need to recompute the
same regex for every line of the CSV file ! - and pre-compile it so
that we can search using it more efficiently.  Localise all the
variables related to that at the same time.

Split up various long lines, notably when Log()ging failure to open
the inventory.

Move creation of some objects to where they're needed, to save the
need to tidy them away on failure in the interval.

Don't leak the allocated line when it doesn't match our expectations.

Restructure the for(;;) loop as a while with assignment in its
condition so as to move the failure-handling out of the loop and avoid
duplication of clean-up code.  Reviewed the error message on that
failure: it claimed fread() was involved, which is a lie, so re-worked
it.

(cherry picked from commit 3fc8d68041c9cae1cebb2e5438a3a040ded3e5d4)
Petty leak-fix: close socket on which we failed to listen.

About to exit with error anyway, so not crucial.

(cherry picked from commit a14023622adec2a250c1863708c62f4c295a0099)
Tidy up in SocketConnect().

PR #1952 added an ap = ap->ai_next in an if branch that duplicated one
in its else; replacing these with one after the whole branch put the
loop in the form of a for() unrolled as a while, so I rolled it up as
a for().

If an iteration of the loop managed to create a socket but failed to
connect it, we were leaking it (unless it happened to be the last time
round the loop); the "on failure close the socket" was after the loop,
where it belonged inside.  Further, the Log()ging of that tried to use
GetErrorStr() when enough other functions had been called since the
error that the error string might easily be from something unrelated
to the connection failure.  So Log() before closing the socket in the
loop and don't try to include an error string with the final "none of
it worked" Log().

Tweaked a couple of other Log() messages.

(cherry picked from commit ca9d2fb252d84788baee872707fa52ad83caf7c9)
Fix a badly-thought-out loop.

The BSD compiler warned that i >= 0 is always true for a size_t i; the
loop conditioned on that could have spun for ever.  So turn it into a
while that terminates correctly and simplify what's left.

(cherry picked from commit cad04bf29138210cebee41bf4771bdc09df3fd29)