diff --git a/INSTALL b/INSTALL index 632a6cb6bf..52b2a8e118 100644 --- a/INSTALL +++ b/INSTALL @@ -157,10 +157,12 @@ sudo apk add alpine-sdk lmdb-dev openssl-dev bison flex-dev acl-dev pcre2-dev au Note that in order for process promises to work you must install the procps package for a "proper" ps command instead of busybox. -* Termux (2020-04-24) +* Termux (2025-10-10) -pkg install build-essential git autoconf automake bison flex liblmdb openssl pcre2 libacl libyaml -./autogen.sh --without-pam +pkg install build-essential git autoconf automake bison flex liblmdb openssl pcre2 libacl libyaml binutils librsync +# maybe binutils-is-llvm - Use llvm as binutils instead of binutils to get ld +LDFLAGS='-landroid-glob' ./autogen.sh --without-pam --prefix=$PREFIX --with-workdir=$PREFIX/var/lib/cfengine --without-systemd-service --without-selinux-policy +make && make install * OSX (2021-10-20) diff --git a/ci/build.sh b/ci/build.sh index 3bd306e6e8..3e47dfc761 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -5,7 +5,10 @@ set -ex thisdir="$(dirname "$0")" cd "$thisdir"/.. -source /etc/os-release +if [ -f /etc/os-release ]; then + source /etc/os-release +fi + CFLAGS="-Wall" if [ "$ID" != "alpine" ]; then CFLAGS="$CFLAGS -Werror" diff --git a/ci/configure.sh b/ci/configure.sh index dc66f9f7ed..e47d02b6e1 100755 --- a/ci/configure.sh +++ b/ci/configure.sh @@ -4,15 +4,24 @@ set -ex thisdir="$(dirname "$0")" cd "$thisdir"/.. -OPTS="--enable-debug" +OPTS="--config-cache --enable-debug" -source /etc/os-release -if [ "$ID" = "alpine" ]; then - OPTS="" # we don't want --enable-debug so that libpromises/dbm_test_api is not built due to lack of srand48_r() and friends on alpine linux libmusl +if [ -f /etc/os-release ]; then + source /etc/os-release + if [ "$ID" = "alpine" ]; then + OPTS="" # we don't want --enable-debug so that libpromises/dbm_test_api is not built due to lack of srand48_r() and friends on alpine linux libmusl + fi fi if [ -n "$TERMUX_VERSION" ] || [ "$ID" = "alpine" ]; then OPTS="$OPTS --without-pam" fi +if [ -n "$TERMUX_VERSION" ]; then + export LDFLAGS+=" -landroid-glob" + OPTS="$OPTS --prefix=$PREFIX\ + --with-workdir=$PREFIX/var/lib/cfengine \ + --without-selinux-policy \ + --without-systemd-service" +fi ./autogen.sh $OPTS diff --git a/configure.ac b/configure.ac index 6202c22835..d695a44f95 100644 --- a/configure.ac +++ b/configure.ac @@ -181,6 +181,14 @@ CC="$PTHREAD_CC" CFLAGS="$PTHREAD_CFLAGS $CFLAGS" LIBS="$PTHREAD_LIBS $LIBS" +dnl ###################################################################### +dnl libpromises/evalfunction.c isreadable() uses pthread_cancel so check +dnl if available and reverts to pthread_kill if not. +dnl This check must come after ACX_PTHREAD is called so that CC, CFLAGS, +dnl and LIBS are appropriately set for the local pthreads situation. +dnl ###################################################################### +AC_CHECK_FUNCS([pthread_cancel]) + dnl ###################################################################### dnl Whether to build extensions as builtin extensions or a separate dnl plugin. The default is plugin. @@ -1350,7 +1358,7 @@ AC_CHECK_DECLS([FALLOC_FL_PUNCH_HOLE], [], [], [ ]) AC_CHECK_HEADERS([sys/sendfile.h]) AC_CHECK_FUNCS([sendfile]) -AC_CHECK_FUNCS([copy_file_range]) +AC_CHECK_DECL([copy_file_range]) dnl ####################################################################### diff --git a/libenv/sysinfo.c b/libenv/sysinfo.c index 16f44c70e2..ddb4266094 100644 --- a/libenv/sysinfo.c +++ b/libenv/sysinfo.c @@ -3809,6 +3809,12 @@ static void SysOSNameHuman(EvalContext *ctx) "Alpine", CF_DATA_TYPE_STRING, "source=agent,derived-from=alpine"); } + else if (EvalContextClassGet(ctx, NULL, "termux") != NULL) + { + EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, lval, + "Termux", CF_DATA_TYPE_STRING, + "source=agent,derived-from=termux"); + } else if (EvalContextClassGet(ctx, NULL, "gentoo") != NULL) { EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, lval, diff --git a/libntech b/libntech index 3e7866b5d3..b0ea745cdd 160000 --- a/libntech +++ b/libntech @@ -1 +1 @@ -Subproject commit 3e7866b5d393b200a814ff5def7550ca18732ec0 +Subproject commit b0ea745cdddb4f8b12cc9709cebbe7a222d1db9e diff --git a/libpromises/dbm_test_api.c b/libpromises/dbm_test_api.c index def4d50b92..0ea5ba94e7 100644 --- a/libpromises/dbm_test_api.c +++ b/libpromises/dbm_test_api.c @@ -22,8 +22,9 @@ included file COSL.txt. */ +#ifndef __ANDROID__ #include -#include /* lrand48_r() */ +#include /* lrand48() */ #include /* usleep(), syscall()/gettid() */ #include /* xstrndup() */ #include @@ -70,23 +71,22 @@ static void DBItemDestroy(DBItem *item) } } -static __thread struct drand48_data rng_data; static void InitializeRNG(long int seed) { - srand48_r(seed, &rng_data); + srand48(seed); } static long GetRandomNumber(long limit) { long rnd_val; - lrand48_r(&rng_data, &rnd_val); /* generates a value in the [0, 2^31) interval */ + rnd_val = lrand48(); const long random_max = ((0x80000000 - 1) / limit) * limit; while (rnd_val > random_max) { /* got a bad value past the greatest multiple of the limit interval, * retry (see "modulo bias" if this is unclear) */ - lrand48_r(&rng_data, &rnd_val); + rnd_val = lrand48(); } return rnd_val % limit; } @@ -735,3 +735,4 @@ void RemoveFilament(DBFilament *filament) free(filament); CloseDB(db); } +#endif /* not __ANDROID__ */ diff --git a/libpromises/dbm_test_api.h b/libpromises/dbm_test_api.h index ffda177d75..a6fe0ae63d 100644 --- a/libpromises/dbm_test_api.h +++ b/libpromises/dbm_test_api.h @@ -22,6 +22,7 @@ included file COSL.txt. */ +#ifndef __ANDROID__ #ifndef CFENGINE_DBM_TEST_API_H #define CFENGINE_DBM_TEST_API_H @@ -55,3 +56,4 @@ DBFilament *FillUpDB(dbid db_id, int usage_pct); void RemoveFilament(DBFilament *filament); #endif /* CFENGINE_DBM_TEST_API_H */ +#endif /* not __ANDROID__ */ diff --git a/libpromises/evalfunction.c b/libpromises/evalfunction.c index b65b514af1..d5f24b8d23 100644 --- a/libpromises/evalfunction.c +++ b/libpromises/evalfunction.c @@ -86,6 +86,7 @@ #include #include /* ThreadWait */ #include +#include /* MaskTerminationSignalsInThread */ #include @@ -9672,10 +9673,29 @@ struct IsReadableThreadData bool success; }; +#ifndef HAVE_PTHREAD_CANCEL +#define PTHREAD_CANCELED ((void *)-1) +static void ThreadSignalHandler(int signum) +{ + pthread_exit(PTHREAD_CANCELED); +} +#endif + static void *IsReadableThreadRoutine(void *data) { assert(data != NULL); +#ifndef HAVE_PTHREAD_CANCEL + MaskTerminationSignalsInThread(); + struct sigaction actions; + memset(&actions, 0, sizeof(actions)); + sigemptyset(&actions.sa_mask); + actions.sa_flags = 0; + actions.sa_handler = ThreadSignalHandler; + sigaction(SIGHUP, &actions, NULL); + MaskTerminationSignalsInThread(); +#endif + struct IsReadableThreadData *const thread_data = data; // Give main thread time to call pthread_cond_timedwait(3) @@ -9827,7 +9847,11 @@ static FnCallResult FnCallIsReadable(ARG_UNUSED EvalContext *const ctx, "Read operation timed out, exceeded %ld seconds.", path, timeout); +#ifdef HAVE_PTHREAD_CANCEL ret = pthread_cancel(thread_data.thread); +#else + ret = pthread_kill(thread_data.thread, SIGUSR2); +#endif if (ret != 0) { Log(LOG_LEVEL_ERR, "Failed to cancel thread"); @@ -9857,10 +9881,12 @@ static FnCallResult FnCallIsReadable(ARG_UNUSED EvalContext *const ctx, return FnFailure(); } +#ifdef HAVE_PTHREAD_CANCEL if (status == PTHREAD_CANCELED) { Log(LOG_LEVEL_DEBUG, "Thread was canceled"); } +#endif return FnReturnContext(success); } diff --git a/tests/acceptance/testall b/tests/acceptance/testall index 0959688b33..1630c5ad76 100755 --- a/tests/acceptance/testall +++ b/tests/acceptance/testall @@ -285,9 +285,9 @@ workdir() { } # Example: fgrepvar 'word' VARNAME -# Silent fgrep for variables: search for "word" in $VARNAME -fgrepvar() { - eval echo \$$2 | fgrep "$1" > /dev/null +# Silent grep -F for variables: search for "word" in $VARNAME +fgrepvar(){ + eval echo \$$2 | grep -F "$1" > /dev/null } # Same but instead of word search for a regex @@ -524,22 +524,22 @@ export CFENGINE_TEST_OVERRIDE_WORKDIR TEMP CFENGINE_TEST_OVERRIDE_EXTENSION_LIBR echo "Return code is $RETVAL." >> "$WORKDIR/$LOG" # Try to collect test metadata if any - if egrep "R: test description: " $OUTFILE > /dev/null + if grep -E "R: test description: " $OUTFILE > /dev/null then - TEST_DESCRIPTION="$(egrep "R: test description" $OUTFILE | sed -e "s,.*test description: \([A-Za-z0-9_]*\),\1,")" + TEST_DESCRIPTION="$(grep -E "R: test description" $OUTFILE | sed -e "s,.*test description: \([A-Za-z0-9_]*\),\1,")" fi - if egrep -e "R: test story_id: " $OUTFILE > /dev/null + if grep -E -e "R: test story_id: " $OUTFILE > /dev/null then - TEST_STORY="$(egrep "R: test story_id" $OUTFILE | sed -e "s,.*test story_id: \([0-9][0-9]*\),\1,")" + TEST_STORY="$(grep -E "R: test story_id" $OUTFILE | sed -e "s,.*test story_id: \([0-9][0-9]*\),\1,")" fi - if egrep -e "R: test covers: " $OUTFILE > /dev/null + if grep -E -e "R: test covers: " $OUTFILE > /dev/null then - TEST_COVERS="$(egrep "R: test covers" $OUTFILE | sed -e "s,.*test covers: \([A-Za-z0-9_]*\),\1,")" + TEST_COVERS="$(grep -E "R: test covers" $OUTFILE | sed -e "s,.*test covers: \([A-Za-z0-9_]*\),\1,")" fi if [ $TEST_TYPE = errorexit ] then - if [ $RETVAL -gt 0 ] && [ $RETVAL -lt 128 ] && egrep "error:|aborted on defined class" $OUTFILE > /dev/null + if [ $RETVAL -gt 0 ] && [ $RETVAL -lt 128 ] && grep -E "error:|aborted on defined class" $OUTFILE > /dev/null then RESULT=Pass RESULT_MSG="${COLOR_SUCCESS}Pass${COLOR_NORMAL}" @@ -557,7 +557,7 @@ export CFENGINE_TEST_OVERRIDE_WORKDIR TEMP CFENGINE_TEST_OVERRIDE_EXTENSION_LIBR then RESULT=FAIL RESULT_MSG="${COLOR_FAILURE}FAIL (NON-ZERO EXIT CODE!)${COLOR_NORMAL}" - elif fgrep 'error: ' "$OUTFILE" > /dev/null + elif grep -F 'error: ' "$OUTFILE" > /dev/null then RESULT=Pass RESULT_MSG="${COLOR_SUCCESS}Pass${COLOR_NORMAL}" @@ -575,21 +575,21 @@ export CFENGINE_TEST_OVERRIDE_WORKDIR TEMP CFENGINE_TEST_OVERRIDE_EXTENSION_LIBR # Some states are output by dcs.sub.cf, therefore check for both TEST # prefix and dcs.sub.cf prefix. ESCAPED_TEST="$(echo "($TEST|dcs.sub.cf)" | sed -e 's/\./\\./g')" - if egrep "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE > /dev/null && ! egrep "R: .*$ESCAPED_TEST Wait/" $OUTFILE > /dev/null + if grep -E "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE > /dev/null && ! grep -E "R: .*$ESCAPED_TEST Wait/" $OUTFILE > /dev/null then # Check for passed outcome, which should not happen. - if egrep "R: .*$ESCAPED_TEST " $OUTFILE | egrep "R: .*$ESCAPED_TEST Pass" > /dev/null + if grep -E "R: .*$ESCAPED_TEST " $OUTFILE | grep -E "R: .*$ESCAPED_TEST Pass" > /dev/null then RESULT=FAIL RESULT_MSG="${COLOR_FAILURE}FAIL (The test Passed, but failure was expected)${COLOR_NORMAL}" - elif egrep "R: .*$ESCAPED_TEST " $OUTFILE | egrep -v "R: .*$ESCAPED_TEST [XS]?FAIL" > /dev/null + elif grep -E "R: .*$ESCAPED_TEST " $OUTFILE | grep -E -v "R: .*$ESCAPED_TEST [XS]?FAIL" > /dev/null then # Other test case outcomes than fail. Should not happen. RESULT=FAIL RESULT_MSG="${COLOR_FAILURE}FAIL (Failure was expected, but the test had an unexpected test outcome, check test output, Pass/FAIL need to match exactly)${COLOR_NORMAL}" else - TICKET="$(egrep "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE | sed -e "s,.*[XS]FAIL/\(.*\),\1,")" - RESULT="$(egrep "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE | sed -e "s,.*\([XS]FAIL\).*,\1,")" + TICKET="$(grep -E "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE | sed -e "s,.*[XS]FAIL/\(.*\),\1,")" + RESULT="$(grep -E "R: .*$ESCAPED_TEST [XS]FAIL" $OUTFILE | sed -e "s,.*\([XS]FAIL\).*,\1,")" if [ "$RESULT" = "XFAIL" ] then RESULT_MSG="${COLOR_WARNING}FAIL (Suppressed, $TICKET)${COLOR_NORMAL}" @@ -600,38 +600,38 @@ export CFENGINE_TEST_OVERRIDE_WORKDIR TEMP CFENGINE_TEST_OVERRIDE_EXTENSION_LIBR elif [ $RETVAL -ne 0 ] then RESULT=FAIL - elif egrep "R: .*$ESCAPED_TEST FAIL/no_ticket_number" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST FAIL/no_ticket_number" $OUTFILE > /dev/null then RESULT=FAIL RESULT_MSG="${COLOR_FAILURE}FAIL (Tried to suppress failure, but no issue number is provided)${COLOR_NORMAL}" - elif egrep "R: .*$ESCAPED_TEST Wait/[0-9]+" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST Wait/[0-9]+" $OUTFILE > /dev/null then if [ -z "$NEXT_TIMEOUT_VAR" ] then RESULT=FAIL RESULT_MSG="${COLOR_FAILURE}FAIL (Test tried to wait but is not in \"timed\" directory)${COLOR_NORMAL}" else - WAIT_TIME=$(egrep "R: .*$ESCAPED_TEST Wait/[0-9]+" $OUTFILE | sed -e 's,.*Wait/\([0-9][0-9]*\).*,\1,') + WAIT_TIME=$(grep -E "R: .*$ESCAPED_TEST Wait/[0-9]+" $OUTFILE | sed -e 's,.*Wait/\([0-9][0-9]*\).*,\1,') eval $NEXT_TIMEOUT_VAR=$(($TEST_END_TIME+$WAIT_TIME)) RESULT=Wait RESULT_MSG="Awaiting ($WAIT_TIME seconds)..." fi - elif egrep "R: .*$ESCAPED_TEST Pass" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST Pass" $OUTFILE > /dev/null then RESULT=Pass RESULT_MSG="${COLOR_SUCCESS}Pass${COLOR_NORMAL}" - elif egrep "R: .*$ESCAPED_TEST Skip/unsupported" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST Skip/unsupported" $OUTFILE > /dev/null then RESULT=Skip RESULT_MSG="${COLOR_WARNING}Skipped (No platform support)${COLOR_NORMAL}" - elif egrep "R: .*$ESCAPED_TEST Skip/needs_work" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST Skip/needs_work" $OUTFILE > /dev/null then RESULT=Skip RESULT_MSG="${COLOR_WARNING}Skipped (Test needs work)${COLOR_NORMAL}" - elif egrep "R: .*$ESCAPED_TEST FLAKEY" $OUTFILE > /dev/null + elif grep -E "R: .*$ESCAPED_TEST FLAKEY" $OUTFILE > /dev/null then RESULT=FLAKEY - TICKET="$(egrep "R: .*$ESCAPED_TEST FLAKEY" $OUTFILE | sed -e "s,.*FLAKEY/\(.*\),\1,")" + TICKET="$(grep -E "R: .*$ESCAPED_TEST FLAKEY" $OUTFILE | sed -e "s,.*FLAKEY/\(.*\),\1,")" RESULT_MSG="${COLOR_WARNING}Flakey fail ($TICKET)${COLOR_NORMAL}" else @@ -1075,7 +1075,7 @@ fi for addtest in $ALL_TESTS do - if echo "$addtest" | fgrep "/timed/" > /dev/null + if echo "$addtest" | grep -F "/timed/" > /dev/null then if [ "$TIMED_TESTS" = 1 ] then @@ -1133,12 +1133,12 @@ print_header() { print_footer() { # Recalculate results since sub invocations may not have been recorded. - PASSED_TESTS=`egrep '^Pass ' $SUMMARY | wc -l | tr -d ' '` - FAILED_TESTS=`egrep '^(FAIL|XFAIL) ' $SUMMARY | wc -l | tr -d ' '` - SUPPRESSED_FAILURES=`egrep '^XFAIL ' $SUMMARY | wc -l | tr -d ' '` - SOFT_FAILURES=`egrep '^SFAIL ' $SUMMARY | wc -l | tr -d ' '` - FLAKEY_FAILURES=`egrep '^FLAKEY ' $SUMMARY | wc -l | tr -d ' '` - SKIPPED_TESTS=`egrep '^Skip ' $SUMMARY | wc -l | tr -d ' '` + PASSED_TESTS=`grep -E '^Pass ' $SUMMARY | wc -l | tr -d ' '` + FAILED_TESTS=`grep -E '^(FAIL|XFAIL) ' $SUMMARY | wc -l | tr -d ' '` + SUPPRESSED_FAILURES=`grep -E '^XFAIL ' $SUMMARY | wc -l | tr -d ' '` + SOFT_FAILURES=`grep -E '^SFAIL ' $SUMMARY | wc -l | tr -d ' '` + FLAKEY_FAILURES=`grep -E '^FLAKEY ' $SUMMARY | wc -l | tr -d ' '` + SKIPPED_TESTS=`grep -E '^Skip ' $SUMMARY | wc -l | tr -d ' '` ( echo echo ======================================================================