. "$BST_LIB" # log4c 1.2.4 -- a C logging framework in the log4j idiom (meta-oe # recipes-support). See log4c_%.bbappend for what the port adds and why. # # --------------------------------------------------------------------------- # WHERE THE EVIDENCE IN THIS SUITE COMES FROM, AND WHY IT IS IN TWO HALVES # # The stock recipe installs NO program that exercises the library: log4c-config # is a shell script and binconfig-disabled replaces it with a stub that exits 1. # So on-target coverage had to come from somewhere, and it comes from two # independent places on purpose. # # UPSTREAM'S OWN CORPUS, WITH UPSTREAM'S OWN EXPECTED OUTPUT. tests/log4c/ is # noinst_PROGRAMS under `if TEST`; --enable-test builds it and this port # installs the four programs upstream itself diffs against checked-in # reference output (`check-local` in tests/log4c/Makefile.am), together with # that output. The comparison below IS upstream's -- same programs, same # LOG4C_PRIORITY, same normalising sed, same .ref files -- rather than a # re-typed approximation of it. Between them they cover the category tree, # priority inheritance and additivity, the appender/layout/rollingpolicy # factories, custom appender and layout types, the basic and reentrant # layouts, and log4c_rc_load's XML parse. # # A PROBE, for what has no .ref. data/log4c-probe (src/log4c_probe.c) is # cross-linked with wasmcc-glibc against THE VERY ARCHIVE THAT SHIPS # (/usr/lib/liblog4c.a) and covers the platform surface upstream's corpus # does not: which appender types the archive actually carries, writable # MAP_SHARED store-through, the mmap appender, the pthread-gated rolling-file # appender, and the expat config path through log4c_init(). # # BRINTOS-217 is the precedent for not stopping at payload shape: oniguruma # compiled and packaged perfectly on this arm and then returned silently wrong # offsets to every caller. # # THE ROWS WRITTEN FOR PLATFORM REASONS RATHER THAN FOR log4c'S, and the ones to # read first on a red run: # # probe-rawmmap-* mmap(PROT_READ|PROT_WRITE, MAP_SHARED) on a file, a # store into the mapping, and the bytes read back through # an ordinary descriptor. This image has answered # MAP_PRIVATE reads (logrotate) and MAP_SHARED|PROT_READ # on the virtiofs root (BRINTOS-491); it has never been # asked whether STORES reach the file. Asked here on BOTH # the virtiofs root and a tmpfs copy, because those are # different answers and the suite should not have to guess # which one a red belongs to. # probe-types-mmap HAVE_MMAP IS PRE-ANSWERED, NOT MEASURED. AC_FUNC_MMAP # is a run test and cross-compiling never executes it; # poky's meta/site/common-glibc supplies `yes` for every # glibc cross target, which is why the configure log reads # "(cached) yes". It is the same table entry file(1) and # libarchive override with `no`. If it ever flips, the # mmap appender vanishes from the archive and nothing else # in the build says so. # probe-types-rollingfile / probe-rollingfile-* # WITH_ROLLINGFILE follows AC_CHECK_LIB(pthread, # pthread_mutex_init) against this arm's libc. The # appender takes a pthread mutex on every append, so # these rows are where a libc that offers the SYMBOL # without offering working mutexes would show. # probe-syslog-* openlog/syslog to /dev/log -- the same AF_UNIX surface # BRINTOS-492 measured from the other side, asserted here # as "does not take the process down on an image with no # daemon", which is the part that is portable. # # EVERY EXPECTED VALUE IS THE VALUE A NATIVE x86_64 BUILD OF THE IDENTICAL # RELEASE PRODUCES, and probe-native-byte-identical asserts that ON TARGET # rather than by eyeballing two logs off-target. require log4c-test-category log4c/present D=${TMPDIR:-/tmp}/bst-log4c.$$ rm -rf "$D"; mkdir -p "$D" # has # # A red carries THE LINE THE PROBE ACTUALLY PRINTED, not just the needle that # was missing. Every probe case prints its value on both the OK and the FAIL # path precisely so a failure is self-describing, and reporting only "not found: # L4C-x OK" throws that away -- the first run of this suite on target reported # five reds that between them did not say which errno mmap returned, and # answering that took a second boot. The needle's own case name is enough to # find the line: "L4C- OK" -> grep "^L4C- ". has() { case "$3" in *"$2"*) bst_ok "$1" ;; *) _n=${2% OK} [ "$_n" = "$2" ] && _n=${2%% *} # banner needles carry no " OK" _got=$(printf '%s\n' "$3" | grep "^$_n " | head -n 1) bst_notok "$1" "${_got:-no $_n line}" ;; esac } # --- payload shape ------------------------------------------------------------ # The -dev/-staticdev split oe-core produces, at the paths this image uses, plus # the four conformance programs and their fixtures. inv="" for f in /usr/lib/liblog4c.a \ /usr/include/log4c.h \ /usr/include/log4c/category.h \ /usr/include/log4c/appender.h \ /usr/lib/pkgconfig/log4c.pc \ /etc/log4crc.sample \ /usr/bin/log4c-test-category \ /usr/bin/log4c-test-rc \ /usr/bin/log4c-test-layout-r \ /usr/bin/log4c-test-big \ /usr/share/log4c-tests/test_category.ref \ /usr/share/log4c-tests/test_rc.ref \ /usr/share/log4c-tests/test_layout_r.ref \ /usr/share/log4c-tests/test_big.ref \ /usr/share/log4c-tests/test_rc.in; do [ -e "$f" ] || inv="$inv $f" done check_eq log4c/inventory "" "$inv" # The CONVERTED arm's shape. This row used to assert the opposite -- that no # liblog4c*.so exists at all -- and said it was what would notice if the distro # stopped forcing --disable-shared. It did stop, for log4c, in BRINTOS-1419: the # recipe is allow-listed, `-version-info @LT_VERSION@` now does reach libtool's # $(CC) -shared step, and the package ships a real side module. So the row is # replaced by the assertions that are load-bearing once it exists rather than # deleted -- the old one would now be a standing red that says only "the flip # happened", which is already recorded in conf/distro/brintos.conf. # # bst_lib_shape catches the two ways a converted package ships a library nothing # can use: a symlink whose target went to -dev (dangling on the image), and a # zero-length .so. The second is worth a standing row precisely here -- that is # BRINTOS-1413's shape, libgsl.so at 1469 bytes, and log4c is assembled the same # way, one convenience archive (liblog4c_sd) merged in under --whole-archive. bst_lib_shape log4c/shared-object-shape '/usr/lib/liblog4c.so*' # The digest-qualified name is a SEPARATE assertion from the library existing, # and it is the one that decides whether a consumer can bind. A main records its # dependency as . and the loader looks that exact # filename up in /usr/lib -- BRINTOS-1442 -- so a correctly versioned # liblog4c.so.3.3.1 with no digest-qualified name beside it is a library nothing # on the image can resolve, and every one of the four programs below would die at # exec rather than fail a comparison. # # Conditional on the arm, like bst_lib_shape above and for the same reason. The # allow-list entry only permits the conversion; whether it happens is # BRINTOS_PACKAGE_SHARED, and the shipped arm sets it "0" # (conf/distro/brintos.conf), so /usr/lib holds liblog4c.a and no .so at all. # Asserting the digest name unconditionally makes this a red that can never go # green on the arm we ship -- which says nothing about log4c and hides the case # it was written for. Measured on the batch-1987 image, 2026-09-04. sos=$(ls /usr/lib/liblog4c.so* 2>/dev/null | tr '\n' ' ') if [ -z "$sos" ]; then bst_skip log4c/shared-object-digest-staged \ "static arm: no /usr/lib/liblog4c.so* to qualify (BRINTOS_PACKAGE_SHARED=0)" elif ls /usr/lib/liblog4c.so* 2>/dev/null | grep -qE '\.[0-9a-f]{64}$'; then bst_ok log4c/shared-object-digest-staged else bst_notok log4c/shared-object-digest-staged \ "no /usr/lib/liblog4c.so*.; $sos" fi # log4c-config is a binconfig script and binconfig-disabled replaced it with a # stub. Asserting the STUB (rather than its absence) is the point: a build that # quietly shipped the real script would hand callers the build host's -I/-L # paths, which is what binconfig-disabled exists to prevent. if [ -e /usr/bin/log4c-config ]; then check_rc log4c/config-stub-refuses 1 /usr/bin/log4c-config --cflags else bst_skip log4c/config-stub-refuses "log4c-config not packaged in this image" fi # --- upstream's own reference comparison -------------------------------------- # Exactly what tests/log4c/Makefile.am's check-local does: run each program with # LOG4C_PRIORITY=notice, normalise the one machine-dependent token (the appender # udata pointer) with upstream's own sed, and diff against upstream's .ref. # `diff -b` is upstream's flag too. # # EACH PROGRAM IS RUN THROUGH A LINK CARRYING UPSTREAM'S NAME, AND THAT IS # LOAD-BEARING, NOT TIDINESS. sd_test_new() takes basename(argv[0]) and derives # ".out", ".in" and ".ref" from it -- and test_category.c goes # further, naming its stream appender log4c_appender_get(sd_test_get_name(t)), # which the basic layout then prints in EVERY LINE. So invoking the installed # `log4c-test-category` directly writes log4c-test-category.out and fills it # with "[log4c-test-category] ..." where the .ref says "[test_category] ...", # and all four comparisons fail on the port's own rename rather than on log4c. # # Running via $D/test_category restores upstream's argv[0] while the IMAGE keeps # the non-generic ${bindir} name -- so the comparison below is upstream's, # unmodified, and the .ref files ship from the tarball untouched. # # (Caught by dry-running this file against the native control: every exit status # was 0 and every comparison reported "no .out produced" -- which is the shape a # silent rename failure has, and is why the dry run happens before the image is # built rather than after.) refdir=/usr/share/log4c-tests for pair in test_category:log4c-test-category test_layout_r:log4c-test-layout-r \ test_rc:log4c-test-rc test_big:log4c-test-big; do stem=${pair%%:*}; prog=${pair#*:} ln -s "$(command -v "$prog")" "$D/$stem" 2>/dev/null || \ cp "$(command -v "$prog")" "$D/$stem" 2>/dev/null done ( cd "$D" || exit 1 for stem in test_category test_layout_r test_rc test_big; do LOG4C_PRIORITY=notice "./$stem" >/dev/null 2>&1 printf '%s %d\n' "$stem" "$?" >> "$D/rcs" done ) for pair in category:test_category layout_r:test_layout_r rc:test_rc \ big:test_big; do name=${pair%%:*}; stem=${pair#*:} prc=$(awk -v n="$stem" '$1==n{print $2}' "$D/rcs" 2>/dev/null) check_eq "log4c/upstream-$name-exit0" 0 "${prc:-missing}" if [ ! -f "$D/$stem.out" ]; then bst_notok "log4c/upstream-$name-ref" "no $stem.out produced" continue fi sed -e 's/udata:0x00*\([ }]\)/udata:(nil)\1/' \ -e 's/udata:00*\([ }]\)/udata:(nil)\1/' \ -e 's/udata:0x[0-9a-fA-F][0-9a-fA-F]*\([ }]\)/udata:0x111111111111\1/' \ -e 's/udata:[0-9a-fA-F][0-9a-fA-F]*\([ }]\)/udata:0x111111111111\1/' \ "$D/$stem.out" > "$D/$stem.out2" 2>/dev/null if diff -b "$D/$stem.out2" "$refdir/$stem.ref" >/dev/null 2>&1; then bst_ok "log4c/upstream-$name-ref" else bst_notok "log4c/upstream-$name-ref" \ "first diff: $(diff -b "$D/$stem.out2" "$refdir/$stem.ref" 2>/dev/null | sed -n '2,3p' | tr '\n' ' ' | cut -c1-90)" fi done # --- the probe ---------------------------------------------------------------- probe=$D/log4c-probe if cp "$BST_DATA/log4c-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then all=$D/all.txt : > "$all" # Four invocations, and they are separate processes for two independent # reasons: log4c_init() latches per process (so `rc` cannot run after # anything else has initialised), and the mmap appender's undetected-failure # path ends in a store to (void*)-1 (so on an arm that could not map, that # mode would abort and must not take the others with it). # # stderr is dropped: log4c's own error paths perror() and fprintf() PATHS, # which differ between the arms by construction and would break the # byte-diff below. The verdicts are all on stdout. for m in core mmapapp rollingfile rc; do wd=$D/wd-$m; rm -rf "$wd"; mkdir -p "$wd" "$probe" "$m" "$wd" 2>/dev/null >> "$all" eval "rc_$m=\$?" done out=$(cat "$all") # -- which appender types the shipped archive carries ------------------------ has log4c/probe-types-stream "L4C-types-stream OK" "$out" has log4c/probe-types-stream2 "L4C-types-stream2 OK" "$out" has log4c/probe-types-mmap "L4C-types-mmap OK" "$out" has log4c/probe-types-syslog "L4C-types-syslog OK" "$out" has log4c/probe-types-rollingfile "L4C-types-rollingfile OK" "$out" has log4c/probe-types-unknown-null "L4C-types-unknown-null OK" "$out" # -- THE FILE-BACKED mmap MATRIX --------------------------------------------- # Four combinations over one file plus an anonymous control, each carrying # its errno when it fails. These are the rows to read first: they are the # platform's own answer, taken with the same call log4c makes, and they are # what every mmap-appender row below depends on. has log4c/probe-rawmmap-open "L4C-rawmmap-open OK" "$out" has log4c/probe-rawmmap-anon "L4C-rawmmap-anon-control OK" "$out" has log4c/probe-rawmmap-private-read "L4C-rawmmap-private-read OK" "$out" has log4c/probe-rawmmap-shared-read "L4C-rawmmap-shared-read OK" "$out" has log4c/probe-rawmmap-private-write "L4C-rawmmap-private-write OK" "$out" has log4c/probe-rawmmap-shared-write "L4C-rawmmap-shared-write OK" "$out" has log4c/probe-rawmmap-storethrough "L4C-rawmmap-storethrough OK" "$out" # Whether the platform has the mapping log4c's appender needs. Every # mmap-appender row below is conditioned on this, so a platform without it # produces TWO reds that each mean something (the matrix row above, and # log4c-unusable below) instead of a dozen that all mean the same one. case "$out" in *"L4C-rawmmap-shared-write OK"*) HAVE_SHARED_WRITE=1 ;; *) HAVE_SHARED_WRITE=0 ;; esac # -- the stream appender, and the layout's exact bytes ----------------------- has log4c/probe-stream-appender-new "L4C-stream-appender-new OK" "$out" has log4c/probe-stream-line-exact "L4C-stream-line-exact OK" "$out" # -- the syslog appender ----------------------------------------------------- has log4c/probe-syslog-open "L4C-syslog-open OK" "$out" has log4c/probe-syslog-survived "L4C-syslog-append-survived OK" "$out" has log4c/probe-syslog-close "L4C-syslog-close OK" "$out" # -- the priority string mapping, which log4crc parses through --------------- has log4c/probe-prio-to-string "L4C-prio-to-string-error OK" "$out" has log4c/probe-prio-from-string "L4C-prio-from-string-warn OK" "$out" has log4c/probe-prio-garbage "L4C-prio-from-string-garbage OK" "$out" # -- log4c's mmap appender --------------------------------------------------- # Its type is registered whatever the platform does -- HAVE_MMAP is a build- # time table entry, not a measurement -- so this row is asserted either way. has log4c/probe-mmapapp-type "L4C-mmapapp-type OK" "$out" if [ "$HAVE_SHARED_WRITE" = 1 ]; then has log4c/probe-mmapapp-missing-refused "L4C-mmapapp-missing-file-refused OK" "$out" has log4c/probe-mmapapp-empty-refused "L4C-mmapapp-empty-file-refused OK" "$out" has log4c/probe-mmapapp-open "L4C-mmapapp-open OK" "$out" has log4c/probe-mmapapp-close "L4C-mmapapp-close OK" "$out" has log4c/probe-mmapapp-storethrough "L4C-mmapapp-storethrough OK" "$out" has log4c/probe-mmapapp-size-unchanged "L4C-mmapapp-size-unchanged OK" "$out" has log4c/probe-mmapapp-tail-untouched "L4C-mmapapp-tail-untouched OK" "$out" # The appender name is part of the STREAM appender's output and not part of # the layout, so the same event lands on disk in two different formats # depending on which appender took it. Pinned so a change that unified them # would be visible rather than silent. has log4c/probe-mmapapp-no-prefix "L4C-mmapapp-no-appender-prefix OK" "$out" has log4c/probe-mmapapp-wrap-size "L4C-mmapapp-wrap-size OK" "$out" has log4c/probe-mmapapp-wrap-content "L4C-mmapapp-wrap-content OK" "$out" bst_ok log4c/probe-mmapapp-usable else # ONE red for the consequence, and skips -- not reds -- for the rows that # simply cannot be run. The defect itself is already red one section up # (probe-rawmmap-shared-write, carrying the errno); repeating it eleven # times here would not make it more visible, only harder to read. Nothing # is downgraded to make the suite green: an image that ships an appender # its platform cannot support is a FAILURE and says so here. bst_notok log4c/probe-mmapapp-usable \ "log4c ships an mmap appender this platform cannot back: mmap(PROT_WRITE, MAP_SHARED) on a file fails, see probe-rawmmap-shared-write for the errno" for c in missing-refused empty-refused open close storethrough \ size-unchanged tail-untouched no-prefix wrap-size wrap-content; do bst_skip "log4c/probe-mmapapp-$c" \ "needs a writable shared file mapping; see log4c/probe-mmapapp-usable" done fi # UPSTREAM'S UNDETECTED MAP_FAILED, PROVOKED ON PURPOSE. # # mmap_open tests its result as `addr == NULL`; mmap fails with MAP_FAILED, # (void*)-1. So where the mapping fails, log4c reports the appender OPEN and # the first append memcpys to (void*)-1 -- on wasm32 an out-of-bounds store # that takes the module down. `mmapapp-unguarded` drives exactly that path. # # Both outcomes are a pass, because which one happens is a property of the # platform and the case exists to say WHICH: on a platform with the mapping # the run completes, and on one without it the process dies. Only a third # shape -- a clean run that silently wrote nowhere -- is red, and that is the # one worth waking someone for. uout=$("$probe" mmapapp-unguarded "$D/wd-mmapapp" 2>/dev/null); urc=$? if [ "$HAVE_SHARED_WRITE" = 1 ]; then case "$uout=$urc" in *"L4C-mmapapp-storethrough OK"*=0) bst_ok log4c/probe-mapfailed-not-reached ;; *) bst_notok log4c/probe-mapfailed-not-reached "rc=$urc $(_bst_1line "$uout")" ;; esac else case "$urc" in 0) bst_notok log4c/probe-mapfailed-kills-process \ "expected the undetected MAP_FAILED store to abort; it returned 0: $(_bst_1line "$uout")" ;; *) bst_ok log4c/probe-mapfailed-kills-process ;; esac fi # -- the rolling-file appender, i.e. pthread mutexes on this arm ------------- has log4c/probe-rollingfile-type "L4C-rollingfile-type OK" "$out" has log4c/probe-rollingfile-init "L4C-rollingfile-policy-init OK" "$out" has log4c/probe-rollingfile-close "L4C-rollingfile-close OK" "$out" has log4c/probe-rollingfile-live "L4C-rollingfile-live-exists OK" "$out" has log4c/probe-rollingfile-rolled "L4C-rollingfile-rolled-exists OK" "$out" has log4c/probe-rollingfile-bounded "L4C-rollingfile-window-bounded OK" "$out" has log4c/probe-rollingfile-size-rolled "L4C-rollingfile-rolled-size OK" "$out" has log4c/probe-rollingfile-size-oldest "L4C-rollingfile-oldest-size OK" "$out" has log4c/probe-rollingfile-size-live "L4C-rollingfile-live-size OK" "$out" # -- the expat config path through log4c_init() ------------------------------ has log4c/probe-rc-init "L4C-rc-init OK" "$out" has log4c/probe-rc-category "L4C-rc-category-exists OK" "$out" has log4c/probe-rc-priority "L4C-rc-category-priority OK" "$out" has log4c/probe-rc-appender "L4C-rc-category-appender OK" "$out" has log4c/probe-rc-line-exact "L4C-rc-appender-line-exact OK" "$out" has log4c/probe-rc-filtered "L4C-rc-priority-filtered OK" "$out" # The arm's own banner. Excluded from the byte-diff below along with L4C-ENV, # because these are the lines that must legitimately differ between the # control and this arm rather than the ones that must not. has log4c/probe-arch "L4C-ARCH pointers=32 sizeof(long)=4 sizeof(size_t)=4" "$out" # BYTE-IDENTITY AGAINST THE NATIVE CONTROL, asserted here ON TARGET rather # than by eyeballing two logs off-target. data/log4c-native.txt is the # verbatim output of this same probe source built natively against a host # build of the identical release, with the arm- and environment-dependent # lines removed. Comparing it inside the guest keeps the console capture out # of the comparison, and turns "matches native" from a one-off manual check # into a permanent regression guard: a change in mmap semantics, in the # rotation arithmetic or in the expat parse shows up as a CHANGED VALUE here # even if every verdict above still passes. # The mmap rows are excluded for the same reason L4C-ARCH is: they are the # lines that may LEGITIMATELY differ between the two arms, and they are # already asserted individually above -- which is stronger than a diff, not # weaker. Everything else must match to the byte, and that is where a silent # change in the rotation arithmetic, the expat parse or the layout would show. ctl=$BST_DATA/log4c-native.txt gotf=$D/got.txt printf '%s\n' "$out" \ | grep -vE '^L4C-(ENV|ARCH|VERSION|SUMMARY|rawmmap|mmapapp)' > "$gotf" 2>/dev/null if [ ! -s "$ctl" ]; then bst_notok log4c/probe-native-byte-identical "control absent or empty: $ctl" elif cmp -s "$ctl" "$gotf"; then bst_ok log4c/probe-native-byte-identical else bst_notok log4c/probe-native-byte-identical \ "first diff: $(diff "$ctl" "$gotf" 2>/dev/null | sed -n '2,3p' | tr '\n' ' ' | cut -c1-90)" fi # The probe's own tallies for the two modes that are platform-independent. # These are what the same source scores natively against a host build of the # identical release. core's and mmapapp's tallies are not asserted as numbers # because both legitimately shrink where the platform lacks the mapping -- # their cases are asserted individually above instead. has log4c/probe-summary-rollingfile "L4C-SUMMARY 10/10" "$out" has log4c/probe-summary-rc "L4C-SUMMARY 7/7" "$out" check_eq log4c/probe-exit0-rollingfile 0 "$rc_rollingfile" check_eq log4c/probe-exit0-rc 0 "$rc_rc" # -- THE SAME WRITABLE MAPPING, ON tmpfs ------------------------------------- # Everything above ran under ${TMPDIR:-/tmp}. Whether that is the virtiofs # root or a tmpfs depends on the image, and the two are genuinely different # substrates for mmap -- which is the distinction BRINTOS-491 had to draw for # MAP_SHARED|PROT_READ and could only draw by testing both. So the raw # store-through and the mmap appender are re-run against the OTHER one, and # the rows are named so a red says which substrate it belongs to. # # $BST_DATA is on the payload's own filesystem (the rootfs), so it is the # second substrate whichever way $TMPDIR resolved. It is read-only in # principle, so the working directory goes beside it only if that works, and # says so plainly if it does not. alt=$BST_DATA/../l4c-alt.$$ if mkdir -p "$alt" 2>/dev/null && : > "$alt/.w" 2>/dev/null; then rm -f "$alt/.w" aout=$("$probe" core "$alt" 2>/dev/null) has log4c/probe-rawmmap-shared-write-rootfs \ "L4C-rawmmap-shared-write OK" "$aout" has log4c/probe-rawmmap-storethrough-rootfs \ "L4C-rawmmap-storethrough OK" "$aout" rm -rf "$alt" else bst_skip log4c/probe-rawmmap-shared-write-rootfs \ "no writable directory on the payload filesystem" bst_skip log4c/probe-rawmmap-storethrough-rootfs \ "no writable directory on the payload filesystem" fi else bst_notok log4c/probe-stage "cannot stage $BST_DATA/log4c-probe" fi rm -rf "$D"