mirror of
https://github.com/fosslinux/live-bootstrap.git
synced 2026-03-02 01:18:08 +01:00
Ever since an old patch version, it has (for reasonable security reasons) not supported patched with ../ in the filename. Many of our patches have been relying on this behaviour being OK, because we start off with an ancient patch version that didn't perform such checks. As soon as we need this behaviour after we build a newer patch though, we will have problems. So, let's change the policy. Patches are relative to where tarballs are extracted, rather than the "working directory" - e.g. have patches for `coreutils-9.4/src/cp.c` instead of `src/cp.c`. Keeping this consistent has a few implications; - patches are applied from the build/ directory in bash era now, with `-p0` - when patches are manually applied in the bash era, use `-p` as required, usually `-p1` - in kaem era where patches are always manually applied, `-p1` is used
538 lines
16 KiB
Bash
Executable file
538 lines
16 KiB
Bash
Executable file
#!/bin/bash -e
|
|
|
|
# SPDX-FileCopyrightText: 2021 Andrius Štikonas <andrius@stikonas.eu>
|
|
# SPDX-FileCopyrightText: 2021-22 fosslinux <fosslinux@aussies.space>
|
|
# SPDX-FileCopyrightText: 2021 Paul Dersey <pdersey@gmail.com>
|
|
# SPDX-FileCopyrightText: 2021 Melg Eight <public.melg8@gmail.com>
|
|
#
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
# Set constant umask
|
|
umask 022
|
|
|
|
# Get a list of files
|
|
get_files() {
|
|
echo "."
|
|
_get_files "${1}"
|
|
}
|
|
|
|
_get_files() {
|
|
local prefix
|
|
prefix="${1}"
|
|
fs=
|
|
if [ -n "$(ls 2>/dev/null)" ]; then
|
|
# This can be removed once Debian 12 is stable
|
|
# shellcheck disable=SC2035
|
|
fs=$(echo *)
|
|
fi
|
|
if [ -n "$(ls .[0-z]* 2>/dev/null)" ]; then
|
|
fs="${fs} $(echo .[0-z]*)"
|
|
fi
|
|
for f in ${fs}; do
|
|
# Archive symlinks to directories as symlinks
|
|
echo "${prefix}/${f}"
|
|
if [ -d "${f}" ] && ! [ -h "${f}" ]; then
|
|
cd "${f}"
|
|
_get_files "${prefix}/${f}"
|
|
cd ..
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Reset all timestamps to unix time 0
|
|
reset_timestamp() {
|
|
if command -v find >/dev/null 2>&1; then
|
|
# find does not error out on exec error
|
|
find . -print0 | xargs -0 touch -h -t 197001010000.00
|
|
else
|
|
# A rudimentary find implementation that does the trick
|
|
fs=
|
|
if [ -n "$(ls 2>/dev/null)" ]; then
|
|
fs=$(echo ./*)
|
|
fi
|
|
if [ -n "$(ls .[0-z]* 2>/dev/null)" ]; then
|
|
fs="${fs} $(echo .[0-z]*)"
|
|
fi
|
|
for f in ${fs}; do
|
|
touch -h -t 197001010000.00 "${f}"
|
|
if [ -d "${f}" ]; then
|
|
cd "${f}"
|
|
reset_timestamp
|
|
cd ..
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# Fake grep
|
|
_grep() {
|
|
local text="${1}"
|
|
local fname="${2}"
|
|
if command -v grep >/dev/null 2>&1; then
|
|
grep "${text}" "${fname}"
|
|
else
|
|
# shellcheck disable=SC2162
|
|
while read line; do
|
|
case "${line}" in *"${text}"*)
|
|
echo "${line}" ;;
|
|
esac
|
|
done < "${fname}"
|
|
fi
|
|
}
|
|
|
|
get_revision() {
|
|
local pkg=$1
|
|
local oldpwd="${PWD}"
|
|
cd "/external/repo"
|
|
# Get revision (n time this package has been built)
|
|
revision=$( (ls -1 "${pkg}"* 2>/dev/null || true) | wc -l | sed 's/ *//g')
|
|
cd "${oldpwd}"
|
|
}
|
|
|
|
# Installs binary packages from an earlier run
|
|
# This is useful to speed up development cycle
|
|
bin_preseed() {
|
|
if [ -d "/external/repo-preseeded" ]; then
|
|
get_revision "${pkg}"
|
|
cd "/external/repo-preseeded"
|
|
test -e "${pkg}_${revision}.tar.bz2" || return 1
|
|
if [ "${UPDATE_CHECKSUMS}" = "True" ] || src_checksum "${pkg}" $((revision)); then
|
|
echo "${pkg}: installing prebuilt package."
|
|
mv "${pkg}_${revision}"* /external/repo || return 1
|
|
cd "/external/repo"
|
|
rm -f /tmp/filelist.txt
|
|
src_apply "${pkg}" $((revision))
|
|
cd "${SRCDIR}"
|
|
return 0
|
|
fi
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
# Removes either an existing package or file
|
|
uninstall() {
|
|
local in_fs in_pkg symlinks
|
|
while [ $# -gt 0 ]; do
|
|
removing="$1"
|
|
case "${removing}" in
|
|
/*)
|
|
# Removing a file
|
|
echo "removing file: ${removing}."
|
|
rm -f "${removing}"
|
|
;;
|
|
*)
|
|
echo "${removing}: uninstalling."
|
|
local oldpwd="${PWD}"
|
|
mkdir -p "/tmp/removing"
|
|
cd "/tmp/removing"
|
|
get_revision "${removing}"
|
|
local filename="/external/repo/${removing}_$((revision-1)).tar.bz2"
|
|
# Initial bzip2 built against meslibc has broken pipes
|
|
bzip2 -dc "${filename}" | tar -xf -
|
|
# reverse to have files before directories
|
|
if command -v find >/dev/null 2>&1; then
|
|
find . | sort -r > ../filelist
|
|
else
|
|
get_files . | tac > ../filelist
|
|
fi
|
|
# shellcheck disable=SC2162
|
|
while read file; do
|
|
if [ -d "${file}" ]; then
|
|
if [ -z "$(ls -A "/${file}")" ]; then
|
|
rmdir "/${file}"
|
|
fi
|
|
else
|
|
# in some cases we might be uninstalling a file that has already been overwritten
|
|
# in this case we don't want to remove it
|
|
in_fs="$(sha256sum "${file}" 2>/dev/null | cut -d' ' -f1)"
|
|
in_pkg="$(sha256sum "/${file}" 2>/dev/null | cut -d' ' -f1)"
|
|
if [ "${in_fs}" = "${in_pkg}" ]; then
|
|
rm -f "/${file}"
|
|
fi
|
|
if [ -h "${file}" ]; then
|
|
symlinks="${symlinks} ${file}"
|
|
fi
|
|
fi
|
|
done < ../filelist
|
|
rm -f ../filelist
|
|
for link in ${symlinks}; do
|
|
if [ ! -e "/${link}" ]; then
|
|
rm -f "/${link}"
|
|
fi
|
|
done
|
|
cd "${oldpwd}"
|
|
rm -rf "/tmp/removing"
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
}
|
|
|
|
# Common build steps
|
|
# Build function provides a few common stages with default implementation
|
|
# that can be overridden on per package basis in the build script.
|
|
# build takes two arguments:
|
|
# 1) name-version of the package
|
|
# 2) optionally specify build script. Default is pass$((revision+1)).sh
|
|
# 3) optionally specify directory to cd into
|
|
build() {
|
|
pkg=$1
|
|
get_revision "${pkg}"
|
|
script_name=${2:-pass$((revision+1)).sh}
|
|
dirname=${3:-${pkg}}
|
|
|
|
# shellcheck disable=SC2015
|
|
bin_preseed && return || true # Normal build if preseed fails
|
|
|
|
cd "${SRCDIR}/${pkg}" || (echo "Cannot cd into ${pkg}!"; kill $$)
|
|
echo "${pkg}: beginning build using script ${script_name}"
|
|
base_dir="${PWD}"
|
|
if [ -e "${base_dir}/patches-$(basename "${script_name}" .sh)" ]; then
|
|
patch_dir="${base_dir}/patches-$(basename "${script_name}" .sh)"
|
|
else
|
|
patch_dir="${base_dir}/patches"
|
|
fi
|
|
mk_dir="${base_dir}/mk"
|
|
files_dir="${base_dir}/files"
|
|
|
|
rm -rf "build"
|
|
mkdir "build"
|
|
cd "build"
|
|
|
|
build_script="${base_dir}/${script_name}"
|
|
if test -e "${build_script}"; then
|
|
# shellcheck source=/dev/null
|
|
. "${build_script}"
|
|
fi
|
|
|
|
echo "${pkg}: getting sources."
|
|
build_stage=src_get
|
|
call $build_stage
|
|
|
|
echo "${pkg}: unpacking source."
|
|
build_stage=src_unpack
|
|
call $build_stage
|
|
unset EXTRA_DISTFILES
|
|
|
|
cd "${dirname}" || (echo "Cannot cd into build/${dirname}!"; kill $$)
|
|
|
|
echo "${pkg}: preparing source."
|
|
build_stage=src_prepare
|
|
call $build_stage
|
|
|
|
echo "${pkg}: configuring source."
|
|
build_stage=src_configure
|
|
call $build_stage
|
|
|
|
echo "${pkg}: compiling source."
|
|
build_stage=src_compile
|
|
call $build_stage
|
|
|
|
echo "${pkg}: install to fakeroot."
|
|
mkdir -p "${DESTDIR}"
|
|
build_stage=src_install
|
|
call $build_stage
|
|
|
|
echo "${pkg}: postprocess binaries."
|
|
build_stage=src_postprocess
|
|
call $build_stage
|
|
|
|
echo "${pkg}: creating package."
|
|
cd "${DESTDIR}"
|
|
src_pkg
|
|
|
|
src_checksum "${pkg}" "${revision}"
|
|
|
|
echo "${pkg}: cleaning up."
|
|
rm -rf "${SRCDIR}/${pkg}/build"
|
|
rm -rf "${DESTDIR}"
|
|
|
|
echo "${pkg}: installing package."
|
|
src_apply "${pkg}" "${revision}"
|
|
|
|
echo "${pkg}: build successful"
|
|
|
|
cd "${SRCDIR}"
|
|
|
|
unset -f src_get src_unpack src_prepare src_configure src_compile src_install src_postprocess
|
|
unset extract
|
|
}
|
|
|
|
download_source_line() {
|
|
url="${1}"
|
|
checksum="${2}"
|
|
fname="${3}"
|
|
# Default to basename of url if not given
|
|
fname="${fname:-$(basename "${url}")}"
|
|
if ! [ -e "${fname}" ]; then
|
|
curl --fail --retry 5 --location "${url}" --output "${fname}" || true
|
|
fi
|
|
}
|
|
|
|
check_source_line() {
|
|
url="${1}"
|
|
checksum="${2}"
|
|
fname="${3}"
|
|
# Default to basename of url if not given
|
|
fname="${fname:-$(basename "${url}")}"
|
|
if ! [ -e "${fname}" ]; then
|
|
false
|
|
fi
|
|
echo "${checksum} ${fname}" > "${fname}.sum"
|
|
sha256sum -c "${fname}.sum"
|
|
rm "${fname}.sum"
|
|
}
|
|
|
|
# Default get function that downloads source tarballs.
|
|
default_src_get() {
|
|
# shellcheck disable=SC2153
|
|
cd "${DISTFILES}"
|
|
# shellcheck disable=SC2162
|
|
while read line; do
|
|
# This is intentional - we want to split out ${line} into separate arguments.
|
|
# shellcheck disable=SC2086
|
|
download_source_line ${line}
|
|
done < "${base_dir}/sources"
|
|
# shellcheck disable=SC2162
|
|
while read line; do
|
|
# This is intentional - we want to split out ${line} into separate arguments.
|
|
# shellcheck disable=SC2086
|
|
check_source_line ${line}
|
|
done < "${base_dir}/sources"
|
|
cd -
|
|
}
|
|
|
|
# Intelligently extracts a file based upon its filetype.
|
|
extract_file() {
|
|
f="${3:-$(basename "${1}")}"
|
|
# shellcheck disable=SC2154
|
|
case "${noextract}" in
|
|
*${f}*)
|
|
cp "${DISTFILES}/${f}" .
|
|
;;
|
|
*)
|
|
case "${f}" in
|
|
*.tar* | *.tgz)
|
|
# shellcheck disable=SC2153
|
|
if test -e "${PREFIX}/libexec/rmt"; then
|
|
# Again, we want to split out into words.
|
|
# shellcheck disable=SC2086
|
|
tar --no-same-owner -xf "${DISTFILES}/${f}" ${extract}
|
|
else
|
|
# shellcheck disable=SC2086
|
|
case "${f}" in
|
|
*.tar.gz) tar -xzf "${DISTFILES}/${f}" ${extract} ;;
|
|
*.tar.bz2)
|
|
# Initial bzip2 built against meslibc has broken pipes
|
|
bzip2 -dc "${DISTFILES}/${f}" | tar -xf - ${extract} ;;
|
|
*.tar.xz | *.tar.lzma)
|
|
if test -e "${PREFIX}/bin/xz"; then
|
|
tar -xf "${DISTFILES}/${f}" --use-compress-program=xz ${extract}
|
|
else
|
|
unxz --file "${DISTFILES}/${f}" | tar -xf - ${extract}
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
;;
|
|
*)
|
|
cp "${DISTFILES}/${f}" .
|
|
;;
|
|
esac
|
|
;;
|
|
esac
|
|
}
|
|
|
|
# Default unpacking function that unpacks all sources.
|
|
default_src_unpack() {
|
|
# Handle the first one differently
|
|
first_line=$(head -n 1 ../sources)
|
|
# Again, we want to split out into words.
|
|
# shellcheck disable=SC2086
|
|
extract_file ${first_line}
|
|
# This assumes there is only one directory in the tarball
|
|
# Get the dirname "smartly"
|
|
if ! [ -e "${dirname}" ]; then
|
|
for i in *; do
|
|
if [ -d "${i}" ]; then
|
|
dirname="${i}"
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
# shellcheck disable=SC2162
|
|
tail -n +2 ../sources | while read line; do
|
|
# shellcheck disable=SC2086
|
|
extract_file ${line}
|
|
done
|
|
}
|
|
|
|
# Default function to prepare source code.
|
|
# It applies all patches from patch_dir (at the moment only -p0 patches are supported).
|
|
# Patches are applied from the parent directory.
|
|
# Then it copies our custom makefile and any other custom files from files directory.
|
|
default_src_prepare() {
|
|
if test -d "${patch_dir}"; then
|
|
if ls "${patch_dir}"/*.patch >/dev/null 2>&1; then
|
|
for p in "${patch_dir}"/*.patch; do
|
|
echo "Applying patch: ${p}"
|
|
patch -d.. -Np0 < "${p}"
|
|
done
|
|
fi
|
|
fi
|
|
|
|
makefile="${mk_dir}/main.mk"
|
|
if test -e "${makefile}"; then
|
|
cp "${makefile}" Makefile
|
|
fi
|
|
|
|
if test -d "${files_dir}"; then
|
|
cp --no-preserve=mode "${files_dir}"/* "${PWD}/"
|
|
fi
|
|
}
|
|
|
|
# Default function for configuring source.
|
|
default_src_configure() {
|
|
:
|
|
}
|
|
|
|
# Default function for compiling source. It simply runs make without any parameters.
|
|
default_src_compile() {
|
|
make "${MAKEJOBS}" -f Makefile PREFIX="${PREFIX}"
|
|
}
|
|
|
|
# Default installing function. PREFIX should be set by run.sh script.
|
|
# Note that upstream makefiles might ignore PREFIX and have to be configured in configure stage.
|
|
default_src_install() {
|
|
make -f Makefile install PREFIX="${PREFIX}" DESTDIR="${DESTDIR}"
|
|
}
|
|
|
|
# Default function for postprocessing binaries.
|
|
default_src_postprocess() {
|
|
if (command -v find && command -v file && command -v strip) >/dev/null 2>&1; then
|
|
# Logic largely taken from void linux 06-strip-and-debug-pkgs.sh
|
|
# shellcheck disable=SC2162
|
|
find "${DESTDIR}" -type f | while read f; do
|
|
case "$(file -bi "${f}")" in
|
|
application/x-executable*) strip "${f}" ;;
|
|
application/x-sharedlib*|application/x-pie-executable*)
|
|
machine_set="$(file -b "${f}")"
|
|
case "${machine_set}" in
|
|
*no\ machine*) ;; # don't strip ELF container-only
|
|
*) strip --strip-unneeded "${f}" ;;
|
|
esac
|
|
;;
|
|
application/x-archive*) strip --strip-debug "${f}" ;;
|
|
esac
|
|
done
|
|
fi
|
|
}
|
|
|
|
src_pkg() {
|
|
touch -t 197001010000.00 .
|
|
reset_timestamp
|
|
|
|
local tar_basename="${pkg}_${revision}.tar"
|
|
local dest_tar="/external/repo/${tar_basename}"
|
|
local filelist=/tmp/filelist.txt
|
|
|
|
cd /external/repo
|
|
# If grep is unavailable, then tar --sort is unavailable.
|
|
# So this does not need a command -v grep.
|
|
if tar --help | grep ' \-\-sort' >/dev/null 2>&1; then
|
|
tar -C "${DESTDIR}" --sort=name --hard-dereference \
|
|
--numeric-owner --owner=0 --group=0 --mode=go=rX,u+rw -cf "${dest_tar}" .
|
|
else
|
|
local olddir
|
|
olddir=$PWD
|
|
cd "${DESTDIR}"
|
|
local null
|
|
if command -v find >/dev/null 2>&1 && command -v sort >/dev/null 2>&1; then
|
|
find . -print0 | LC_ALL=C sort -z > "${filelist}"
|
|
null="--null"
|
|
elif command -v sort >/dev/null 2>&1; then
|
|
get_files . | LC_ALL=C sort > "${filelist}"
|
|
else
|
|
get_files . > ${filelist}
|
|
fi
|
|
tar --no-recursion ${null} --files-from "${filelist}" \
|
|
--numeric-owner --owner=0 --group=0 --mode=go=rX,u+rw -cf "${dest_tar}"
|
|
rm -f "$filelist"
|
|
cd "$olddir"
|
|
fi
|
|
touch -t 197001010000.00 "${tar_basename}"
|
|
bzip2 --best "${tar_basename}"
|
|
}
|
|
|
|
src_checksum() {
|
|
local pkg=$1 revision=$2
|
|
local rval=0
|
|
if ! [ "$UPDATE_CHECKSUMS" = True ] ; then
|
|
# We avoid using pipes as that is not supported by initial sha256sum from mescc-tools-extra
|
|
local checksum_file=/tmp/checksum
|
|
_grep "${pkg}_${revision}" "${SRCDIR}/SHA256SUMS.pkgs" > "${checksum_file}" || true
|
|
# Check there is something in checksum_file
|
|
if ! [ -s "${checksum_file}" ]; then
|
|
echo "${pkg}: no checksum stored!"
|
|
false
|
|
fi
|
|
echo "${pkg}: checksumming created package."
|
|
sha256sum -c "${checksum_file}" || rval=$?
|
|
rm "${checksum_file}"
|
|
fi
|
|
return "${rval}"
|
|
}
|
|
|
|
src_apply() {
|
|
local pkg="${1}" revision="${2}"
|
|
local TAR_PREFIX BZIP2_PREFIX
|
|
|
|
# Make sure we have at least one copy of tar
|
|
if [[ "${pkg}" == tar-* ]]; then
|
|
mkdir -p /tmp
|
|
cp "${PREFIX}/bin/tar" "/tmp/tar"
|
|
TAR_PREFIX="/tmp/"
|
|
fi
|
|
|
|
# Bash does not like to be overwritten
|
|
if [[ "${pkg}" == bash-* ]]; then
|
|
rm "${PREFIX}/bin/bash"
|
|
fi
|
|
|
|
# Overwriting files is mega busted, so do it manually
|
|
# shellcheck disable=SC2162
|
|
if [ -e /tmp/filelist.txt ]; then
|
|
while IFS= read -d $'\0' file; do
|
|
rm -f "/${file}" >/dev/null 2>&1 || true
|
|
done < /tmp/filelist.txt
|
|
fi
|
|
|
|
# Bzip2 does not like to be overwritten
|
|
if [[ "${pkg}" == bzip2-* ]]; then
|
|
mkdir -p /tmp
|
|
mv "${PREFIX}/bin/bzip2" "/tmp/bzip2"
|
|
BZIP2_PREFIX="/tmp/"
|
|
fi
|
|
"${BZIP2_PREFIX}bzip2" -dc "/external/repo/${pkg}_${revision}.tar.bz2" | \
|
|
"${TAR_PREFIX}tar" -C / -xpf -
|
|
rm -f "/tmp/bzip2" "/tmp/tar"
|
|
}
|
|
|
|
# Check if bash function exists
|
|
fn_exists() {
|
|
test "$(type -t "$1")" == 'function'
|
|
}
|
|
|
|
# Call package specific function or default implementation.
|
|
call() {
|
|
if fn_exists "$1"; then
|
|
$1
|
|
else
|
|
default_"${1}"
|
|
fi
|
|
}
|
|
|
|
# Call default build stage function
|
|
default() {
|
|
"default_${build_stage}"
|
|
}
|