galeb

Једноставна статичка дистрибуција заснована на musl-у
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 2c8c1df9b920777197d53f2a9a75c934652c0813
родитељ d89a12dd8c4c719b209036395eef469ce8c8c36d
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sun, 10 Jul 2022 22:13:19 +0200

Chroot up to Python3; lib/gensums,lib/showpkgs: New scripts

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
M01-cross.sh | 52+++++++++++++++++++++++++++++++++-------------------
M02-prep-chroot.sh | 6+++---
M03-chroot.sh | 488++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Afil/elfutils-void/error.h | 27+++++++++++++++++++++++++++
Afil/musl-legacy-compat-void/cdefs.h | 29+++++++++++++++++++++++++++++
Afil/musl-legacy-compat-void/queue.h | 846+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afil/musl-legacy-compat-void/tree.h | 761+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/fun.sh | 17+++++++----------
Alib/gensums | 37+++++++++++++++++++++++++++++++++++++
Mlib/pkgs.tsv | 133+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Alib/showpkgs | 12++++++++++++
Apat-11.2.1/libffi-alpine/pax-dlmmap.patch | 120+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apat-11.2.1/python3-void/musl-find_library.patch | 44++++++++++++++++++++++++++++++++++++++++++++
Apat-11.2.1/python3-void/tweak-MULTIARCH-for-powerpc-linux-musl.patch | 13+++++++++++++
Apat-11.2.1/xz-alpine/xzgrep-ZDI-CAN-16587.patch | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
измењених датотека: 15, додавања: 2530(+), брисања: 149(-)

diff --git a/01-cross.sh b/01-cross.sh @@ -52,29 +52,43 @@ cp_or_fail -r ${WD}/${FLD}/* ${G_FIL}/ msg info "Copying patches to %s" ${G_PAT} cp_or_fail -r ${WD}/${PTD}/* ${G_PAT}/ -msg info "Fetching packages" -sed 1d ${WD}/lib/pkgs.tsv | \ +msg info "Fetching packages and checking MD5 sums" +lineno=0 +totallines=$(wc -l ${WD}/lib/pkgs.tsv | cut -d ' ' -f1) +totallines=$((totallines - 1)) while read -r record do -( + perc=$((lineno * 100 / totallines)) + printf "%3d%%\r" "${perc}" + [ ${lineno} -eq 0 ] || \ + ( delay=2 # seconds between downloads; customize rate limiting - IFS=$(printf '\t') - cn=0 - for column in ${record}; do - case ${cn} in - 0) url=${column};; - 1) dir=${column};; - *) ;; - esac - cn=$((cn+1)) - done + url=$(printf "${record}" | cut -d "$(printf '\t')" -f1) + dirtb=$(printf "${record}" | cut -sd "$(printf '\t')" -f2) + md5=$(printf "${record}" | cut -sd "$(printf '\t')" -f3) + + tarball=${url##*/} + if [ -n "${dirtb}" ]; then + tarball=${dirtb} + fi + case ${url} in - git:*|git+https:*) git_clone "${dir}" ${url##git+} ${delay};; - https:*) fetch_pkg ${url} "${dir}" ${delay};; + git:*|git+https:*) git_clone "${dirtb}" ${url##git+} ${delay};; + https:*) fetch_pkg ${url} "${dirtb}" ${delay};; *) ;; esac -) -done + if [ -n "${md5}" ]; then + if ! printf "%s %s" "${md5}" "${G_PKG}/${tarball}" | \ + md5sum -c - >/dev/null 2>&1; then + msg err "MD5 check failed on %s" ${tarball} + exit 1 + fi + fi + ) || exit 1 + lineno=$((lineno+1)) +done <${WD}/lib/pkgs.tsv +echo +unset lineno begin_substep linux-5.17.13 "Linux headers" if [ -e ${CT}/${G_TARGET}/include/linux/stddef.h ]; then @@ -358,7 +372,7 @@ SPECFILE=$(realpath $(dirname $(${G_TARGET}-gcc -print-libgcc-file-name)))/specs msg info "Specfile at %s" "${SPECFILE}" ${G_TARGET}-gcc -dumpspecs > specs /bin/sed -i 's,:\(/lib/ld-musl-'${G_ARCH_EXT_ALT}'.so.1\),:/'${TLD}'\1,g' specs -cat specs >>${G_LOG} +cat specs >>${G_LOGFILE} mv_or_fail specs ${SPECFILE} unset SPECFILE @@ -574,7 +588,7 @@ SPECFILE=$(realpath $(dirname $(${G_TARGET}-gcc -print-libgcc-file-name)))/specs msg info "Specfile at %s" "${SPECFILE}" ${G_TARGET}-gcc -dumpspecs > specs /bin/sed -i 's,:\(/lib/ld-musl-'${G_ARCH_EXT_ALT}'.so.1\),:/'${TLD}'\1,g' specs -cat specs >>${G_LOG} +cat specs >>${G_LOGFILE} mv_or_fail specs ${SPECFILE} unset SPECFILE diff --git a/02-prep-chroot.sh b/02-prep-chroot.sh @@ -143,11 +143,11 @@ cp_or_fail ${WD}/lib/env.sh ${G_LIB}/env.sh cp_or_fail ${WD}/lib/fun.sh ${G_LIB}/fun.sh msg warn "Next run 03-chroot.sh" -msg query "Run as root [y/N]?" +msg query "Run as root [Y/n]?" read -r run_as_root case "${run_as_root}" in - y|Y) chroot ${GR} /${TLD}/bin/mksh -l +h;; - *) chroot --userspec=${GUID}:${GGID} ${GR} /${TLD}/bin/mksh -l +h;; + n|N) chroot --userspec=${GUID}:${GGID} ${GR} /${TLD}/bin/mksh -l +h;; + *) chroot ${GR} /${TLD}/bin/mksh -l +h;; esac umount ${GR}/tmp diff --git a/03-chroot.sh b/03-chroot.sh @@ -1675,7 +1675,7 @@ XML/Parser.pm ${pkg} elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then unpack_pkg ${pkg} / else - extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.gz + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.gz touch ( cd_or_fail ${G_SRC}/${pkg} @@ -1768,11 +1768,11 @@ mkpk_install() ./configure --prefix=/sucks make ${JN} || exit 1 - make install + make install DESTDIR=/build } ! mkpk ${pkg} - #unpack_pkg ${pkg} / + unpack_pkg ${pkg} / ) || exit 1 remove_dir ${G_SRC}/${pkg} fi @@ -1837,11 +1837,6 @@ mkpk_install() DESTDIR=/build export CFLAGS LDFLAGS DESTDIR - touch configure.ac - touch Makefile.in - touch aclocal.m4 - touch configure - ./configure --prefix=/sucks --docdir=/sucks/share/doc/${pkg} make ${JN} || exit 1 @@ -1879,7 +1874,6 @@ mkpk_install() export CFLAGS LDFLAGS DESTDIR sed -i '/pkgconfig_DATA/i pkgconfigdir=/lib/pkgconfig' Makefile.am - mkdir m4 ./bootstrap.sh ./configure --prefix=/ --sysconfdir=/etc --localstatedir=/var @@ -1895,6 +1889,438 @@ mkpk_install() fi end_substep +begin_substep musl-obstack-1.1 +if [ -e /lib/libobstack.a ]; then + msg info "%s exists, skipping %s" /lib/libobstack.a ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.gz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.gz + ( + cd_or_fail ${G_SRC}/${pkg} + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe -fPIC' + LDFLAGS= + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + sed -i '/pkgconfig_DATA/i pkgconfigdir=/lib/pkgconfig' Makefile.am + ./bootstrap.sh + + ./configure --prefix=/ --sysconfdir=/etc --localstatedir=/var + + make ${JN} || exit 1 + make install-strip +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep xz-5.2.5 +if [ -e /bin/xz ]; then + msg info "%s exists, skipping %s" /bin/xz ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.xz + ( + cd_or_fail ${G_SRC}/${pkg} + + apply_patch final-system -Np1 -i \ + ${G_PAT}/xz-alpine/xzgrep-ZDI-CAN-16587.patch + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe -static --static -fcommon' + LDFLAGS='-static --static -fcommon' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + ./configure --prefix=/ --docdir=/share/doc/${pkg} + + make ${JN} || exit 1 + make install-strip +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep kmod-29 +if [ -e /bin/kmod ]; then + msg info "%s exists, skipping %s" /bin/kmod ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.xz + ( + cd_or_fail ${G_SRC}/${pkg} + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe -static --static -fcommon' + LDFLAGS='-static --static -fcommon' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + ./configure --prefix=/ \ + --sysconfdir=/etc \ + --with-xz \ + --with-zlib \ + --with-zstd + + make ${JN} || exit 1 + make install-strip + + for p in depmod insmod lsmod modinfo modprobe rmmod + do + ln -sfv kmod /build/bin/\$p + done +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep gettext-tiny-0.3.2 +if [ -e /bin/msgfmt ]; then + msg info "%s exists, skipping %s" /bin/msgfmt ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.xz + ( + cd_or_fail ${G_SRC}/${pkg} + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + cat <<@ >config.mak +CFLAGS=-O3 -march=native -mtune=native -pipe -static --static -fcommon +LDFLAGS=-static --static -fcommon +@ + sed -i 's,/usr/local,,g' Makefile + make LIBINTL=MUSL ${JN} || exit 1 + make LIBINTL=MUSL DESTDIR=/build prefix=/ install +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep musl-legacy-compat-20220710 +if [ -e /include/sys/cdefs.h ]; then + msg info "%s exists, skipping %s" /include/sys/cdefs.h ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + check_dir ${G_SRC}/${pkg} + cp_or_fail -r "${G_FIL}/musl-legacy-compat-void" ${G_SRC}/${pkg}/ + ( + cd_or_fail ${G_SRC}/${pkg} + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + for h in cdefs queue tree + do + install -Dm 644 musl-legacy-compat-void/\$h.h \ + /build/include/sys/\$h.h + done +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep argp-standalone-1.4.1 +if [ -e /lib/libargp.a ]; then + msg info "%s exists, skipping %s" /lib/libargp.a ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg "${G_SRC}" "${pkg}" "${pkg}.tar.gz" + ( + cd_or_fail ${G_SRC}/${pkg} + apply_patch final-system -Np1 -i \ + ${G_PAT}/argp-standalone-adelie/gnu89-inline.patch + apply_patch final-system -Np1 -i \ + ${G_PAT}/argp-standalone-mlfs/\ +generate_configure_script.patch + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + chmod +x configure + + CFLAGS='-O3 -march=native -mtune=native -pipe -fPIC' \\ + ./configure --prefix=/ \\ + --sysconfdir=/etc \\ + --localstatedir=/var + make ${JN} || exit 1 + + mkdir -p /build/lib + mkdir -p /build/include + + cp libargp.a /build/lib + cp argp.h /build/include +} +! + mkpk ${pkg} + remove_dir ${G_SRC}/${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep libelf-0.186 +if [ -e /sucks/lib/libelf-0.186.so ]; then + msg info "%s exists, skipping %s" /sucks/lib/libelf-0.186.so ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} elfutils-0.186 ${pkg}.tar.bz2 ${pkg} + ( + cd_or_fail ${G_SRC}/${pkg} + cp_or_fail ${G_FIL}/elfutils-void/error.h lib/ + cp_or_fail ${G_FIL}/elfutils-void/error.h src/ + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe' + CFLAGS+=' -DFNM_EXTMATCH=0 -Wno-error -Wno-error=null-dereference' + CFLAGS+=' -Wl,-z,stack-size=2097152' + LDFLAGS='' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + autoreconf -vif + + ./configure --prefix=/sucks \ + --disable-debuginfod \ + --enable-libdebuginfod=dummy + + make ${JN} -C lib || exit 1 + make ${JN} -C libelf || exit 1 + make -C libelf DESTDIR=\${DESTDIR} install + + mkdir -p /build/sucks/lib/pkgconfig + install -vm644 config/libelf.pc /build/sucks/lib/pkgconfig/ +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep libffi-3.4.2 +if [ -e /sucks/lib/libffi.so.8.1.0 ]; then + msg info "%s exists, skipping %s" /sucks/lib/libffi.so.8.1.0 ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.gz + ( + cd_or_fail ${G_SRC}/${pkg} + + apply_patch final-system -Np1 -i \ + ${G_PAT}/libffi-alpine/pax-dlmmap.patch + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe' + LDFLAGS='' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + ./configure --prefix=/sucks \ + --disable-static \ + --includedir=/sucks/include \ + --disable-multi-os-directory \ + --with-pic + + make ${JN} || exit 1 + make install +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +# LibreSSL doesn't suck, even though technically IMHO it should belong in /sucks +# since currently I don't see a clear way to produce both static and dynamic +# libraries while keeping binaries static +begin_substep libressl-3.4.2 +if [ -e /lib/libssl.a ]; then + msg info "%s exists, skipping %s" /lib/libssl.a ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.gz + ( + cd_or_fail ${G_SRC}/${pkg} + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe' + LDFLAGS='' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + autoreconf -vif + + ./configure --prefix=/ \ + --sysconfdir=/etc \ + --mandir=/share/man \ + --localstatedir=/var + + make ${JN} || exit 1 + make install-strip +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + +begin_substep Python-3.9.9 +if [ -x /sucks/bin/python3 ]; then + msg info "%s exists, skipping %s" /sucks/bin/python3 ${pkg} +elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then + unpack_pkg ${pkg} / +else + extract_pkg ${G_SRC} ${pkg} ${pkg}.tar.xz + ( + cd_or_fail ${G_SRC}/${pkg} + + apply_patch final-system -Np0 -i \ + ${G_PAT}/python3-void/musl-find_library.patch + apply_patch final-system -Np0 -i \ + ${G_PAT}/python3-void/tweak-MULTIARCH-for-powerpc-\ +linux-musl.patch + + remove_dir Modules/expat + remove_dir Modules/_ctypes/darwin + remove_dir Modules/_ctypes/libffi + + cat <<! >MKPK +mkpk_name() +{ + printf "%s" "${pkg}" +} + +mkpk_install() +{ + CFLAGS='-O3 -march=native -mtune=native -pipe' + LDFLAGS='' + DESTDIR=/build + export CFLAGS LDFLAGS DESTDIR + + ./configure --prefix=/sucks \ + --enable-shared \ + --with-system-expat \ + --with-system-ffi \ + --with-ensurepip=yes \ + --enable-ipv6 \ + --with-threads \ + --enable-loadable-sqlite-extensions \ + --with-computed-gotos + + make ${JN} || exit 1 + make install + + chmod 755 /build/sucks/lib/libpython3.9.so + + ln -sv python3.9 /build/sucks/bin/python + ln -sv python3.9-config /build/sucks/bin/python-config + ln -sv idle3.9 /build/sucks/bin/idle + ln -sv pydoc3.9 /build/sucks/bin/pydoc + ln -sv python3.9.1 /build/sucks/share/man/man1/python.1 +} +! + mkpk ${pkg} + unpack_pkg ${pkg} / + ) || exit 1 + remove_dir ${G_SRC}/${pkg} +fi +end_substep + if false; then # Needs CMake (BMLFS) begin_substep musl-locales-20220708 @@ -2000,49 +2426,5 @@ fi end_substep # Move after autotools -begin_substep argp-standalone-1.4.1 -if [ -x /bin/argp ]; then - msg info "%s exists, skipping %s" /bin/pkg-config ${pkg} -elif [ -e ${G_SPKG}/${pkg}.tar.xz ]; then - unpack_pkg ${pkg} / -else - extract_pkg "${G_SRC}" "${pkg}" "${pkg}.tar.gz" - ( - cd_or_fail ${G_SRC}/${pkg} - apply_patch final-system -Np1 -i \ - ${G_PAT}/argp-standalone-adelie/gnu89-inline.patch - apply_patch final-system -Np1 -i \ - ${G_PAT}/argp-standalone-mlfs/\ -generate_configure_script.patch - cat <<! >MKPK -mkpk_name() -{ - printf "%s" "${pkg}" -} - -mkpk_install() -{ - chmod +x configure - - CFLAGS='-O3 -march=native -mtune=native -pipe -fPIC' \\ - ./configure --prefix=/ \\ - --sysconfdir=/etc \\ - --localstatedir=/var - make ${JN} || exit 1 - - mkdir -p /build/lib - mkdir -p /build/include - - cp libargp.a /build/lib - cp argp.h /build/include -} -! - mkpk ${pkg} - remove_dir ${G_SRC}/${pkg} - unpack_pkg ${pkg} / - ) || exit 1 - remove_dir ${G_SRC}/${pkg} -fi -end_substep fi end_step diff --git a/fil/elfutils-void/error.h b/fil/elfutils-void/error.h @@ -0,0 +1,27 @@ +#ifndef _ERROR_H_ +#define _ERROR_H_ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +static unsigned int error_message_count = 0; + +static inline void error(int status, int errnum, const char* format, ...) +{ + va_list ap; + fprintf(stderr, "%s: ", program_invocation_name); + va_start(ap, format); + vfprintf(stderr, format, ap); + va_end(ap); + if (errnum) + fprintf(stderr, ": %s", strerror(errnum)); + fprintf(stderr, "\n"); + error_message_count++; + if (status) + exit(status); +} + +#endif /* _ERROR_H_ */ diff --git a/fil/musl-legacy-compat-void/cdefs.h b/fil/musl-legacy-compat-void/cdefs.h @@ -0,0 +1,29 @@ +#warning usage of non-standard #include <sys/cdefs.h> is deprecated + +#undef __P +#undef __PMT + +#define __P(args) args +#define __PMT(args) args + +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x + +#ifdef __cplusplus +# define __BEGIN_DECLS extern "C" { +# define __END_DECLS } +#else +# define __BEGIN_DECLS +# define __END_DECLS +#endif + +#if defined(__GNUC__) && !defined(__cplusplus) +# define __THROW __attribute__ ((__nothrow__)) +# define __NTH(fct) __attribute__ ((__nothrow__)) fct +#else +# define __THROW +# define __NTH(fct) fct +#endif + +#define __CONCAT(x,y) x ## y +#define __STRING(x) #x diff --git a/fil/musl-legacy-compat-void/queue.h b/fil/musl-legacy-compat-void/queue.h @@ -0,0 +1,846 @@ +/* $NetBSD: queue.h,v 1.68 2014/11/19 08:10:01 uebayasi Exp $ */ + +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * Include the definition of NULL only on NetBSD because sys/null.h + * is not available elsewhere. This conditional makes the header + * portable and it can simply be dropped verbatim into any system. + * The caveat is that on other systems some other header + * must provide NULL before the macros can be used. + */ +#ifdef __NetBSD__ +#include <sys/null.h> +#endif + +#if defined(QUEUEDEBUG) +# if defined(_KERNEL) +# define QUEUEDEBUG_ABORT(...) panic(__VA_ARGS__) +# else +# include <err.h> +# define QUEUEDEBUG_ABORT(...) err(1, __VA_ARGS__) +# endif +#endif + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List access methods. + */ +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_END(head) NULL +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; \ + (var) != SLIST_END(head); \ + (var) = (var)->field.sle_next) + +#define SLIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = SLIST_FIRST((head)); \ + (var) != SLIST_END(head) && \ + ((tvar) = SLIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = SLIST_END(head); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_AFTER(slistelm, field) do { \ + (slistelm)->field.sle_next = \ + SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods. + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var) != LIST_END(head); \ + (var) = ((var)->field.le_next)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) != LIST_END(head) && \ + ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_MOVE(head1, head2) do { \ + LIST_INIT((head2)); \ + if (!LIST_EMPTY((head1))) { \ + (head2)->lh_first = (head1)->lh_first; \ + LIST_INIT((head1)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * List functions. + */ +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + if (*(elm)->field.le_prev != (elm)) \ + QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = LIST_END(head); \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != \ + LIST_END(head)) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_END(head) NULL +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head)) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var) != SIMPLEQ_END(head); \ + (var) = ((var)->field.sqe_next)) + +#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->sqh_first); \ + (var) != SIMPLEQ_END(head) && \ + ((next = ((var)->field.sqe_next)), 1); \ + (var) = (next)) + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \ + if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \ + == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_CONCAT(head1, head2) do { \ + if (!SIMPLEQ_EMPTY((head2))) { \ + *(head1)->sqh_last = (head2)->sqh_first; \ + (head1)->sqh_last = (head2)->sqh_last; \ + SIMPLEQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_LAST(head, type, field) \ + (SIMPLEQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->sqh_last) - offsetof(struct type, field)))) + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { TAILQ_END(head), &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue access methods. + */ +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) (NULL) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head)) + + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var) != TAILQ_END(head); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_SAFE(var, head, field, next) \ + for ((var) = ((head)->tqh_first); \ + (var) != TAILQ_END(head) && \ + ((next) = TAILQ_NEXT(var, field), 1); (var) = (next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\ + (var) != TAILQ_END(head); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var) != TAILQ_END(head) && \ + ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev)) + +/* + * Tail queue functions. + */ +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \ + if ((head)->tqh_first && \ + (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \ + QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \ + if (*(head)->tqh_last != NULL) \ + QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_OP(elm, field) \ + if ((elm)->field.tqe_next && \ + (elm)->field.tqe_next->field.tqe_prev != \ + &(elm)->field.tqe_next) \ + QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + if (*(elm)->field.tqe_prev != (elm)) \ + QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \ + if ((elm)->field.tqe_next == NULL && \ + (head)->tqh_last != &(elm)->field.tqe_next) \ + QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\ + (head), (elm), __FILE__, __LINE__); +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \ + (elm)->field.tqe_next = (void *)1L; \ + (elm)->field.tqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) +#define QUEUEDEBUG_TAILQ_OP(elm, field) +#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) +#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) +#endif + +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = TAILQ_END(head); \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \ + (elm)->field.tqe_next = TAILQ_END(head); \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \ + TAILQ_END(head)) \ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_TAILQ_OP((listelm), field) \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \ + QUEUEDEBUG_TAILQ_OP((elm), field) \ + if (((elm)->field.tqe_next) != TAILQ_END(head)) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \ + TAILQ_END(head)) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \ +} while (/*CONSTCOND*/0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_END(head) NULL +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) +#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head)) + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = STAILQ_FIRST((head)); \ + (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY((head)) ? \ + NULL : \ + ((struct type *)(void *) \ + ((char *)((head)->stqh_last) - offsetof(struct type, field)))) + + +#ifndef _KERNEL +/* + * Circular queue definitions. Do not use. We still keep the macros + * for compatibility but because of pointer aliasing issues their use + * is discouraged! + */ + +/* + * __launder_type(): We use this ugly hack to work around the the compiler + * noticing that two types may not alias each other and elide tests in code. + * We hit this in the CIRCLEQ macros when comparing 'struct name *' and + * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC + * 4.8) declare these comparisons as always false, causing the code to + * not run as designed. + * + * This hack is only to be used for comparisons and thus can be fully const. + * Do not use for assignment. + * + * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix + * this by changing the head/tail sentinal values, but see the note above + * this one. + */ +static __inline const void * __launder_type(const void *); +static __inline const void * +__launder_type(const void *__x) +{ + __asm __volatile("" : "+r" (__x)); + return __x; +} + +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \ + if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \ + (head)->cqh_first->field.cqe_prev != CIRCLEQ_ENDC(head)) \ + QUEUEDEBUG_ABORT("CIRCLEQ head forw %p %s:%d", (head), \ + __FILE__, __LINE__); \ + if ((head)->cqh_last != CIRCLEQ_ENDC(head) && \ + (head)->cqh_last->field.cqe_next != CIRCLEQ_ENDC(head)) \ + QUEUEDEBUG_ABORT("CIRCLEQ head back %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) \ + if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) { \ + if ((head)->cqh_last != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm last %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_next->field.cqe_prev != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm forw %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } \ + if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) { \ + if ((head)->cqh_first != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm first %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } else { \ + if ((elm)->field.cqe_prev->field.cqe_next != (elm)) \ + QUEUEDEBUG_ABORT("CIRCLEQ elm prev %p %s:%d", \ + (elm), __FILE__, __LINE__); \ + } +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) \ + (elm)->field.cqe_next = (void *)1L; \ + (elm)->field.cqe_prev = (void *)1L; +#else +#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) +#define QUEUEDEBUG_CIRCLEQ_ELM(head, elm, field) +#define QUEUEDEBUG_CIRCLEQ_POSTREMOVE(elm, field) +#endif + +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { CIRCLEQ_END(&head), CIRCLEQ_END(&head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = CIRCLEQ_END(head); \ + (head)->cqh_last = CIRCLEQ_END(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (listelm), field) \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = CIRCLEQ_END(head); \ + if ((head)->cqh_last == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + (elm)->field.cqe_next = CIRCLEQ_END(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + QUEUEDEBUG_CIRCLEQ_HEAD((head), field) \ + QUEUEDEBUG_CIRCLEQ_ELM((head), (elm), field) \ + if ((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ + QUEUEDEBUG_CIRCLEQ_POSTREMOVE((elm), field) \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != CIRCLEQ_ENDC(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != CIRCLEQ_ENDC(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +/* For comparisons */ +#define CIRCLEQ_ENDC(head) (__launder_type(head)) +/* For assignments */ +#define CIRCLEQ_END(head) ((void *)(head)) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) +#define CIRCLEQ_EMPTY(head) \ + (CIRCLEQ_FIRST(head) == CIRCLEQ_ENDC(head)) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == CIRCLEQ_ENDC(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == CIRCLEQ_ENDC(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) +#endif /* !_KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ diff --git a/fil/musl-legacy-compat-void/tree.h b/fil/musl-legacy-compat-void/tree.h @@ -0,0 +1,761 @@ +/* $NetBSD: tree.h,v 1.20 2013/09/14 13:20:45 joerg Exp $ */ +/* $OpenBSD: tree.h,v 1.13 2011/07/09 00:19:45 pirofti Exp $ */ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline __unused struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __unused __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) do {} while (/*CONSTCOND*/ 0) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_SAFE(x, name, head, y) \ + for ((x) = RB_MIN(name, head); \ + ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#define RB_FOREACH_REVERSE_FROM(x, name, y) \ + for ((x) = (y); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \ + for ((x) = RB_MAX(name, head); \ + ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \ + (x) = (y)) + +#endif /* _SYS_TREE_H_ */ diff --git a/lib/fun.sh b/lib/fun.sh @@ -162,15 +162,8 @@ exit_cleanup() extract_pkg() { - local prog parent_dir dir tarball realdir - - parent_dir=$1 - shift - dir=$1 - shift - tarball=$1 - shift - realdir=$1 + local prog parent_dir=$1 dir=$2 tarball=$3 realdir=$4 touch=$5 + local mopt cd_or_fail ${parent_dir} if [ -n "${realdir}" ] && [ -d "${realdir}" ]; then @@ -188,7 +181,11 @@ extract_pkg() *) msg err "Unsupported archive format" exit 1;; esac - if ! ${prog} "${G_PKG}/${tarball}" | tar -xmf -; then + mopt='' + if [ "${touch}" = "touch" ]; then + mopt=-m + fi + if ! ${prog} "${G_PKG}/${tarball}" | tar -x ${mopt} -f -; then msg err "Extracting %s failed" "${tarball}" exit 1 fi diff --git a/lib/gensums b/lib/gensums @@ -0,0 +1,37 @@ +#!/bin/sh + +. ./lib/env.sh + +pkgdb=./lib/pkgs.tsv + +sed 1q "${pkgdb}" >newfile +lineno=0 +while read -r record +do + [ ${lineno} -eq 0 ] || \ + ( + IFS=$(printf '\t') + url=$(printf "${record}" | cut -d "$(printf '\t')" -f1) + dirtb=$(printf "${record}" | cut -sd "$(printf '\t')" -f2) + md5=$(printf "${record}" | cut -sd "$(printf '\t')" -f3) + + tarball=${url##*/} + if [ -n "${dirtb}" ]; then + tarball=${dirtb} + fi + + case ${url} in + https:*) md5=$(md5sum ${G_PKG}/${tarball} | \ + cut -d ' ' -f1);; + *) md5='';; + esac + if [ -n "${md5}" ]; then + printf "%s\t%s\t%s\n" "${url}" "${dirtb}" "${md5}" >>newfile + else + printf "%s\t%s\n" "${url}" "${dirtb}" >>newfile + fi + ) + lineno=$((lineno+1)) +done <${pkgdb} + +mv newfile "${pkgdb}" diff --git a/lib/pkgs.tsv b/lib/pkgs.tsv @@ -1,70 +1,75 @@ -URL Directory +URL Directory/Tarball MD5 Sum git+https://github.com/mirbsd/mksh mksh-20220709 git+https://github.com/onetrueawk/awk awk-20220709 git://git.suckless.org/9base 9base-20220706 git://git.suckless.org/sbase sbase-20220709 git://git.suckless.org/ubase ubase-20220709 git://repo.or.cz/tinycc.git tinycc-20220708 -https://astron.com/pub/file/file-5.41.tar.gz -https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-2.46.tar.gz -https://dev.alpinelinux.org/archive/posixtz/posixtz-0.5.tar.xz -https://dev.gentoo.org/~xen0n/distfiles/pax-utils-1.3.4.tar.xz -https://distfiles.dereferenced.org/pkgconf/pkgconf-1.8.0.tar.xz -https://download.savannah.gnu.org/releases/acl/acl-2.3.1.tar.xz -https://download.savannah.gnu.org/releases/attr/attr-2.5.1.tar.gz -https://ftp.barfooze.de/pub/sabotage/tarballs/gettext-tiny-0.3.2.tar.xz -https://ftp.barfooze.de/pub/sabotage/tarballs/netbsd-curses-0.3.2.tar.xz -https://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.xz -https://ftp.gnu.org/gnu/automake/automake-1.16.4.tar.xz -https://ftp.gnu.org/gnu/bash/bash-5.1.tar.gz -https://ftp.gnu.org/gnu/binutils/binutils-2.38.tar.xz -https://ftp.gnu.org/gnu/coreutils/coreutils-9.1.tar.xz -https://ftp.gnu.org/gnu/diffutils/diffutils-3.8.tar.xz -https://ftp.gnu.org/gnu/findutils/findutils-4.9.0.tar.xz -https://ftp.gnu.org/gnu/gdbm/gdbm-1.20.tar.gz -https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.xz libgmp-6.2.1.tar.xz -https://ftp.gnu.org/gnu/gperf/gperf-3.1.tar.gz -https://ftp.gnu.org/gnu/grep/grep-3.7.tar.xz -https://ftp.gnu.org/gnu/gzip/gzip-1.12.tar.xz -https://ftp.gnu.org/gnu/help2man/help2man-1.49.2.tar.xz -https://ftp.gnu.org/gnu/inetutils/inetutils-2.1.tar.xz -https://ftp.gnu.org/gnu/libtool/libtool-2.4.6.tar.xz -https://ftp.gnu.org/gnu/m4/m4-1.4.19.tar.xz -https://ftp.gnu.org/gnu/make/make-4.3.tar.gz -https://ftp.gnu.org/gnu/mpc/mpc-1.2.1.tar.gz libmpc-1.2.1.tar.gz -https://ftp.gnu.org/gnu/mpfr/mpfr-4.1.0.tar.xz libmpfr-4.1.0.tar.xz -https://ftp.gnu.org/gnu/patch/patch-2.7.6.tar.xz -https://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz -https://ftp.gnu.org/gnu/sed/sed-4.8.tar.xz -https://ftp.gnu.org/gnu/tar/tar-1.34.tar.xz -https://ftp.gnu.org/gnu/texinfo/texinfo-6.8.tar.xz -https://gcc.gnu.org/pub/gcc/snapshots/11-20220101/gcc-11-20220101.tar.xz -https://git.sr.ht/~strahinja/sled/archive/v0.10.8.tar.gz sled-0.10.8.tar.gz -https://github.com/Mic92/iana-etc/releases/download/20210611/iana-etc-20210611.tar.gz -https://github.com/arsv/perl-cross/releases/download/1.4/perl-cross-1.4.tar.gz -https://github.com/ericonr/argp-standalone/archive/refs/tags/1.4.1.tar.gz argp-standalone-1.4.1.tar.gz -https://github.com/facebook/zstd/releases/download/v1.5.0/zstd-1.5.0.tar.gz -https://github.com/pullmoll/musl-fts/archive/v1.2.7.tar.gz musl-fts-1.2.7.tar.gz -https://github.com/pullmoll/musl-obstack/archive/v1.1.tar.gz musl-obstack-1.1.tar.gz -https://github.com/shadow-maint/shadow/releases/download/v4.11.1/shadow-4.11.1.tar.xz -https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.0.6.tar.gz zlib-ng-2.0.6.tar.gz -https://invisible-island.net/archives/byacc/byacc-20220128.tgz -https://invisible-island.net/archives/reflex/reflex-20210808.tgz -https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz -https://libisl.sourceforge.io/isl-0.24.tar.xz libisl-0.24.tar.xz -https://mandoc.bsd.lv/snapshots/mandoc-1.14.6.tar.gz -https://mandoc.bsd.lv/snapshots/mdocml-1.14.1.tar.gz -https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/man-pages-5.13.tar.xz -https://musl.libc.org/releases/musl-1.2.3.tar.gz -https://prdownloads.sourceforge.net/expat/expat-2.4.8.tar.xz -https://sourceforge.net/projects/psmisc/files/psmisc/psmisc-23.4.tar.xz -https://sourceforge.net/projects/tcl/files/Tcl/8.6.12/tcl8.6.12-src.tar.gz -https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz -https://tukaani.org/xz/xz-5.2.5.tar.xz -https://www.cpan.org/src/5.0/perl-5.32.1.tar.xz -https://www.greenwoodsoftware.com/less/less-590.tar.gz -https://www.iana.org/time-zones/repository/releases/tzcode2022a.tar.gz -https://www.iana.org/time-zones/repository/releases/tzdata2022a.tar.gz -https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.17.13.tar.xz -https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.17.13.tar.xz -https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-2.62.tar.xz +https://astron.com/pub/file/file-5.41.tar.gz 18233bb0a0089dfdc7dfbc93b96f231b +https://cpan.metacpan.org/authors/id/T/TO/TODDR/XML-Parser-2.46.tar.gz 80bb18a8e6240fcf7ec2f7b57601c170 +https://dev.alpinelinux.org/archive/posixtz/posixtz-0.5.tar.xz 80f8ae1df19dd28e1c8b192c6ea7b836 +https://dev.gentoo.org/~xen0n/distfiles/pax-utils-1.3.4.tar.xz b9cdbc70fdd4e377dcf17eeff28c5ade +https://distfiles.dereferenced.org/pkgconf/pkgconf-1.8.0.tar.xz 823212dc241793df8ff1d097769a3473 +https://download.savannah.gnu.org/releases/acl/acl-2.3.1.tar.xz 95ce715fe09acca7c12d3306d0f076b2 +https://download.savannah.gnu.org/releases/attr/attr-2.5.1.tar.gz ac1c5a7a084f0f83b8cace34211f64d8 +https://ftp.barfooze.de/pub/sabotage/tarballs/gettext-tiny-0.3.2.tar.xz 9ddf4d35636fa3beacd3627cc02723ff +https://ftp.barfooze.de/pub/sabotage/tarballs/netbsd-curses-0.3.2.tar.xz bff9cfda41ae25ea84bd8da6c674dcb7 +https://ftp.gnu.org/gnu/autoconf/autoconf-2.71.tar.xz 12cfa1687ffa2606337efe1a64416106 +https://ftp.gnu.org/gnu/automake/automake-1.16.4.tar.xz 86e8e682bd74e6390a016c4d9c11267c +https://ftp.gnu.org/gnu/bash/bash-5.1.tar.gz bb91a17fd6c9032c26d0b2b78b50aff5 +https://ftp.gnu.org/gnu/binutils/binutils-2.38.tar.xz 6e39cad1bb414add02b5b1169c18fdc5 +https://ftp.gnu.org/gnu/coreutils/coreutils-9.1.tar.xz 8b1ca4e018a7dce9bb937faec6618671 +https://ftp.gnu.org/gnu/diffutils/diffutils-3.8.tar.xz 6a6b0fdc72acfe3f2829aab477876fbc +https://ftp.gnu.org/gnu/findutils/findutils-4.9.0.tar.xz 4a4a547e888a944b2f3af31d789a1137 +https://ftp.gnu.org/gnu/gdbm/gdbm-1.20.tar.gz 006c19b8b60828fd6916a16f3496bd3c +https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.xz libgmp-6.2.1.tar.xz 0b82665c4a92fd2ade7440c13fcaa42b +https://ftp.gnu.org/gnu/gperf/gperf-3.1.tar.gz 9e251c0a618ad0824b51117d5d9db87e +https://ftp.gnu.org/gnu/grep/grep-3.7.tar.xz 7c9cca97fa18670a21e72638c3e1dabf +https://ftp.gnu.org/gnu/gzip/gzip-1.12.tar.xz 9608e4ac5f061b2a6479dc44e917a5db +https://ftp.gnu.org/gnu/help2man/help2man-1.49.2.tar.xz 0372898fbf054140d62385a79c5855f4 +https://ftp.gnu.org/gnu/inetutils/inetutils-2.1.tar.xz 4e7676d1980e57c7df665e5c5c3c1047 +https://ftp.gnu.org/gnu/libtool/libtool-2.4.6.tar.xz 1bfb9b923f2c1339b4d2ce1807064aa5 +https://ftp.gnu.org/gnu/m4/m4-1.4.19.tar.xz 0d90823e1426f1da2fd872df0311298d +https://ftp.gnu.org/gnu/make/make-4.3.tar.gz fc7a67ea86ace13195b0bce683fd4469 +https://ftp.gnu.org/gnu/mpc/mpc-1.2.1.tar.gz libmpc-1.2.1.tar.gz 9f16c976c25bb0f76b50be749cd7a3a8 +https://ftp.gnu.org/gnu/mpfr/mpfr-4.1.0.tar.xz libmpfr-4.1.0.tar.xz bdd3d5efba9c17da8d83a35ec552baef +https://ftp.gnu.org/gnu/patch/patch-2.7.6.tar.xz 78ad9937e4caadcba1526ef1853730d5 +https://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz e9557dd5b1409f5d7b37ef717c64518e +https://ftp.gnu.org/gnu/sed/sed-4.8.tar.xz 6d906edfdb3202304059233f51f9a71d +https://ftp.gnu.org/gnu/tar/tar-1.34.tar.xz 9a08d29a9ac4727130b5708347c0f5cf +https://ftp.gnu.org/gnu/texinfo/texinfo-6.8.tar.xz a91b404e30561a5df803e6eb3a53be71 +https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.4.2.tar.gz 18aa728e7947a30af3bb04243e4482aa +https://gcc.gnu.org/pub/gcc/snapshots/11-20220101/gcc-11-20220101.tar.xz 2d984314c9ad01d941358bcf3ec6b29e +https://git.sr.ht/~strahinja/sled/archive/v0.10.8.tar.gz sled-0.10.8.tar.gz 2a12c7eb0e6cb4f671299acb76753986 +https://github.com/Mic92/iana-etc/releases/download/20210611/iana-etc-20210611.tar.gz f2854be57fe281e3ffc7364984467d2f +https://github.com/arsv/perl-cross/releases/download/1.4/perl-cross-1.4.tar.gz 73c246c20766d027c3dc9f606418c22c +https://github.com/ericonr/argp-standalone/archive/refs/tags/1.4.1.tar.gz argp-standalone-1.4.1.tar.gz 7f391d52161e7fe8e8d3df4f850bc7ee +https://github.com/facebook/zstd/releases/download/v1.5.0/zstd-1.5.0.tar.gz a6eb7fb1f2c21fa80030a47993853e92 +https://github.com/libffi/libffi/releases/download/v3.4.2/libffi-3.4.2.tar.gz 294b921e6cf9ab0fbaea4b639f8fdbe8 +https://github.com/pullmoll/musl-fts/archive/v1.2.7.tar.gz musl-fts-1.2.7.tar.gz bce0b5de0cf2519a74fbfacead60369d +https://github.com/pullmoll/musl-obstack/archive/v1.1.tar.gz musl-obstack-1.1.tar.gz 185975cc117dba8e6158cce847ba44d5 +https://github.com/shadow-maint/shadow/releases/download/v4.11.1/shadow-4.11.1.tar.xz 5a95ec069aa91508167d02fecafaa912 +https://github.com/zlib-ng/zlib-ng/archive/refs/tags/2.0.6.tar.gz zlib-ng-2.0.6.tar.gz 4ba0da231291632799948c5568906ce4 +https://invisible-island.net/archives/byacc/byacc-20220128.tgz c861b313fb59857a5ca3475ce9d62c4e +https://invisible-island.net/archives/reflex/reflex-20210808.tgz 31ed4340e8b636cb2c1de2ad378a14e9 +https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz 12e517cac2b57a0121cda351570f1e63 +https://libisl.sourceforge.io/isl-0.24.tar.xz libisl-0.24.tar.xz fae030f604a9537adc2502990a8ab4d1 +https://mandoc.bsd.lv/snapshots/mandoc-1.14.6.tar.gz f0adf24e8fdef5f3e332191f653e422a +https://mandoc.bsd.lv/snapshots/mdocml-1.14.1.tar.gz 07db67f437ee894e7e4b18b305d53ca1 +https://mirrors.edge.kernel.org/pub/linux/docs/man-pages/man-pages-5.13.tar.xz 3ac24e8c6fae26b801cb87ceb63c0a30 +https://musl.libc.org/releases/musl-1.2.3.tar.gz a507ae4f7f20bcfe566d8eb65c1af73e +https://prdownloads.sourceforge.net/expat/expat-2.4.8.tar.xz 0584a7318a4c007f7ec94778799d72fe +https://sourceforge.net/projects/psmisc/files/psmisc/psmisc-23.4.tar.xz 8114cd4489b95308efe2509c3a406bbf +https://sourceforge.net/projects/tcl/files/Tcl/8.6.12/tcl8.6.12-src.tar.gz 87ea890821d2221f2ab5157bc5eb885f +https://sourceware.org/ftp/elfutils/0.186/elfutils-0.186.tar.bz2 libelf-0.186.tar.bz2 2c095e31e35d6be7b3718477b6d52702 +https://sourceware.org/pub/bzip2/bzip2-1.0.8.tar.gz 67e051268d0c475ea773822f7500d0e5 +https://tukaani.org/xz/xz-5.2.5.tar.xz aa1621ec7013a19abab52a8aff04fe5b +https://www.cpan.org/src/5.0/perl-5.32.1.tar.xz 7f104064b906ad8c7329ca5e409a32d7 +https://www.greenwoodsoftware.com/less/less-590.tar.gz f029087448357812fba450091a1172ab +https://www.iana.org/time-zones/repository/releases/tzcode2022a.tar.gz fdc790effd7b01d29837fb27b3e81672 +https://www.iana.org/time-zones/repository/releases/tzdata2022a.tar.gz 081662184f3b902f8e5d96816568432e +https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.17.13.tar.xz 1f0478b27e1ec649e33b6c3dc0f6a583 +https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.17.13.tar.xz 1f0478b27e1ec649e33b6c3dc0f6a583 +https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-2.62.tar.xz 342c7560ed2103899f6914d1de75a89f +https://www.kernel.org/pub/linux/utils/kernel/kmod/kmod-29.tar.xz e81e63acd80697d001c8d85c1acb38a0 +https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tar.xz 11d12076311563252a995201248d17e5 diff --git a/lib/showpkgs b/lib/showpkgs @@ -0,0 +1,12 @@ +#!/bin/sh +cols='' +if [ -n "$*" ]; then + cols="-c $*" +fi +total=$(wc -l lib/pkgs.tsv | cut -d ' ' -f1) +total=$((total-1)) +git=$(grep '^git' lib/pkgs.tsv | wc -l | cut -d ' ' -f1) +tarballs=$((total-git)) +{ printf "%d total packages (%d git repos, %d tarballs)\n" \ + "${total}" "${git}" "${tarballs}" +table -d "$(printf '\t')" ${cols} lib/pkgs.tsv -f 35:10:12; } | less -S diff --git a/pat-11.2.1/libffi-alpine/pax-dlmmap.patch b/pat-11.2.1/libffi-alpine/pax-dlmmap.patch @@ -0,0 +1,120 @@ +From 48d2e46528fb6e621d95a7fa194069fd136b712d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20B=C3=BChler?= <buehler@cert.uni-stuttgart.de> +Date: Wed, 7 Sep 2016 15:49:48 +0200 +Subject: [PATCH 1/2] dlmmap_locked always needs locking as it always modifies + execsize + +--- + src/closures.c | 13 ++++--------- + 1 file changed, 4 insertions(+), 9 deletions(-) + +diff --git a/src/closures.c b/src/closures.c +index 2e0ffb45..04d6e27f 100644 +--- a/src/closures.c ++++ b/src/closures.c +@@ -769,16 +769,11 @@ dlmmap (void *start, size_t length, int prot, + MREMAP_DUP and prot at this point. */ + } + +- if (execsize == 0 || execfd == -1) +- { +- pthread_mutex_lock (&open_temp_exec_file_mutex); +- ptr = dlmmap_locked (start, length, prot, flags, offset); +- pthread_mutex_unlock (&open_temp_exec_file_mutex); ++ pthread_mutex_lock (&open_temp_exec_file_mutex); ++ ptr = dlmmap_locked (start, length, prot, flags, offset); ++ pthread_mutex_unlock (&open_temp_exec_file_mutex); + +- return ptr; +- } +- +- return dlmmap_locked (start, length, prot, flags, offset); ++ return ptr; + } + + /* Release memory at the given address, as well as the corresponding + +From 7aad5f895e2dfdb79d2ef67e1b231d21063e6511 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Stefan=20B=C3=BChler?= <buehler@cert.uni-stuttgart.de> +Date: Wed, 7 Sep 2016 15:50:54 +0200 +Subject: [PATCH 2/2] ignore PaX EMUTRAMP flag; instead check for MPROTECT + +- code using ffi_closure_alloc doesn't necessarily generate gcc compatible trampolines; only those are allowed by PaX +- if MPROTECT is enabled use the same workaround as is used for SELinux (double mmap()) +--- + src/closures.c | 29 +++++++++++++---------------- + 1 file changed, 13 insertions(+), 16 deletions(-) + +diff --git a/src/closures.c b/src/closures.c +index 04d6e27f..babecc1a 100644 +--- a/src/closures.c ++++ b/src/closures.c +@@ -401,14 +401,15 @@ selinux_enabled_check (void) + + #endif /* !FFI_MMAP_EXEC_SELINUX */ + +-/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */ ++/* On PaX enable kernels that have MPROTECT enabled we can't use PROT_EXEC. */ + #ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX + #include <stdlib.h> + +-static int emutramp_enabled = -1; ++/* -1: not read yet; 0: no PaX or MPROTECT disabled; 1: MPROTECT enabled. */ ++static int mprotect_enabled = -1; + + static int +-emutramp_enabled_check (void) ++mprotect_enabled_check (void) + { + char *buf = NULL; + size_t len = 0; +@@ -422,9 +423,7 @@ emutramp_enabled_check (void) + while (getline (&buf, &len, f) != -1) + if (!strncmp (buf, "PaX:", 4)) + { +- char emutramp; +- if (sscanf (buf, "%*s %*c%c", &emutramp) == 1) +- ret = (emutramp == 'E'); ++ ret = (NULL != strchr (buf + 4, 'M')); + break; + } + free (buf); +@@ -432,8 +431,9 @@ emutramp_enabled_check (void) + return ret; + } + +-#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \ +- : (emutramp_enabled = emutramp_enabled_check ())) ++#define is_mprotect_enabled() (mprotect_enabled >= 0 ? mprotect_enabled \ ++ : (mprotect_enabled = mprotect_enabled_check ())) ++ + #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ + + #elif defined (__CYGWIN__) || defined(__INTERIX) +@@ -446,7 +446,7 @@ emutramp_enabled_check (void) + #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */ + + #ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX +-#define is_emutramp_enabled() 0 ++#define is_mprotect_enabled() 0 + #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */ + + /* Declare all functions defined in dlmalloc.c as static. */ +@@ -750,13 +750,10 @@ dlmmap (void *start, size_t length, int prot, + && flags == (MAP_PRIVATE | MAP_ANONYMOUS) + && fd == -1 && offset == 0); + +- if (execfd == -1 && is_emutramp_enabled ()) +- { +- ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset); +- return ptr; +- } +- +- if (execfd == -1 && !is_selinux_enabled ()) ++ /* -1 != execfd hints that we already decided to use dlmmap_locked ++ last time. If PaX MPROTECT or SELinux is active fallback to ++ dlmmap_locked. */ ++ if (execfd == -1 && !is_mprotect_enabled () && !is_selinux_enabled ()) + { + ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset); + diff --git a/pat-11.2.1/python3-void/musl-find_library.patch b/pat-11.2.1/python3-void/musl-find_library.patch @@ -0,0 +1,44 @@ +--- Lib/ctypes/util.py.orig ++++ Lib/ctypes/util.py +@@ -204,6 +204,41 @@ + def find_library(name, is64 = False): + return _get_soname(_findLib_crle(name, is64) or _findLib_gcc(name)) + ++ elif True: ++ ++ # Patched for Alpine Linux / musl - search manually system paths ++ def _is_elf(filepath): ++ try: ++ with open(filepath, 'rb') as fh: ++ return fh.read(4) == b'\x7fELF' ++ except: ++ return False ++ ++ def find_library(name): ++ from glob import glob ++ # absolute name? ++ if os.path.isabs(name): ++ return name ++ # special case for libm, libcrypt and libpthread and musl ++ if name in ['m', 'crypt', 'pthread']: ++ name = 'c' ++ elif name in ['libm.so', 'libcrypt.so', 'libpthread.so']: ++ name = 'libc.so' ++ # search in standard locations (musl order) ++ paths = ['/lib', '/local/lib', '/sucks/lib'] ++ if 'LD_LIBRARY_PATH' in os.environ: ++ paths = os.environ['LD_LIBRARY_PATH'].split(':') + paths ++ for d in paths: ++ f = os.path.join(d, name) ++ if _is_elf(f): ++ return os.path.basename(f) ++ ++ prefix = os.path.join(d, 'lib'+name) ++ for suffix in ['.so', '.so.*']: ++ for f in glob('{0}{1}'.format(prefix, suffix)): ++ if _is_elf(f): ++ return os.path.basename(f) ++ + else: + + def _findSoname_ldconfig(name): diff --git a/pat-11.2.1/python3-void/tweak-MULTIARCH-for-powerpc-linux-musl.patch b/pat-11.2.1/python3-void/tweak-MULTIARCH-for-powerpc-linux-musl.patch @@ -0,0 +1,13 @@ +--- configure ++++ configure +@@ -5205,6 +5205,10 @@ + + MULTIARCH=$($CC --print-multiarch 2>/dev/null) + ++if test x$MULTIARCH = xpowerpc-linux-musl ++then ++ MULTIARCH="powerpc-linux-gnu" ++fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the platform triplet based on compiler characteristics" >&5 + $as_echo_n "checking for the platform triplet based on compiler characteristics... " >&6; } diff --git a/pat-11.2.1/xz-alpine/xzgrep-ZDI-CAN-16587.patch b/pat-11.2.1/xz-alpine/xzgrep-ZDI-CAN-16587.patch @@ -0,0 +1,94 @@ +From 69d1b3fc29677af8ade8dc15dba83f0589cb63d6 Mon Sep 17 00:00:00 2001 +From: Lasse Collin <lasse.collin@tukaani.org> +Date: Tue, 29 Mar 2022 19:19:12 +0300 +Subject: [PATCH] xzgrep: Fix escaping of malicious filenames (ZDI-CAN-16587). + +Malicious filenames can make xzgrep to write to arbitrary files +or (with a GNU sed extension) lead to arbitrary code execution. + +xzgrep from XZ Utils versions up to and including 5.2.5 are +affected. 5.3.1alpha and 5.3.2alpha are affected as well. +This patch works for all of them. + +This bug was inherited from gzip's zgrep. gzip 1.12 includes +a fix for zgrep. + +The issue with the old sed script is that with multiple newlines, +the N-command will read the second line of input, then the +s-commands will be skipped because it's not the end of the +file yet, then a new sed cycle starts and the pattern space +is printed and emptied. So only the last line or two get escaped. + +One way to fix this would be to read all lines into the pattern +space first. However, the included fix is even simpler: All lines +except the last line get a backslash appended at the end. To ensure +that shell command substitution doesn't eat a possible trailing +newline, a colon is appended to the filename before escaping. +The colon is later used to separate the filename from the grep +output so it is fine to add it here instead of a few lines later. + +The old code also wasn't POSIX compliant as it used \n in the +replacement section of the s-command. Using \<newline> is the +POSIX compatible method. + +LC_ALL=C was added to the two critical sed commands. POSIX sed +manual recommends it when using sed to manipulate pathnames +because in other locales invalid multibyte sequences might +cause issues with some sed implementations. In case of GNU sed, +these particular sed scripts wouldn't have such problems but some +other scripts could have, see: + + info '(sed)Locale Considerations' + +This vulnerability was discovered by: +cleemy desu wayo working with Trend Micro Zero Day Initiative + +Thanks to Jim Meyering and Paul Eggert discussing the different +ways to fix this and for coordinating the patch release schedule +with gzip. +--- + src/scripts/xzgrep.in | 20 ++++++++++++-------- + 1 file changed, 12 insertions(+), 8 deletions(-) + +diff --git a/src/scripts/xzgrep.in b/src/scripts/xzgrep.in +index b180936..e5186ba 100644 +--- a/src/scripts/xzgrep.in ++++ b/src/scripts/xzgrep.in +@@ -180,22 +180,26 @@ for i; do + { test $# -eq 1 || test $no_filename -eq 1; }; then + eval "$grep" + else ++ # Append a colon so that the last character will never be a newline ++ # which would otherwise get lost in shell command substitution. ++ i="$i:" ++ ++ # Escape & \ | and newlines only if such characters are present ++ # (speed optimization). + case $i in + (*' + '* | *'&'* | *'\'* | *'|'*) +- i=$(printf '%s\n' "$i" | +- sed ' +- $!N +- $s/[&\|]/\\&/g +- $s/\n/\\n/g +- ');; ++ i=$(printf '%s\n' "$i" | LC_ALL=C sed 's/[&\|]/\\&/g; $!s/$/\\/');; + esac +- sed_script="s|^|$i:|" ++ ++ # $i already ends with a colon so don't add it here. ++ sed_script="s|^|$i|" + + # Fail if grep or sed fails. + r=$( + exec 4>&1 +- (eval "$grep" 4>&-; echo $? >&4) 3>&- | sed "$sed_script" >&3 4>&- ++ (eval "$grep" 4>&-; echo $? >&4) 3>&- | ++ LC_ALL=C sed "$sed_script" >&3 4>&- + ) || r=2 + exit $r + fi >&3 5>&- +-- +2.35.1 +