# BST-TIMEOUT: 900 # 71 small files digested in one sha256sum -c pass, read a # # second time by an awk reader, and one 1 MB wasm probe # # run. Under the 46-68x wall-clock factor this platform # # carries (linux-in-the-browser#117) that is minutes. The # # bound is a LOAD bound: it must fire when the guest is # # starved, not when the package regressed. . "$BST_LIB" # xbitmaps 1.1.3 -- the common X11 bitmap set. 71 XBM files under # /usr/include/X11/bitmaps and one .pc, and nothing else: no program, no # library, no configuration. So "the port works" is entirely a statement about # INSTALLED DATA, and the assertions below are the three things that can be said # about data of this kind. # # 1. IT IS ALL THERE AND IT IS UNCHANGED. The installed set is compared as an # EQUALITY against the recipe's own manifest -- so a file added or dropped # upstream is visible rather than absorbed by a one-sided "everything # declared is present" -- and every file's sha256 is checked against what # the recipe measured at do_install. # # 2. EVERY FILE IS A WELL-FORMED XBM. An XBM's one silent failure mode is a # _width/_height pair that disagrees with the length of the _bits array: # it compiles, it installs, and it draws garbage or reads off the end. That # relation is checked here on the shipped bytes by data/xbitmaps-xbm.awk, # which shares no code with the Python parser that wrote CENSUS -- so # agreement between the two is a statement about the data rather than about # either parser. It is ALSO checked at compile time on this arm, by a # _Static_assert per bitmap inside the probe the recipe cross-compiles. # # 3. IT MEANS THE SAME THING HERE AS ANYWHERE. The probe's whole output is # diffed against a build-host run of the SAME generated source over the # SAME headers -- 69 lines of dimensions, array lengths and Fletcher sums, # target wasm32 against x86-64. For a package of pure data any difference # is a real difference, so the pass criterion is exact equality. # # WHY 69 AND NOT 71. An XBM file is dual use: Xlib's XReadBitmapFile() parses it # at run time, and a C translation unit can #include it. The second use needs # the file's stem to be a valid C identifier, and `1x1' and `2x2' begin with a # digit -- so `#define 1x1_width 16' is a constraint violation every # preprocessor rejects. They are runtime-parse-only upstream, on every compiler # and every architecture. This is not an arm fact, there is nothing to fix, and # the pair is asserted BY NAME below so that a third file joining them is a red # rather than a smaller number. # # WHAT IS NOT ASSERTED, AND WHY. The ticket asked for an architecture field of # `all'. The recipe is not allarch: meta-oe's xorg-data-common.inc does not # inherit it, so this package carries this arm's architecture and the built # .deb says `Architecture: wasm32'. That is measured below rather than wished # away. The substance of the question -- that nothing architecture-specific is # in the payload -- is asserted directly instead: every installed bitmap is # checked to be C source text, which no ELF object (\177ELF) or wasm module # (\0asm) can be, and the package is checked to install nothing under libdir. BM=/usr/include/X11/bitmaps PCD=/usr/share/pkgconfig ST=/usr/libexec/xbitmaps-tests CENSUS=$ST/CENSUS REF=$ST/xbitmaps-probe.ref XBMAWK=$BST_DATA/xbitmaps-xbm.awk NBITMAPS=71 NCOMPILABLE=69 PKGVER=1.1.3-r0 PV=1.1.3 # The dropped-first-line absorber: brintos/linux#96 loses the first BST result # line of a brintos-selftest INVOCATION. This case exists to be the one that is # lost -- it asserts nothing and costs nothing when this suite is not run first. # Remove it when #96 closes. bst_ok xbitmaps/suite-canary if [ ! -d "$BM" ]; then bst_skip xbitmaps/present "no $BM on this image" exit 0 fi bst_ok xbitmaps/present t=${TMPDIR:-/tmp}/bst-xbitmaps.$$ if ! mkdir -p "$t" 2>/dev/null; then bst_notok xbitmaps/tmpdir "cannot create $t" exit 0 fi # ------------------------------------- 1. the recipe's own evidence arrived # # Every later section reads CENSUS. A suite that compared the tree against a # MISSING manifest would agree with nothing and report it as a pass, so each # read below has the shape "derive from the file, then compare", never "grep the # file for the answer". check xbitmaps/census-installed test -s "$CENSUS" check xbitmaps/census-green grep -qx "CENSUS-END fails=0" "$CENSUS" check xbitmaps/census-count grep -qx "CENSUS-COUNT $NBITMAPS $NCOMPILABLE" "$CENSUS" check xbitmaps/ref-installed test -s "$REF" check xbitmaps/probe-installed test -s "$ST/xbitmaps-probe" check xbitmaps/xbmawk-installed test -s "$XBMAWK" # ------------------------------------------- 2. the declared set, as equality DECL=$t/declared INST=$t/installed sed -n 's/^CENSUS-FILE \([^ ]*\) .*$/\1/p' "$CENSUS" | LC_ALL=C sort > "$DECL" ls -1 "$BM" | LC_ALL=C sort > "$INST" check_eq xbitmaps/declared-count "$NBITMAPS" "$(wc -l < "$DECL" | tr -d ' ')" check_eq xbitmaps/installed-count "$NBITMAPS" "$(wc -l < "$INST" | tr -d ' ')" # cmp, not "every declared file exists": the comparison has to bite in BOTH # directions. A bitmap upstream added and the recipe's floors did not notice # would pass a one-sided check while the image quietly carried a file nobody # had measured. if cmp -s "$DECL" "$INST"; then bst_ok xbitmaps/declared-set else bst_notok xbitmaps/declared-set \ "the installed set and CENSUS disagree -- only in CENSUS: $(LC_ALL=C comm -23 "$DECL" "$INST" | tr '\n' ' '); only installed: $(LC_ALL=C comm -13 "$DECL" "$INST" | tr '\n' ' ')" fi # ------------------------------------- 3. every file is byte-for-byte the same # file the recipe measured. sha256, not size: a bitmap edited in place keeps # its length far more often than not, because the payload is a fixed-width hex # table. SUMS=$t/sums awk -v d="$BM" '$1 == "CENSUS-FILE" { print $5 " " d "/" $2 }' "$CENSUS" > "$SUMS" check_eq xbitmaps/sums-derived "$NBITMAPS" "$(wc -l < "$SUMS" | tr -d ' ')" if command -v sha256sum >/dev/null 2>&1; then check_eq xbitmaps/payload-digests "" "$(sha256sum -c "$SUMS" 2>&1 | grep -v ': OK$' | tr '\n' ' ')" else bst_skip xbitmaps/payload-digests "no sha256sum on this image" fi # The sizes too, as a separate and cheaper statement: a digest mismatch says # WHICH file changed and a size mismatch says by how much, and the two together # distinguish a truncated install from an edited one. BADSIZE=$(awk -v d="$BM" '$1 == "CENSUS-FILE" { print $2, $4 }' "$CENSUS" | while read -r n sz; do a=$(wc -c < "$BM/$n" 2>/dev/null | tr -d ' ') [ "$a" = "$sz" ] || printf '%s(%s!=%s) ' "$n" "$a" "$sz" done) check_eq xbitmaps/payload-sizes "" "$BADSIZE" # --------------------- 4. every file is a well-formed XBM, read independently # # data/xbitmaps-xbm.awk walks the SHIPPED bytes and re-derives, per file, the # symbol stem, the declared width and height, the storage type of the bits # array and the number of initialisers in it. CENSUS carries the same six # fields from a Python parser that ran at do_install. Projecting CENSUS into the # reader's own output format and comparing the two whole files is one assertion # that covers all 71 files and all six fields -- and it is an assertion about # the bitmaps, because nothing is shared between the two implementations. AWKOUT=$t/awk.out awk -f "$XBMAWK" "$BM"/* > "$AWKOUT" 2>"$t/awk.err" check_eq xbitmaps/xbm-reader-clean "" "$(cat "$t/awk.err")" # The reader reports what it could not parse rather than skipping it. Anything # here is a corrupt bitmap, and it must not be able to pass as a shorter clean # run -- which is what the count case below is for. check_eq xbitmaps/xbm-reader-no-bad "" "$(grep '^XBM-AWK-BAD ' "$AWKOUT" | tr '\n' ' ')" check_eq xbitmaps/xbm-reader-count "$NBITMAPS" "$(grep -c '^XBM-AWK ' "$AWKOUT" | tr -d ' ')" sed -n 's/^CENSUS-FILE \([^ ]*\) \([^ ]*\) [0-9]* [0-9a-f]* \(.*\)$/XBM-AWK \1 \2 \3/p' \ "$CENSUS" | LC_ALL=C sort > "$t/census.proj" # The reader emits one field CENSUS does not carry -- the Fletcher sum, which # is joined to the PROBE below rather than to the census -- so it is dropped # here. Everything else is compared. grep '^XBM-AWK ' "$AWKOUT" | awk '{ print $1, $2, $3, $4, $5, $6, $7, $8 }' \ | LC_ALL=C sort > "$t/awk.proj" if cmp -s "$t/census.proj" "$t/awk.proj"; then bst_ok xbitmaps/xbm-reader-agrees else bst_notok xbitmaps/xbm-reader-agrees \ "the on-target awk reader and the recipe's census disagree about the bitmaps; first difference: $(diff "$t/census.proj" "$t/awk.proj" 2>/dev/null | head -n 4 | tr '\n' ' ')" fi # THE DIMENSION RELATION, stated once here in the suite's own arithmetic rather # than taken from either parser. ((width + 7) / 8) * height is the number of # bytes an XBM of that size must carry, and a file where the two disagree is the # one way an XBM can be silently wrong. BADDIM=$(grep '^XBM-AWK ' "$AWKOUT" | while read -r _ n _ w h _ nb _; do want=$(( ((w + 7) / 8) * h )) [ "$nb" = "$want" ] || printf '%s(%sx%s:%s!=%s) ' "$n" "$w" "$h" "$nb" "$want" done) check_eq xbitmaps/dimensions-match-bits "" "$BADDIM" # ------------------------------- 5. the two files no C program can include # # Asserted BY NAME, in both directions. A count would let a third file join them # unnoticed, and a one-sided check would not notice if one of the pair started # compiling -- which would mean upstream had renamed it, and renaming a bitmap # breaks every consumer that includes it. check_eq xbitmaps/non-identifier-set "1x1 2x2" \ "$(sed -n 's/^CENSUS-drop-\([^ ]*\) .*$/\1/p' "$CENSUS" | LC_ALL=C sort | tr '\n' ' ' | sed 's/ $//')" # Each refusal carries the compiler's own reason. Not the WORDING -- clang says # "macro name must be an identifier" and gcc "macro names must be identifiers", # and the target compiler is not the suite's business -- only that a reason was # recorded, so the exclusion is auditable rather than asserted. check_eq xbitmaps/non-identifier-reasons 2 \ "$(grep -c '^CENSUS-drop-[^ ]* .' "$CENSUS" | tr -d ' ')" # And they SHIP. They cannot be included, but XReadBitmapFile() reads them at # run time and an X client that names one must find it. Excluding them from the # probe must not have excluded them from the package. check xbitmaps/non-identifier-1x1-installed test -s "$BM/1x1" check xbitmaps/non-identifier-2x2-installed test -s "$BM/2x2" # --------------------- 6. the five files whose symbols are not under their name # # An XBM's file name and its symbol stem are independent, and upstream proves # it five times: a consumer that derived `calculator_bits' from the file name # would not compile. Two of them collide outright -- `calculator' and `icon' # both declare icon_width, icon_height and icon_bits, at 28x48 and 16x16 -- which # is why the probe includes each bitmap inside its own function body with the # macros undefined between. The set is pinned so that a rename is a red here # rather than a mystery in some client months later. check_eq xbitmaps/symbol-stems \ "calculator=icon dropbar7=bar7 mailemptymsk=mailemask terminal=xterm woman=sorceress" \ "$(awk '$1 == "CENSUS-FILE" && $2 != $3 { printf "%s=%s ", $2, $3 }' "$CENSUS" | sed 's/ $//')" # The collision itself, asserted rather than described: the two files really do # share a stem and really do differ in size, so a probe that included both at # file scope could not have built. check_eq xbitmaps/stem-collision "icon 28 48 / icon 16 16" \ "$(awk '$1 == "CENSUS-FILE" && ($2 == "calculator" || $2 == "icon") { printf "%s %s %s / ", $3, $6, $7 }' "$CENSUS" | sed 's| / $||')" # ---------------------------------- 7. the fixtures, against literals # # Spot values typed here rather than derived from anything on the image, so that # a CENSUS and a payload that were rewritten TOGETHER -- consistently, and # therefore invisibly to every comparison above -- still fail. check_eq xbitmaps/fixture-gray1 "gray1 gray1 2 2 char 2 -" \ "$(awk '$1 == "CENSUS-FILE" && $2 == "gray1" { print $2, $3, $6, $7, $8, $9, $10 }' "$CENSUS")" check_eq xbitmaps/fixture-gray1-bytes "0x01, 0x02" \ "$(sed -n 's/^ *\(0x[0-9a-f][0-9a-f], 0x[0-9a-f][0-9a-f]\)}.*$/\1/p' "$BM/gray1")" check_eq xbitmaps/fixture-weird-size "weird_size weird_size 7 13 char 13 -" \ "$(awk '$1 == "CENSUS-FILE" && $2 == "weird_size" { print $2, $3, $6, $7, $8, $9, $10 }' "$CENSUS")" check_eq xbitmaps/fixture-xlogo16 "xlogo16 xlogo16 16 16 unsigned-char 32 -" \ "$(awk '$1 == "CENSUS-FILE" && $2 == "xlogo16" { print $2, $3, $6, $7, $8, $9, $10 }' "$CENSUS")" check_eq xbitmaps/fixture-xsnow "xsnow xsnow 300 350 char 13300 -" \ "$(awk '$1 == "CENSUS-FILE" && $2 == "xsnow" { print $2, $3, $6, $7, $8, $9, $10 }' "$CENSUS")" # weird_size is the fixture that matters most: 7 is not a multiple of 8, so it # is the only file whose byte count is not simply width/8 * height, and a reader # that rounded the wrong way would be right about all 70 others. check_eq xbitmaps/fixture-weird-size-rounding 13 "$(( ((7 + 7) / 8) * 13 ))" # Both storage types are present. `char' and `unsigned char' differ in whether # the high bit is negative, which is why the probe's checksum reads the arrays # through unsigned char -- a suite that saw only one type would never exercise # the distinction. check_eq xbitmaps/storage-types "66 char / 5 unsigned-char" \ "$(awk '$1 == "CENSUS-FILE" { n[$8]++ } END { printf "%d char / %d unsigned-char", n["char"], n["unsigned-char"] }' "$CENSUS")" # The nine cursors that carry a hotspot, and the one that declares -1,-1 -- # XReadBitmapFile returns a hotspot only when both coordinates are present, so # a file that lost one would silently lose its hotspot rather than fail. check_eq xbitmaps/hotspots \ "cntr_ptr@7,1 left_ptr@3,1 opendot@7,7 opendotMask@7,7 plaid@-1,-1 right_ptr@12,1 sipb@12,16 star@7,7 starMask@7,7" \ "$(awk '$1 == "CENSUS-FILE" && $10 != "-" { printf "%s@%s ", $2, $10 }' "$CENSUS" | sed 's/ $//')" # ------------- 8. THE PASS CRITERION: this arm against the build host, exactly # # do_install writes the probe 0755 but the rootfs is read-only at run time, so # it arrives non-executable where it sits and is copied to /tmp, which is a # mode=1777 tmpfs with no noexec. probe=$t/xbitmaps-probe if cp "$ST/xbitmaps-probe" "$probe" 2>/dev/null && chmod +x "$probe" 2>/dev/null; then bst_ok xbitmaps/probe-staged # bst_probe rather than a plain run: a probe that does not return would # otherwise take the suite with it at the runner's bound, and the transcript # would die with the guest's tmpfs. bst_probe xbitmaps/probe-runs "$t/probe.out" 600 "$probe" prc=$? if [ "$prc" -eq 0 ]; then # It reached its end. Without this, a run truncated part-way would present # a short line set, and cmp against a reference would red for a reason # nobody could tell apart from a data difference. check xbitmaps/probe-complete grep -qx "XBM-TOTAL $NCOMPILABLE" "$t/probe.out" check_eq xbitmaps/probe-line-count "$(( NCOMPILABLE + 1 ))" \ "$(wc -l < "$t/probe.out" | tr -d ' ')" # THE COMPARISON. 69 lines of stem, width, height, sizeof(bits) and a # Fletcher sum over the bytes, target wasm32 against the x86-64 build host, # from one generated source over one set of headers. Nothing in it can # differ unless the data differs. if cmp -s "$t/probe.out" "$REF"; then bst_ok xbitmaps/probe-matches-buildhost else bst_notok xbitmaps/probe-matches-buildhost \ "the target probe and the build-host reference disagree; first difference: $(diff "$REF" "$t/probe.out" 2>/dev/null | head -n 4 | tr '\n' ' ')" fi # Named spot checks, so a red carries a readable bitmap rather than only a # byte offset. The Fletcher sums are literals: they are a fact about the # bytes and must not move. check_out xbitmaps/probe-spot-xlogo16 "XBM xlogo16 xlogo16 16 16 32 2611087558 -" cat "$t/probe.out" check_out xbitmaps/probe-spot-calculator "XBM calculator icon 28 48 192 4073543974 -" cat "$t/probe.out" check_out xbitmaps/probe-spot-weird-size "XBM weird_size weird_size 7 13 13 251134547 -" cat "$t/probe.out" # The probe's dimensions agree with the awk reader's, which read the source # files rather than the compiled-in arrays. This is the end-to-end join: the # bytes on disk, the bytes the compiler saw, and the bytes the build host # saw are all the same bytes. # Stem, width, height, array length AND the Fletcher sum over the bytes. # Including the sum is what makes this the join it is described as: the # digest case above compares the rootfs against a manifest the recipe wrote # in the same breath as the payload, so a payload and a manifest rewritten # TOGETHER pass it. Nothing can rewrite the probe, which carries the bytes # the compiler saw, compiled in. Measured: with the sum left out, a single # flipped byte in one bitmap reds exactly one case in this whole suite. grep '^XBM ' "$t/probe.out" | awk '{ print $2, $3, $4, $5, $6, $7 }' | LC_ALL=C sort > "$t/probe.dim" grep '^XBM-AWK ' "$AWKOUT" | awk '{ print $2, $3, $4, $5, $7, $9 }' | LC_ALL=C sort > "$t/awk.dim" # LC_ALL=C on the comm as well as on the sorts that fed it. comm validates # its inputs' order in the CURRENT locale and warns to stderr when that # disagrees with how they were sorted -- and a stray line on a suite's # stdout is not a harmless warning here: the runner counts result lines, so # it lands as an uncounted extra and the verdict survives while the # arithmetic around it does not. LC_ALL=C comm -13 "$t/awk.dim" "$t/probe.dim" > "$t/dim.only-probe" check_eq xbitmaps/probe-agrees-with-source "" "$(cat "$t/dim.only-probe" | tr '\n' ' ')" else bst_skip xbitmaps/probe-complete "the probe did not run to completion (rc=$prc); its output is not a result" bst_skip xbitmaps/probe-matches-buildhost "no complete probe output to compare" fi else bst_notok xbitmaps/probe-staged "cannot copy $ST/xbitmaps-probe to $t and make it executable" fi # ------------------------------------------------------- 9. the .pc # # xbitmaps.pc is what a consumer's PKG_CHECK_MODULES resolves, and it is # generated by configure from xbitmaps.pc.in. if command -v pkg-config >/dev/null 2>&1; then check_eq xbitmaps/pc-modversion "$PV" "$(pkg-config --modversion xbitmaps 2>&1)" # PKG_CONFIG_ALLOW_SYSTEM_CFLAGS for the same reason 57-spice-protocol sets # it: pkg-config suppresses an -I naming a directory already on the # compiler's system include path, and /usr/include IS such a directory here -- # so without the flag the answer is the empty string and the case would be # about pkg-config's output policy rather than about the .pc's arithmetic. # The trailing space is pkg-config's own and is trimmed rather than tolerated. check_eq xbitmaps/pc-cflags "-I/usr/include" \ "$(PKG_CONFIG_ALLOW_SYSTEM_CFLAGS=1 pkg-config --cflags xbitmaps 2>&1 | sed 's/[[:space:]]*$//')" # Libs is empty upstream and must stay empty: this package has no library, and # a Libs line would put a link flag into every consumer for a thing that does # not exist. check_eq xbitmaps/pc-libs "" "$(pkg-config --libs xbitmaps 2>&1 | sed 's/[[:space:]]*$//')" else bst_skip xbitmaps/pc-modversion "no pkg-config on this image" fi check xbitmaps/pc-installed test -s "$PCD/xbitmaps.pc" check xbitmaps/pc-version grep -qx "Version: $PV" "$PCD/xbitmaps.pc" # The .pc must name no libdir, no architecture and no unsubstituted template # variable -- it is metadata for a package of architecture-independent data, and # it is checked here on the image, where a rootfs assembled from a stale .deb # would show a different answer than the recipe did. if grep -qE '^libdir=|/usr/lib|wasm32|@[A-Za-z_]*@' "$PCD/xbitmaps.pc"; then bst_notok xbitmaps/pc-arch-neutral \ "xbitmaps.pc names a libdir, an arch token or an unsubstituted variable: $(_bst_1line "$(cat "$PCD/xbitmaps.pc")")" else bst_ok xbitmaps/pc-arch-neutral fi # --------------------------- 10. the package, as the image's own database sees it # # ${PN} carries nothing -- ${includedir} and ${datadir}/pkgconfig are both routed # to ${PN}-dev by bitbake.conf -- and an empty package with no ALLOW_EMPTY is # never written at all. So what an image installs is xbitmaps-dev, and naming # plain `xbitmaps' in IMAGE_INSTALL would fail do_rootfs. Both halves are # asserted: the -dev package is here, and the parent is NOT, because a build # that started emitting an empty parent would change what IMAGE_INSTALL should # say. The same shape is already on this image as nanopb-runtime-dev. if command -v dpkg >/dev/null 2>&1; then if dpkg -s xbitmaps-dev >/dev/null 2>&1; then bst_ok xbitmaps/pkg-dev-installed else bst_notok xbitmaps/pkg-dev-installed "dpkg does not know xbitmaps-dev" fi check_eq xbitmaps/pkg-version "$PKGVER" \ "$(dpkg -s xbitmaps-dev 2>/dev/null | sed -n 's/^Version: //p')" if dpkg -s xbitmaps >/dev/null 2>&1; then bst_notok xbitmaps/pkg-parent-absent \ "dpkg knows a package called xbitmaps. It carries no files -- everything this recipe installs is routed to -dev -- so an empty parent being written means the packaging changed and IMAGE_INSTALL should be revisited." else bst_ok xbitmaps/pkg-parent-absent fi # The architecture the package actually declares, MEASURED. It is this arm's, # not `all': meta-oe's xorg-data-common.inc does not inherit allarch, so the # payload being architecture-independent and the PACKAGE being architecture- # independent are two different claims and only the first one is true here. check_eq xbitmaps/pkg-architecture "wasm32" \ "$(dpkg -s xbitmaps-dev 2>/dev/null | sed -n 's/^Architecture: //p')" # What dpkg believes the package owns, against what CENSUS says it installed. # This is the third independent view of the same set -- the recipe's manifest, # the directory listing, and now the package database -- and it is the one # that would catch a rootfs assembled from a different .deb than the one this # image's CENSUS came from. DPKGSET=$t/dpkg.set dpkg -L xbitmaps-dev 2>/dev/null | sed -n "s|^$BM/||p" | LC_ALL=C sort > "$DPKGSET" if cmp -s "$DECL" "$DPKGSET"; then bst_ok xbitmaps/pkg-file-list else bst_notok xbitmaps/pkg-file-list \ "dpkg -L xbitmaps-dev and CENSUS disagree -- only in CENSUS: $(LC_ALL=C comm -23 "$DECL" "$DPKGSET" | tr '\n' ' '); only in dpkg: $(LC_ALL=C comm -13 "$DECL" "$DPKGSET" | tr '\n' ' ')" fi # The .pc is the one non-bitmap file the package owns. Named, so that a # packaging change that moved it under libdir is a red here. check_out xbitmaps/pkg-owns-pc "$PCD/xbitmaps.pc" dpkg -L xbitmaps-dev else bst_skip xbitmaps/pkg-dev-installed "no dpkg on this image" fi # ------------------------------------- 11. nothing architecture-specific ships # # The reader in section 4 already established that every installed bitmap is C # source text -- neither \177ELF nor \0asm can open a #define or a /* -- so this # is the other half: the package puts nothing under libdir at all. The probe is # a wasm module and IS architecture-specific, which is why it lives in its own # xbitmaps-tests package and not in the payload one. check_eq xbitmaps/no-libdir-payload "" \ "$(dpkg -L xbitmaps-dev 2>/dev/null | grep '^/usr/lib' | tr '\n' ' ')" rm -rf "$t" 2>/dev/null