+#!/usr/bin/env bash
+
+BUILD_CGROUP="/sys/fs/cgroup/openrc.portage-cgroup"
+KERNEL_SRC="/usr/src/linux"
+
+# ----- generic helpers -------------------------------------------------------
+
+die() {
+ echo "Error: $*" >&2
+ exit 1
+}
+
+root_check() {
+ (( EUID == 0 )) || die "You have to run this script with sudo"
+}
+
+require_gentoo() {
+ grep -qi 'gentoo' /etc/os-release ||
+ die "Dieses System basiert nicht auf Gentoo"
+}
+
+# ----- build cgroup ----------------------------------------------------------
+
+check_build_cgroup() {
+ [[ -d "$BUILD_CGROUP" ]] ||
+ die "Build cgroup does not exist: $BUILD_CGROUP"
+
+ [[ -w "$BUILD_CGROUP/cgroup.procs" ]] ||
+ die "Cannot write to $BUILD_CGROUP/cgroup.procs"
+}
+
+enter_build_cgroup() {
+ check_build_cgroup
+
+ echo "$BASHPID" > "$BUILD_CGROUP/cgroup.procs" ||
+ die "Could not enter build cgroup"
+}
+
+run_in_build_cgroup() {
+ (
+ enter_build_cgroup
+ exec "$@"
+ )
+}
+
+emerge_build() {
+ run_in_build_cgroup \
+ schedtool -D -e \
+ /usr/bin/emerge "$@"
+}
+
+# ----- portage operations ---------------------------------------------------
+
+sync_all_repos() {
+ emaint sync -A
+}
+
+sync_repos() {
+ emaint sync -a
+}
+
+update_world() {
+ emerge_build -avuDNg @world "$@"
+}
+
+resume_operations() {
+ emerge -av --resume
+}
+
+daily_update() {
+ sync_repos && update_world "$@"
+}
+
+update_world_with_bdeps() {
+ emerge_build \
+ -avuDNg \
+ --with-bdeps=y \
+ --binpkg-changed-deps=y \
+ @world "$@"
+}
+
+# ----- kernel build ---------------------------------------------------------
+
+cd_to_src() {
+ [[ -L "$KERNEL_SRC" ]] ||
+ die "Symlink $KERNEL_SRC ist nicht gesetzt"
+
+ [[ -f "$KERNEL_SRC/Makefile" ]] ||
+ die "$KERNEL_SRC zeigt nicht auf einen gueltigen Kernel-Quellbaum"
+
+ cd "$KERNEL_SRC" ||
+ die "Verzeichniswechsel nach $KERNEL_SRC fehlgeschlagen"
+}
+
+prepare_config() {
+ local flavor=$1
+ local config="/usr/src/config-$flavor"
+
+ [[ -f "$config" ]] ||
+ die "Kernel config does not exist: $config"
+
+ cp -- "$config" .config ||
+ die "Kopieren von $config nach .config fehlgeschlagen"
+}
+
+print_version() {
+ echo
+ echo "Building version:"
+ head -n 5 Makefile
+ echo
+}
+
+build_timeout() {
+ local key
+ read -n 1 -s -r -p "Press any key to continue" key
+ echo
+}
+
+build_kernel_in_cgroup() {
+ (
+ # Enter the build cgroup once. All make processes and their children
+ # inherit the cpuset/resource limits from here on.
+ enter_build_cgroup
+
+ local jobs
+ jobs=$(nproc) || exit 2
+
+ echo "Using $jobs build jobs from the cgroup CPU set."
+ echo
+
+ schedtool -D -e make oldconfig || exit 2
+ schedtool -D -e make modules_prepare || exit 2
+ schedtool -D -e make -j"$jobs" || exit 2
+ schedtool -D -e make modules_install || exit 2
+ schedtool -D -e make install || exit 2
+ )
+}
+
+kernel_build() {
+ local flavor=${1:-live}
+
+ root_check
+ cd_to_src
+
+ if [[ "$flavor" == "live" ]]; then
+ [[ -f .config ]] ||
+ die "No .config found in $KERNEL_SRC"
+ else
+ make mrproper ||
+ die "make mrproper failed"
+
+ prepare_config "$flavor"
+ fi
+
+ print_version
+ build_timeout
+
+ build_kernel_in_cgroup ||
+ die "Kernel build failed"
+
+ emerge_build @module-rebuild ||
+ die "Module rebuild failed"
+
+ echo
+ echo "Build completed."
+
+ if [[ "$flavor" != "live" ]]; then
+ echo "Remember to upgrayyedd /usr/src/config-* if necessary."
+ fi
+}
+
+# ----- main -----------------------------------------------------------------
+
+require_gentoo
+
+case "${1:-}" in
+ check)
+ /usr/bin/emerge -puDNg @world
+ ;;
+
+ sync|ref|refresh)
+ root_check
+ sync_all_repos
+ ;;
+
+ daily|all)
+ root_check
+ daily_update "${@:2}"
+ ;;
+
+ world|dup)
+ root_check
+ update_world "${@:2}"
+ ;;
+
+ wbdeps|wbd)
+ root_check
+ update_world_with_bdeps "${@:2}"
+ ;;
+
+ pkg|in)
+ root_check
+ emerge_build -avg "${@:2}"
+ ;;
+
+ resume)
+ root_check
+ resume_operations "${@:2}"
+ ;;
+
+ skipkernel)
+ root_check
+ emerge_build \
+ -avuDNg \
+ @world \
+ --exclude=dist-kernel \
+ --exclude=gentoo-kernel \
+ --exclude=gentoo-sources \
+ --exclude=git-sources \
+ "${@:2}"
+ ;;
+
+ preserved)
+ root_check
+ emerge_build -av @preserved-rebuild
+ ;;
+
+ wholeworld)
+ root_check
+
+ # Intentional exception: this is the only build path outside the
+ # Portage cgroup. A full world rebuild may use all CPUs because the
+ # machine is expected to be otherwise idle / running only TTYs.
+ schedtool -B -e /usr/bin/emerge \
+ -avuDeg \
+ --with-bdeps=y \
+ --usepkg=n \
+ --binpkg-changed-deps=n \
+ --keep-going=y \
+ @world \
+ --exclude="acct-group/* acct-user/* virtual/* app-eselect/* sys-kernel/* sys-firmware/* dev-python/* dev-java/* dev-ruby/* dev-perl/* dev-lua/* dev-php/* dev-tex/* dev-texlive/* x11-themes/* */*-bin"
+ ;;
+
+ search|se)
+ /usr/bin/emerge --search "${@:2}"
+ ;;
+
+ clean|rm)
+ root_check
+ /usr/bin/emerge -a --depclean "${@:2}"
+ ;;
+
+ checkclean)
+ /usr/bin/emerge -apv --depclean "${@:2}"
+ ;;
+
+ live)
+ root_check
+ emerge_build -av @live-rebuild
+ ;;
+
+ flatpaks)
+ flatpak update
+ ;;
+
+ kernel-live)
+ kernel_build live
+ ;;
+
+ kernel-gentoo)
+ kernel_build gentoo
+ ;;
+
+ kernel-llvm)
+ kernel_build llvm
+ ;;
+
+ kernel-git)
+ kernel_build git
+ ;;
+
+ kernel-server)
+ kernel_build server
+ ;;
+
+ clean-kernels)
+ root_check
+
+ echo "Relevant files in /boot:"
+ echo
+
+ command ls -1 \
+ /boot/System.map* \
+ /boot/initramfs* \
+ /boot/vmlinuz* 2>/dev/null
+
+ eclean-kernel -aA -L std
+ ;;
+
+ log)
+ grep -i "completed" /var/log/emerge.log |
+ while IFS=' ' read -r ts rest; do
+ printf '%s %s\n' "$(date -d "@${ts%:}" '+%Y-%m-%d %H:%M:%S')" "$rest"
+ done
+ ;;
+ unlog)
+ grep -i "unmerging" /var/log/emerge.log |
+ while IFS=' ' read -r ts rest; do
+ printf '%s %s\n' "$(date -d "@${ts%:}" '+%Y-%m-%d %H:%M:%S')" "$rest"
+ done
+ ;;
+
+ testify)
+ root_check
+
+ run_in_build_cgroup bash -c '
+ echo "PID: $$"
+ echo
+ echo "cgroup:"
+ cat /proc/$$/cgroup
+ echo
+ echo "allowed CPUs:"
+ grep Cpus_allowed_list /proc/$$/status
+ echo
+ echo "nproc:"
+ nproc
+ '
+ ;;
+
+ *)
+ cat <<'HELP'
+
+Currently available commands:
+
+sync | ref | refresh forcibly synchronize all repositories
+check check for updates
+search | se search packages
+all | daily sync enabled repositories and update world
+world | dup update world without repository sync
+wbdeps | wbd update world including build dependencies
+pkg | in install packages given as arguments
+skipkernel update world except kernel packages
+
+live update all live packages
+flatpaks update flatpaks
+
+wholeworld rebuild everything from scratch using all CPUs
+
+kernel-live build current kernel tree/config
+kernel-gentoo build kernel flavor: gentoo
+kernel-llvm build kernel flavor: llvm
+kernel-git build kernel flavor: git
+kernel-server build kernel flavor: server
+
+checkclean check for orphans
+clean | rm clean orphaned packages
+preserved rebuild preserved libraries
+clean-kernels remove old kernels
+
+log view recently emerged files
+unlog view recently unmerged files
+testify show build cgroup placement
+
+HELP
+ ;;
+esac