Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 251 lines (226 sloc) 7.84 KB
#!/bin/sh
# SPDX-License-Identifier: MIT
#
# Copyright (c) 2017-2019 Nicolas Iooss
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# Build an Arch Linux package in a clean fake-chroot-ed environment
#
# Usage in a directory containing a PKGBUILD file:
# makecleanpkg
#
# When some dependencies are unofficial packages:
# makecleanpkg -I unofficial-package.pkg.tar.xz
#
# Dependencies (Arch Linux and AUR packages): devtools fakechroot fakeroot proot
#
# Tips: to update the package cache of base and base-devel packages, run:
# sudo pacman --noconfirm -Sw base base-devel
#
# makechrootpkg documentation:
# https://wiki.archlinux.org/index.php/DeveloperWiki:Building_in_a_Clean_Chroot
#
# Similar project: https://fsquillace.github.io/junest-site/
# "The Arch Linux based distro that runs upon any Linux distros without root access"
# Exit if a command fails
set -e
# Check dependencies
if [ ! -x /usr/bin/mkarchroot ] ; then
echo >&2 "Arch Linux devtools needs to be installed"
exit 1
fi
for CMD in fakechroot fakeroot proot ; do
if ! "$CMD" --version > /dev/null ; then
echo >&2 "$CMD needs to be installed"
exit 1
fi
done
if ! fakechroot chroot / true ; then
echo >&2 "fakechroot does not seem to work"
exit 1
fi
if [ "$(fakeroot id -u)" != 0 ] ; then
echo >&2 "fakeroot does not seem to work"
exit 1
fi
# proot<=5.1.0 is not compatible with Linux >= 4.9 because of a change in the
# way ptrace and seccomp interacts
# https://github.com/proot-me/PRoot/issues/106
# https://github.com/proot-me/PRoot/pull/115
PROOT_VERSION="$(pacman -Q proot | cut -d' ' -f2)"
if [ -z "$PROOT_VERSION" ] ; then
echo >&2 "proot is not installed"
exit 1
elif [ "$(vercmp "${PROOT_VERSION%-*}" '5.1.0')" -le 0 ] && [ "$(vercmp "$(uname -r)" '4.8')" -gt 0 ] ; then
export PROOT_NO_SECCOMP=1
EXPORT_PROOT_NO_SECCOMP_CMD='export PROOT_NO_SECCOMP=1'
fi
if ! proot true ; then
echo >&2 "proot does not seem to work"
exit 1
fi
# Helper function to create an executable script from standard input
cat_script() {
cat > "$1"
chmod +x "$1"
}
# Find the configured BUILDDIR
if [ -z "$BUILDDIR" ] ; then
BUILDDIR="$(bash -c 'shopt -u extglob ; source /etc/makepkg.conf ; echo $BUILDDIR')"
if [ -z "$BUILDDIR" ] ; then
BUILDDIR='.'
fi
fi
PKGNAME="$(bash -c 'shopt -u extglob ; source ./PKGBUILD ; echo "${pkgbase:-$pkgname}"')"
if [ -z "$PKGNAME" ] ; then
echo >&2 "Unable to find the current package name"
exit 1
fi
# Set-up a temporary directory with fakers
CHROOTDIR="$BUILDDIR/makecleanpkg-$PKGNAME"
mkdir -p "$CHROOTDIR/bin"
# Redirect systemd-nspawn to proot
cat_script "$CHROOTDIR/bin/systemd-nspawn" << EOF
#!/bin/bash
# Fake systemd-nspawn with proot
$EXPORT_PROOT_NO_SECCOMP_CMD
# Allow fakechroot in the proot'ed environment
proot_options=(--cwd=/ -b /usr/lib/libfakeroot/fakechroot -b /usr/bin/fakechroot)
# Allow use of /dev/console inside the pseudo-container
proot_options+=( -b /dev/tty:/dev/console)
env_variables=()
while [ \$# -ge 1 ] ; do
case "\$1" in
-D)
proot_options+=(-R "\$2")
shift
;;
--bind=*|--bind-ro=*)
proot_options+=(-b "\${1#*=}")
;;
-E)
env_variables+=("\$2")
shift
;;
-q|--as-pid2|--keep-unit|--register=no)
;;
locale-gen)
# Skip locale-gen as it crashes with proot 5.1.0
exit
;;
*)
break
;;
esac
shift
done
# Ask --ask=4 to replace packages when installing with pacman -U --noconfirm
if [ "\$1 \$2 \$3" = 'pacman -U --noconfirm' ] ; then
shift
set pacman --ask=4 "\$@"
fi
echo "Running proot \${proot_options[*]} env \${env_variables[*]} \$*"
exec proot "\${proot_options[@]}" env "\${env_variables[@]}" "\$@"
EOF
# Redirect mount and umount to no-ops
echo '#!/bin/true' | cat_script "$CHROOTDIR/bin/mount"
echo '#!/bin/true' | cat_script "$CHROOTDIR/bin/umount"
# Make "env -i" preserve fakeroot and fakechroot variables, in order to be
# compatible after commit
# https://git.archlinux.org/devtools.git/commit/?id=578a62f1e0713b0df9722470146fb85fb819202c
cat_script "$CHROOTDIR/bin/env" << EOF
#!/bin/bash
if [ "\$1" = '-i' ] ; then
_env=(PATH="$CHROOTDIR/bin:/usr/bin")
while read -r varname; do
_env+=("\$varname=\${!varname}")
done < <(
declare -x | \
sed -r 's/^declare -x ([^=]*)=.*/\\1/' | \
grep -e '^FAKE' -e '^LD_LIBRARY_PATH$' -e '^LD_PRELOAD$')
shift
exec /usr/bin/env -i "\${_env[@]}" "\$@"
else
exec /usr/bin/env "\$@"
fi
EOF
export PATH="$CHROOTDIR/bin:$PATH"
# Create a chroot directory if needed
# (it may have been left over after a previous execution failed)
if ! [ -e "$CHROOTDIR/root/.arch-chroot" ] ; then
fakeroot fakechroot mkarchroot "$CHROOTDIR/root" base-devel
fakeroot fakechroot chroot "$CHROOTDIR/root" locale-gen
fi
# Fake sudo for "sudo -iu builduser makepkg" and when makepkg wants to use sudo
# to install packages
mkdir -p "$CHROOTDIR/root/faked_programs"
cat_script "$CHROOTDIR/root/faked_programs/sudo" << EOF
#!/bin/sh
if [ "\$1" = '--preserve-env=SOURCE_DATE_EPOCH' ] ; then
# We do not care about preserving this specific variable
shift
fi
if [ "\$1" = '-u' ] || [ "\$1" = '-iu' ] ; then
if [ "\$2" != 'builduser' ] ; then
echo >&2 "Warning: unexpected sudo-ed user \$2"
fi
shift 2
# Disable fakeroot
unset LD_PRELOAD
unset LD_LIBRARY_PATH
unset FAKEROOTKEY
# Make sure an UTF-8 locale get used when running makepkg
# It is mandatory for building systemd package, because meson needs it.
# Otherwise it displays the following error message:
# WARNING: You are using 'ANSI_X3.4-1968' which is not a a Unicode-compatible locale.
# WARNING: You might see errors if you use UTF-8 strings as filenames, as strings, or as file contents.
# WARNING: Please switch to a UTF-8 locale for your platform.
# c.f. https://github.com/mesonbuild/meson/blob/0.42.0/meson.py#L21
if [ "\$LANG" = 'C' ] ; then
LANG=en_US.UTF-8
fi
"\$@"
else
# Use fakeroot
fakeroot "\$@"
fi
EOF
# Encapsulate all calls to pacman into a fakechroot in order to run install
# scripts in chroots
cat_script "$CHROOTDIR/root/faked_programs/pacman" << EOF
#!/bin/sh
fakechroot /usr/bin/pacman "\$@"
EOF
# Make /chrootbuild and makepkg use the fake programs
cat_script "$CHROOTDIR/root/etc/profile.d/fakesudo.sh" << EOF
#!/bin/sh
if [ "\${PATH#/faked_programs:}" = "\$PATH" ] ; then
PATH="/faked_programs:\$PATH"
fi
EOF
ln -sf ../../../etc/profile.d/fakesudo.sh "$CHROOTDIR/root/usr/share/makepkg/fakesudo.sh"
# Fake sudo environment for makechrootpkg
SUDO_UID="$(id -u)"
SUDO_USER="$(id -nu)"
export SUDO_UID SUDO_USER
# Finally run makechrootpkg!
fakeroot makechrootpkg -r "$CHROOTDIR" "$@"
# All right, let's clean everything up!
rm -rf "${CHROOTDIR:?}"
You can’t perform that action at this time.