#!/bin/bash

# Copyright 2017-2024  Patrick J. Volkerding, Sebeka, MN, USA
# Copyright 2017-2026  Heinz Wiesinger, Amsterdam, The Netherlands
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  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.

cd $(dirname $0) ; CWD=$(pwd)

PKGNAM=kernel-tools
KERNELRELEASE=${KERNELRELEASE:-$(uname -r)}
VERSION=${VERSION:-$(echo $KERNELRELEASE | tr - _)}
BUILD=${BUILD:-1}

NUMJOBS=${NUMJOBS:-" -j$(expr $(nproc) + 1) "}
export MAKEFLAGS="$NUMJOBS"

if [ -z "$ARCH" ]; then
  case "$( uname -m )" in
    i?86) ARCH=i586 ;;
    arm*) ARCH=arm ;;
       *) ARCH=$( uname -m ) ;;
  esac
fi

# If the variable PRINT_PACKAGE_NAME is set, then this script will report what
# the name of the created package would be, and then exit. This information
# could be useful to other scripts.
if [ ! -z "${PRINT_PACKAGE_NAME}" ]; then
  echo "$PKGNAM-$VERSION-$ARCH-$BUILD.txz"
  exit 0
fi

# The kernel's tools/ build system uses these as its object output directory;
# SBo exports OUTPUT as the package drop-off dir. Not used here.
unset OUTPUT

TMP=${TMP:-/tmp}
PKG=$TMP/package-$PKGNAM

if [ "$ARCH" = "i586" ]; then
  SLKCFLAGS="-O2 -march=i586 -mtune=i686"
  LIBDIRSUFFIX=""
elif [ "$ARCH" = "i686" ]; then
  SLKCFLAGS="-O2 -march=i686 -mtune=i686"
  LIBDIRSUFFIX=""
elif [ "$ARCH" = "x86_64" ]; then
  SLKCFLAGS="-O2 -fPIC"
  LIBDIRSUFFIX="64"
else
  SLKCFLAGS="-O2"
  LIBDIRSUFFIX=""
fi

rm -rf $PKG
mkdir -p $TMP $PKG/usr/doc/$PKGNAM-$VERSION

# This builds in place, inside the kernel-source tree, and leaves object files
# behind there.
KERNELSRC=${KERNELSRC:-/lib/modules/$KERNELRELEASE/build}
if [ ! -d "$KERNELSRC/tools" ]; then
  echo "$(basename $0): no kernel source tree at $KERNELSRC" 1>&2
  exit 1
fi

cd $KERNELSRC/tools || exit 1

# Utility to get per-pid and per-tgid delay accounting statistics
# getdelays - per-task/per-tgid delay accounting
# procacct  - per-process accounting using taskstats
# delaytop  - top-like display of per-task delay accounting
make -C accounting CFLAGS="$SLKCFLAGS -I../include/uapi" || exit 1
for prog in getdelays procacct delaytop ; do
  install -D -m0755 accounting/$prog $PKG/usr/bin/$prog || exit 1
done

# bootconfig utility
make -C bootconfig CFLAGS="$SLKCFLAGS" || exit 1
make -C bootconfig install bindir=/usr/bin DESTDIR=$PKG || exit 1

# BPF utilities
# bpf_asm - Minimal BPF assembler
# bpf_dbg - Minimal BPF debugger
# bpf_jit_disasm - Minimal BPF JIT image disassembler
# bpftool - tool for inspection and simple manipulation of eBPF programs and maps
# resolve_btfids - scans Elf object for .BTF_ids section and resolves its symbols with BTF ID values
#
# Note: bpftool only reports the "skeletons" feature when a kernel BTF blob is
# available at build time, i.e. when the kernel was built with
# CONFIG_DEBUG_INFO_BTF. Without it, bpftool skeleton generation and rtla's BPF
# based sampling are unavailable.
make -C bpf bpf_asm bpf_dbg bpf_jit_disasm bpftool resolve_btfids || exit 1
make -C bpf bpftool_install DESTDIR=$PKG prefix=/usr || exit 1
make -C bpf/bpftool doc || exit 1
make -C bpf/bpftool doc-install DESTDIR=$PKG prefix=/usr || exit 1

install -D -m0755 bpf/bpf_jit_disasm $PKG/usr/sbin/bpf_jit_disasm || exit 1
install -D -m0755 bpf/bpf_dbg $PKG/usr/sbin/bpf_dbg || exit 1
install -D -m0755 bpf/bpf_asm $PKG/usr/sbin/bpf_asm || exit 1
install -D -m0755 bpf/resolve_btfids/resolve_btfids $PKG/usr/sbin/resolve_btfids || exit 1

# Counter tools
# counter_example - example on how to use the counter character device
# counter_watch_events - monitor counter events
CFLAGS="$SLKCFLAGS" make -C counter || exit 1
make -C counter install DESTDIR=$PKG bindir=/usr/bin || exit 1

# Script to decode /proc/sys/kernel/tainted
make -C debugging install DESTDIR=$PKG PREFIX=/usr || exit 1

# Interface to snoop mode driver for TI PCILynx 1394 controllers
# (its install rule has no DESTDIR support and does not create directories)
make -C firewire CFLAGS="$SLKCFLAGS -Wall -g" || exit 1
mkdir -p $PKG/usr/bin
make -C firewire install prefix=$PKG/usr || exit 1

# Parser/loader for IHEX formatted data.
make -C firmware CFLAGS="$SLKCFLAGS -Wall -Wextra -g" || exit 1
install -D -m0755 firmware/ihex2fw $PKG/usr/bin/ihex2fw || exit 1

# GPIO tools
# gpio-event-mon - monitor GPIO line events from userspace
# gpio-hammer - example swiss army knife to shake GPIO lines on a system
# gpio-watch - monitor GPIO line configuration changes
# lsgpio - example on how to list the GPIO lines on a system
CFLAGS="$SLKCFLAGS" make -C gpio V=1 || exit 1
make -C gpio install DESTDIR=$PKG || exit 1

# Hyper-V Tools
make -C hv CFLAGS="$SLKCFLAGS" || exit 1
make -C hv install DESTDIR=$PKG || exit 1

# Industrial I/O utilities
make -C iio CFLAGS="$SLKCFLAGS" || exit 1
make -C iio install DESTDIR=$PKG || exit 1

# Report KVM kernel module event counters
make -C kvm/kvm_stat || exit 1
make -C kvm/kvm_stat install INSTALL_ROOT=$PKG MANDIR=usr/man || exit 1

# Simple Disk Sleep Monitor
make -C laptop/dslm CFLAGS="$SLKCFLAGS" || exit 1
install -D -m0755 laptop/dslm/dslm $PKG/usr/bin/dslm || exit 1

# Disk protection for HP/DELL machines
make -C laptop/freefall CFLAGS="$SLKCFLAGS" || exit 1
install -D -m0755 laptop/freefall/freefall $PKG/usr/bin/freefall || exit 1

# LEDs tools
make -C leds CFLAGS="$SLKCFLAGS -Wall -Wextra -g -I../../include/uapi" || exit 1
install -D -m0755 leds/uledmon $PKG/usr/bin/uledmon || exit 1
install -D -m0755 leds/led_hw_brightness_mon $PKG/usr/bin/led_hw_brightness_mon || exit 1

# libthermal - netlink library for the thermal framework
EXTRA_CFLAGS="$SLKCFLAGS" \
make -C lib/thermal || exit 1
make -C lib/thermal prefix=/usr DESTDIR=$PKG install || exit 1
# Drop static library
rm -f $PKG/usr/lib$LIBDIRSUFFIX/libthermal.a

# vm tools
# page-types: Tool for querying page flags
# page_owner_sort: User-space helper to sort the output of /sys/kernel/debug/page_owner
# slabinfo: Tool to get reports about slabs
# thp_swap_allocator_test / thpmaps: transparent hugepage helpers
CFLAGS="$SLKCFLAGS" make -C mm V=1 || exit 1
make -C mm DESTDIR=$PKG install || exit 1

# ynltool - netdev page-pool and queue statistics, via the YNL netlink library
# The code generator validates the YAML netlink specs against their schema
# with python-jsonschema. That checks the specs and generates nothing, so pass
# the empty schema_path that SpecFamily already treats as "no schema" rather
# than pulling in jsonschema and its dependencies. Building lib/, generated/
# and ynltool/ explicitly also skips net/ynl/tests. Upstream's 'install'
# target runs pip, so install by hand.
sed -i "s/super().__init__(file_name, exclude_ops=exclude_ops)/super().__init__(file_name, schema_path='', exclude_ops=exclude_ops)/" \
  net/ynl/pyynl/ynl_gen_c.py
make -C net/ynl lib generated libynl.a || exit 1
make -C net/ynl/ynltool || exit 1
install -D -m0755 net/ynl/ynltool/ynltool $PKG/usr/bin/ynltool || exit 1

# User-land tool to combine with CONFIG_STACK_VALIDATION
CFLAGS="$SLKCFLAGS" make -C objtool V=1 || exit 1
install -D -m0755 objtool/objtool $PKG/usr/bin/objtool || exit 1
mkdir -p $PKG/usr/doc/$PKGNAM-$VERSION/objtool
cp -a objtool/Documentation/*.txt $PKG/usr/doc/$PKGNAM-$VERSION/objtool/ || exit 1

# Performance analysis utility
# - needs libbpf, libtraceevent and libtracefs
#
# EXTRA_CFLAGS is what actually reaches perf's compiler *and* its feature
# checks - without an -O in there the libperl check trips over the
# "_FORTIFY_SOURCE requires compiling with optimization" warning and
# LIBPERL=1 aborts the build.
#
# -fPIC must NOT be in there though. For the python extension perf does
# 'ifeq ($(filter -fPIC,$(CFLAGS)),)' and only then adds -fPIC to *both*
# CFLAGS and CXXFLAGS. Passing -fPIC ourselves skips that, and perf honours no
# EXTRA_CXXFLAGS, so util/llvm-c-helpers.cpp comes out non-PIC and perf.so
# fails to link with "relocation R_X86_64_32 against `.rodata'".
#
# Optional extras that stay off because the libraries are not in Slackware:
#   libcapstone (nicer 'perf annotate' disassembly), libpfm4, libnuma.
#
# The binaries build fine in parallel; the asciidoc documentation does not, so
# 'install' is run serially. The build itself inherits MAKEFLAGS.
PERF_CFLAGS="$(echo $SLKCFLAGS | sed -e 's/-fPIC//' -e 's/  */ /g')"

make \
  -C perf \
  -f Makefile.perf \
  prefix=/usr \
  mandir=/usr/man \
  tipdir=/doc/$PKGNAM-$VERSION/perf \
  EXTRA_CFLAGS="$PERF_CFLAGS" \
  WERROR=0 \
  NO_SDT=1 \
  NO_LIBNUMA=1 \
  GTK2=1 \
  LIBPERL=1 \
  PYTHON=python3 \
  LIBBPF_DYNAMIC=1 \
  BUILD_BPF_SKEL=1 \
  V=1 \
  VF=1 \
  all || exit 1

make \
  -j1 \
  -C perf \
  -f Makefile.perf \
  prefix=/usr \
  mandir=/usr/man \
  tipdir=/doc/$PKGNAM-$VERSION/perf \
  EXTRA_CFLAGS="$PERF_CFLAGS" \
  WERROR=0 \
  NO_SDT=1 \
  NO_LIBNUMA=1 \
  GTK2=1 \
  LIBPERL=1 \
  PYTHON=python3 \
  LIBBPF_DYNAMIC=1 \
  BUILD_BPF_SKEL=1 \
  V=1 \
  VF=1 \
  DESTDIR=$PKG \
  install || exit 1

mkdir -p $PKG/usr/share/bash-completion/completions/
mv $PKG/etc/bash_completion.d/perf \
  $PKG/usr/share/bash-completion/completions/ || exit 1
rm -rf $PKG/etc/bash_completion.d

# Shows and sets processor power related values
CFLAGS="$SLKCFLAGS" \
make \
  -C power/cpupower \
  prefix=/usr \
  libdir=/usr/lib$LIBDIRSUFFIX \
  mandir=/usr/man \
  docdir=/usr/doc/$PKGNAM-$VERSION/cpupower \
  V=1 \
  SYSTEMD=false \
  DESTDIR=$PKG \
  install || exit 1
# No systemd here, so drop the helper script its unit would have called:
rm -rf $PKG/usr/libexec/cpupower
rmdir $PKG/usr/libexec 2> /dev/null
mv $PKG/etc/cpufreq-bench.conf $PKG/etc/cpufreq-bench.conf.new || exit 1
mv $PKG/etc/cpupower-service.conf $PKG/etc/cpupower-service.conf.new || exit 1
mkdir -p $PKG/etc/{default,rc.d}
install -m 644 $CWD/cpupower.default $PKG/etc/default/cpupower.new || exit 1
install -m 644 $CWD/rc.cpupower $PKG/etc/rc.d/rc.cpupower.new || exit 1

# suspend/resume/boot timing analysis tools
# LIBDIR also decides where the /usr/bin symlinks point, so they are redone
# below rather than patching the Makefile.
make -C power/pm-graph \
  LIBDIR=/usr/lib$LIBDIRSUFFIX \
  MANDIR=/usr/man \
  DESTDIR=$PKG install || exit 1
ln -sf ../lib$LIBDIRSUFFIX/pm-graph/bootgraph.py $PKG/usr/bin/bootgraph
ln -sf ../lib$LIBDIRSUFFIX/pm-graph/sleepgraph.py $PKG/usr/bin/sleepgraph
mkdir -p $PKG/usr/doc/$PKGNAM-$VERSION/pm-graph
cp -a power/pm-graph/README $PKG/usr/doc/$PKGNAM-$VERSION/pm-graph/ || exit 1

# Compile python scripts. '-s $PKG' keeps the build root out of the .pyc files;
# it eats the leading separator with it, so '-p /' puts that back.
python3 -m compileall -s $PKG -p / "$PKG/usr/lib$LIBDIRSUFFIX/pm-graph"
python3 -O -m compileall -s $PKG -p / "$PKG/usr/lib$LIBDIRSUFFIX/pm-graph"

# Intel Speed Select support tool
make -C power/x86/intel-speed-select || exit 1
make -C power/x86/intel-speed-select bindir=/usr/bin DESTDIR=$PKG install || exit 1

# Show CPU frequency and C-state residency on modern Intel turbo-capable processors
# (installs its man page under /usr/share/man; relocated further down)
CFLAGS="$SLKCFLAGS" \
make \
  -C power/x86/turbostat \
  PREFIX=/usr \
  DESTDIR=$PKG \
  install || exit 1

# Set the energy versus performance policy preference bias on recent X86 processors
make -C power/x86/x86_energy_perf_policy || exit 1
make -C power/x86/x86_energy_perf_policy DESTDIR=$PKG install || exit 1

# SPI testing utilities
CFLAGS="$SLKCFLAGS" make -C spi || exit 1
make -C spi install DESTDIR=$PKG bindir=/usr/bin || exit 1

# libthermal_tools - helper library for the thermal tools below
EXTRA_CFLAGS="$SLKCFLAGS" \
make -C thermal/lib || exit 1
# Skip install_headers: it refers to a thermal.h that only exists in
# lib/thermal, whose own install already ships it.
make -C thermal/lib prefix=/usr DESTDIR=$PKG install_lib install_pkgconfig || exit 1
# Drop static library
rm -f $PKG/usr/lib$LIBDIRSUFFIX/libthermal_tools.a

# A temperature capture tool
# Its Makefile assigns (rather than appends to) CFLAGS, so the flags have to be
# passed on the command line, include paths and all.
make -C thermal/thermometer \
  CFLAGS="$SLKCFLAGS -Wall -Wextra -I$KERNELSRC/tools/thermal/lib" || exit 1
install -D -m0644 thermal/thermometer/thermometer.8 $PKG/usr/man/man8/thermometer.8 || exit 1
install -D -m0755 thermal/thermometer/thermometer $PKG/usr/bin/thermometer || exit 1
mkdir -p $PKG/usr/doc/$PKGNAM-$VERSION/thermometer
cp -a thermal/thermometer/thermometer.conf \
  $PKG/usr/doc/$PKGNAM-$VERSION/thermometer/thermometer.conf.example || exit 1

# A thermal monitoring engine based on notifications
make -C thermal/thermal-engine \
  CFLAGS="$SLKCFLAGS -Wall -Wextra -I$KERNELSRC/tools/thermal/lib -I$KERNELSRC/tools/lib/thermal/include" || exit 1
install -D -m0755 thermal/thermal-engine/thermal-engine $PKG/usr/bin/thermal-engine || exit 1

# A monitoring and testing tool for Linux kernel thermal subsystem
CFLAGS="$SLKCFLAGS" make -C thermal/tmon || exit 1
# tmon's install rule is prefixed with '-', so it fails silently if the build
# produced nothing (it needs ncursesw/panelw) - check for the binary ourselves.
make -C thermal/tmon INSTALL_ROOT=$PKG install || exit 1
[ -x $PKG/usr/bin/tmon ] || exit 1
install -D -m0644 thermal/tmon/tmon.8 $PKG/usr/man/man8/tmon.8 || exit 1
mkdir -p $PKG/usr/doc/$PKGNAM-$VERSION/tmon
cp -a thermal/tmon/README $PKG/usr/doc/$PKGNAM-$VERSION/tmon/ || exit 1

# latency-collector
# - needs libtracefs
CFLAGS="$SLKCFLAGS -Wall -Wextra -g" \
make -C tracing/latency prefix=/usr || exit 1
CFLAGS="$SLKCFLAGS -Wall -Wextra -g" \
make -C tracing/latency prefix=/usr DESTDIR=$PKG install || exit 1

# rtla - Real-Time Linux Analysis tools
# - needs libtracefs
# EXTRA_CFLAGS/LDFLAGS point the feature checks at the libcpupower we just
# staged, which is what enables 'rtla timerlat --deepest-idle-state'.
CFLAGS="$SLKCFLAGS -I$PKG/usr/include" \
EXTRA_CFLAGS="-I$PKG/usr/include" \
LDFLAGS="-L$PKG/usr/lib$LIBDIRSUFFIX" \
make -C tracing/rtla MANDIR=/usr/man || exit 1
CFLAGS="$SLKCFLAGS -I$PKG/usr/include" \
EXTRA_CFLAGS="-I$PKG/usr/include" \
LDFLAGS="-L$PKG/usr/lib$LIBDIRSUFFIX" \
make -C tracing/rtla MANDIR=/usr/man DESTDIR=$PKG install || exit 1

# USB device sharing over IP networks
( cd usb/usbip
  ./autogen.sh || exit 1

  CFLAGS="$SLKCFLAGS" \
  ./configure \
    --prefix=/usr \
    --sysconfdir=/etc \
    --libdir=/usr/lib${LIBDIRSUFFIX} \
    --localstatedir=/var \
    --mandir=/usr/man \
    --docdir=/usr/doc/$PKGNAM-$VERSION \
    --with-usbids-dir=/usr/share/hwdata \
    --disable-static \
    --build=$ARCH-slackware-linux || exit 1

  make || exit 1
  make DESTDIR=$PKG install || exit 1

  install -m 644 $CWD/rc.usbipd $PKG/etc/rc.d/rc.usbipd.new || exit 1

  mkdir -p $PKG/usr/doc/$PKGNAM-$VERSION/usbip
  cp -a AUTHORS COPYING INSTALL README \
    $PKG/usr/doc/$PKGNAM-$VERSION/usbip || exit 1
) || exit 1

# rv - Runtime Verification interface
# - needs libtracefs
CFLAGS="$SLKCFLAGS" make -C verification/rv MANDIR=/usr/man || exit 1
CFLAGS="$SLKCFLAGS" make -C verification/rv MANDIR=/usr/man DESTDIR=$PKG install || exit 1

# WMI interface example (Dell SMBIOS)
CFLAGS="$SLKCFLAGS" make -C wmi || exit 1
make -C wmi install DESTDIR=$PKG PREFIX=/usr || exit 1

# Don't ship .la files:
rm -f $PKG/{,usr/}lib${LIBDIRSUFFIX}/*.la

# Several upstream Makefiles hardcode $prefix/share/man. Relocate instead of
# patching each of them:
if [ -d $PKG/usr/share/man ]; then
  mkdir -p $PKG/usr/man
  cp -a $PKG/usr/share/man/* $PKG/usr/man/ || exit 1
  rm -rf $PKG/usr/share/man
fi

# Remove empty directories left behind by the hv tools
rmdir -p --ignore-fail-on-non-empty $PKG/var/lib 2> /dev/null

find $PKG -print0 | xargs -0 file | grep -e "executable" -e "shared object" | grep ELF \
  | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true

find $PKG/usr/man -type f -exec gzip -9 {} \;
for i in $( find $PKG/usr/man -type l ) ; do ln -s $( readlink $i ).gz $i.gz ; rm $i ; done

cp -a $KERNELSRC/COPYING $PKG/usr/doc/$PKGNAM-$VERSION/

find $PKG/usr/doc/$PKGNAM-$VERSION -type f -exec chmod 0644 {} \;

mkdir -p $PKG/install
cat $CWD/slack-desc > $PKG/install/slack-desc
zcat $CWD/doinst.sh.gz > $PKG/install/doinst.sh

cd $PKG
/sbin/makepkg -l y -c n $TMP/$PKGNAM-$VERSION-$ARCH-$BUILD.txz
