diff options
author | Slack Coder <slackcoder@server.ky> | 2024-02-16 11:42:34 -0500 |
---|---|---|
committer | Slack Coder <slackcoder@server.ky> | 2024-03-16 14:26:39 -0500 |
commit | d0c7803ddd1b99261fbbddd000e888ee7ef555f7 (patch) | |
tree | 2eeba46dfdd7921de576a967221525b15c68e1c8 /src | |
download | slack-autoupdate-d0c7803ddd1b99261fbbddd000e888ee7ef555f7.tar.xz |
Initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/autoupdate | 186 | ||||
-rw-r--r-- | src/install-kernel | 22 | ||||
-rw-r--r-- | src/rc.update | 56 | ||||
-rwxr-xr-x | src/test/bin/chmod | 2 | ||||
-rwxr-xr-x | src/test/bin/chown | 2 | ||||
-rwxr-xr-x | src/test/bin/tar | 2 | ||||
-rw-r--r-- | src/test/test_autoupdate.sh | 129 |
7 files changed, 399 insertions, 0 deletions
diff --git a/src/autoupdate b/src/autoupdate new file mode 100644 index 0000000..04e432b --- /dev/null +++ b/src/autoupdate @@ -0,0 +1,186 @@ +#!/bin/bash +# +# Update your system automatically! +# +# Packages from different sources are downloaded, under sub-shells, into the +# PACKAGE_DIR where they can be installed on reboot. +# +# A failure encountered at any point should abort any pending package updates +# to install. +# +# To enable sbotools updates, make the /etc/sbotools/sbotools.conf file exist +# and configure PKG_DIR to point to the same path as STAGING_DIR. + +# Set to "yes" to send notification to stdout, causing cron to send an email. +NOTIFY="${NOTIFY:-no}" + +# Reboot after this period for install after a successful update. +# +# Set to empty to disable reboot or 'now' to reboot immediately. +export REBOOT_TIME="${REBOOT_TIME:-""}" + +# Packages are copied here on successful download. +export PACKAGE_DIR="${PACKAGE_DIR:-/var/spool/slack-autoupdate}" + +# Packages are temperarily stored here until success. +export STAGING_DIR="${STAGING_DIR:-/var/cache/slack-autoupdate/staging}" + +# Information of interest to the admin on success. +export UPDATE_INFO="${UPDATE_INFO:-$STAGING_DIR/info.txt}" + +# Information of interest to the admin on failure. +export UPDATE_ERROR="${UPDATE_ERROR:-$STAGING_DIR/error.txt}" + +# Slackware mirror containing packages. +export SLACKWARE_MIRROR="${SLACKWARE_MIRROR:-rsync://mirrors.kernel.org/slackware/slackware64-15.0}" + +# A local Slackware mirror with just enough information to support slackpkg. +# +# This step could be skipped if slackpkg supports downloading updates without +# installing them. +export LOCAL_MIRROR=${LOCAL_MIRROR:-"/var/cache/slack-autoupdate/mirror"} + +# Avoid concurrently running with another instance. +if [ "$(ls /var/lock/autoupdate.* 2>/dev/null)" ]; then + echo "Another instance of autoupdate is running. If this is not correct, you can remove /var/lock/autoupdate.* files and run autoupdate again." \ + >>"$PACKAGE_DIR/$(basename $UPDATE_ERROR)" + if [ "$NOTIFY" = "yes" ]; then + cat "$PACKAGE_DIR/$(basename $UPDATE_ERROR)" + fi + + exit 1 +fi + +touch /var/lock/autoupdate.$$ +trap "rm -f /var/lock/autoupdate.$$" EXIT + +# Keep it simple stupid, install pending updates first. +mkdir --parents "$PACKAGE_DIR" +if [ -n "$(find "$PACKAGE_DIR" -name "*.t*z")" ]; then + exit 0 +fi + +# This is slackpkg's exit code when updates are available. +SLACKPKG_UPDATES_PENDING=100 + +slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates >/dev/null 2>&1 +if [ "$?" -eq "$SLACKPKG_UPDATES_PENDING" ]; then + exit 0 +fi + +# Make the set of package updates available atomically by storing them in a +# temporary location until completion. +rm -fr "$STAGING_DIR" +mkdir --parents "$STAGING_DIR" + +if ! OUTPUT="$( + # Capture this subshell's error output to standard output. + exec 2>&1 + + ( + echo "downloading updates from $SLACKWARE_MIRROR..." + + # Support slackpkg with the least required files for patches. + mkdir --parents "$LOCAL_MIRROR" + cd "$LOCAL_MIRROR" \ + && rsync "$SLACKWARE_MIRROR/CHECKSUMS.md5" . \ + && rsync "$SLACKWARE_MIRROR/CHECKSUMS.md5.asc" . \ + && rsync "$SLACKWARE_MIRROR/ChangeLog.txt" . \ + && rsync "$SLACKWARE_MIRROR/FILELIST.TXT" . \ + && rsync "$SLACKWARE_MIRROR/GPG-KEY" . \ + && rsync "$SLACKWARE_MIRROR/extra" . \ + && rsync "$SLACKWARE_MIRROR/pasture" . \ + && rsync "$SLACKWARE_MIRROR/patches" . \ + && rsync "$SLACKWARE_MIRROR/testing" . \ + && rsync "$SLACKWARE_MIRROR/slackware64/PACKAGES.TXT" slackware64 + ) || exit $? + + slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates + if [ "$?" -ne "$SLACKPKG_UPDATES_PENDING" ]; then + exit 0 + fi + + ( + # Redirect this subshell's standard output to info file. + exec 1>>"$UPDATE_INFO" + + echo "Slackware updates" + echo + slackpkg show-changelog | diff - "$LOCAL_MIRROR/ChangeLog.txt" + echo + ) +)"; then + >>"$UPDATE_ERROR" echo -e "slackpkg:\n\n$OUTPUT" +fi + +if ! OUTPUT="$( + exec 2>&1 + + if [ ! -f /etc/sbotools/sbotools.conf ] \ + || [ "$(sed -n 's/PKG_DIR=//p' /etc/sbotools/sbotools.conf)" != "$STAGING_DIR" ]; then + # Assume sbotools is disabled. + exit 0 + fi + + UPDATE_INFO=$(mktemp /tmp/sbocheck.XXXXXX) + + (sbocheck | tee $UPDATE_INFO) || exit 1 + if grep -i "no updates available" "$UPDATE_INFO"; then + exit 0 + fi + + sboupgrade \ + --all \ + --noinstall \ + --nointeractive \ + || exit "$?" + + ( + exec 1>>"$UPDATE_INFO" + + echo "Slackbuild updates" + echo + cat "$UPDATE_INFO" + echo + ) +)"; then + if [ -f "$UPDATE_ERROR" ]; then + >>"$UPDATE_ERROR" echo "" + >>"$UPDATE_ERROR" echo "" + fi + + >>"$UPDATE_ERROR" echo -e "sbotools:\n\n$OUTPUT" +fi + +# Make updates atomic. +if [ -f "$UPDATE_ERROR" ]; then + mv "$UPDATE_ERROR" "$PACKAGE_DIR" + mv "$UPDATE_INFO" "$PACKAGE_DIR" + + exit 1 +fi + + +mv "$STAGING_DIR"/* "$PACKAGE_DIR/" +rm -fr "$STAGING_DIR" + +if [ -z "$(find "$PACKAGE_DIR" -name "*.t*z" -or -name "info.txt" -or -name "error.txt")" ]; then + # No updates + exit 0 +fi + +if [ "$NOTIFY" = "yes" ]; then + if [ -f "$UPDATE_ERROR" ]; then + echo "Failures were encountered while trying to download updates" + echo "" + cat "$UPDATE_ERROR" + elif [ -f "$UPDATE_INFO" ]; then + echo "Updates pending installation" + echo "" + cat "$UPDATE_INFO" + fi +fi + +if [ -n "$REBOOT_TIME" ]; then + nohup shutdown -r "$REBOOT_TIME" >/dev/null 2>&1 & +fi diff --git a/src/install-kernel b/src/install-kernel new file mode 100644 index 0000000..42db67a --- /dev/null +++ b/src/install-kernel @@ -0,0 +1,22 @@ +#!/bin/sh +# +# System local command to install the kernel into the system boot loader. +# + +# The /boot/vmlinuz-huge softlink points to the last installed kernel. +KERNEL_VERSION="$(realpath /boot/vmlinuz-huge | sed 's/.*\/.*-\(.*\)/\1/')" +if [ "$1" ]; then + KERNEL_VERSION="$(echo "$1" | sed 's/.*\/.*-\(.*\)/\1/')" +fi + +if [ -z "$KERNEL_VERSION" ]; then + >&2 echo "The kernel version could not be detected from the filename." + exit 1 +fi + +echo "Installing kernel version $KERNEL_VERSION into the efi..." +cp -H /boot/vmlinuz-huge /efi/EFI/Slackware/vmlinuz +if [ -f /etc/mkinitrd.conf ]; then + echo "Installing initialized ram disk into the efi..." + mkinitrd -F -k "$KERNEL_VERSION" >/dev/null +fi diff --git a/src/rc.update b/src/rc.update new file mode 100644 index 0000000..db384ca --- /dev/null +++ b/src/rc.update @@ -0,0 +1,56 @@ +#!/bin/bash +# +# Automatically update your system on reboot using packages in the UPDATE_DIR. +# +# Sometimes there are additional steps to make when your kernel is updated. +# You can define these in a custom 'install-kernel' command which this script +# will run if found. We recommend placing this under /usr/local/sbin. +# + +# A local Slackware mirror with just enough information to support slackpkg. +# +# This step could be skipped if slackpkg supports downloading updates without +# installing them. +LOCAL_MIRROR=${LOCAL_MIRROR:-"/var/cache/slack-autoupdate/mirror"} + +# slackpkg exit code when updates are available. +SLACKPKG_UPDATES_PENDING=100 + +# Where packages are stored pending installation. You can use sub-directories +# to order and group packages. +UPDATE_DIR="/var/spool/slack-autoupdate" + +# Where information about pending updates is stored. +UPDATE_INFO="$UPDATE_DIR/info.txt" + +# Where information about failed updates is stored. +UPDATE_ERROR="$UPDATE_DIR/error.txt" + +UPDATES=$(find "$UPDATE_DIR" -name '*.t*z' | sort) +SLACKPKG_UPDATES="$(slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates >&-; echo $?)" + +if [ -z "$UPDATES" -a "$SLACKPKG_UPDATES" -ne "$SLACKPKG_UPDATES_PENDING" ]; then + exit 0 +fi + +if read -r -t 5 -p "Installing updates, press enter to skip this process..."; then + exit 0 +fi + +OLD_KERNEL="$(realpath /boot/vmlinuz)" +for PKG in $UPDATES; do + upgradepkg --install-new "$PKG" && + rm "$PKG" +done + +NEW_KERNEL="$(realpath /boot/vmlinuz)" +if [ "$OLD_KERNEL" -ne "$NEW_KERNEL" ]; then + if command -v install-kernel &> /dev/null; then + install-kernel "$NEW_KERNEL" + fi +fi + +# All package updates have been processed. +find "$UPDATE_DIR" -mindepth 1 -not -path "$UPDATE_DIR_IGNORED/*" | xargs rm -fr + +reboot diff --git a/src/test/bin/chmod b/src/test/bin/chmod new file mode 100755 index 0000000..06bd986 --- /dev/null +++ b/src/test/bin/chmod @@ -0,0 +1,2 @@ +#!/bin/bash +exit 0 diff --git a/src/test/bin/chown b/src/test/bin/chown new file mode 100755 index 0000000..06bd986 --- /dev/null +++ b/src/test/bin/chown @@ -0,0 +1,2 @@ +#!/bin/bash +exit 0 diff --git a/src/test/bin/tar b/src/test/bin/tar new file mode 100755 index 0000000..5f3f66b --- /dev/null +++ b/src/test/bin/tar @@ -0,0 +1,2 @@ +#!/bin/bash +exec /usr/bin/tar --no-same-owner -$1 $2 diff --git a/src/test/test_autoupdate.sh b/src/test/test_autoupdate.sh new file mode 100644 index 0000000..e2eaf08 --- /dev/null +++ b/src/test/test_autoupdate.sh @@ -0,0 +1,129 @@ +#/bin/bash +# +# The test assumes you are running Slackware on a 64 bit system. +# + +# Packages are copied here on successful download. +export PACKAGE_DIR="${PACKAGE_DIR:-/var/spool/slack-autoupdate}" + +# Packages are temperarily stored here until success. +export STAGING_DIR="${STAGING_DIR:-/var/cache/slack-autoupdate/staging}" + +# The system's local Slackware mirror. +export LOCAL_MIRROR=${LOCAL_MIRROR:-"/var/cache/slack-autoupdate/mirror"} + +# Use fake chmod and chown commands to avoid errors when making packages. +BIN_DIR="$(realpath $(dirname "${BASH_SOURCE[0]}"))/bin" + +TEST_DIR="$( + mktemp \ + --directory \ + --tmpdir="$TMP" \ + autoupdate.XXXXXX +)" || exit 1 +trap "rm -fr $TEST_DIR" EXIT + +mkdir -p \ + "$TEST_DIR/tmp" \ + "$TEST_DIR/etc/sbotools" \ + "$TEST_DIR/etc/slackpkg" \ + "$TEST_DIR/root" \ + "$TEST_DIR/tmp" \ + "$TEST_DIR/usr/sbo" \ + "$TEST_DIR/var/cache" \ + "$TEST_DIR/var/lib" \ + "$TEST_DIR/var/lock" \ + "$TEST_DIR/var/log" \ + "$TEST_DIR/var/spool" + +if ! command -v bwrap &> /dev/null +then + echo "bwrap could not be found. The 'bubblewrap' application must be installed to run this test." + exit 1 +fi + +# Slackpkg etc. require a fake root user and filesystem. +export INSTANCE="\ +bwrap \ + --unshare-user --uid 0 --gid 0 \ + --setenv "HOME" "/root" \ + --ro-bind / / \ + --dev /dev \ + --bind "$TEST_DIR/tmp" "/tmp" \ + --bind "$TEST_DIR/etc/sbotools" /etc/sbotools \ + --bind "$TEST_DIR/etc/slackpkg" /etc/slackpkg \ + --bind "$TEST_DIR/root" /root \ + --bind "$BIN_DIR" /usr/local/bin \ + --bind "$TEST_DIR/usr/sbo" /usr/sbo \ + --bind "$TEST_DIR/var" /var \ + --" + +$INSTANCE ln -s ../lib/pkgtools/packages "/var/log/packages" + +echo "Preparing slackpkg test case" +( + mkdir -p "$TEST_DIR/etc" + cp --recursive /etc/slackpkg "$TEST_DIR/etc/" + + echo http://mirrors.kernel.org/slackware/slackware64-14.2/ > "$TEST_DIR/etc/slackpkg/mirrors" + echo "WGETFLAGS=\"-4 --quiet\"" >> "$TEST_DIR/etc/slackpkg/slackpkg.conf" # REMOVE ME + yes | $INSTANCE slackpkg update >/dev/null || exit 1 + echo http://mirrors.kernel.org/slackware/slackware64-15.0/ > "$TEST_DIR/etc/slackpkg/mirrors" +) + +echo "Preparing sbotools test case" +( + $INSTANCE sboconfig --pkg-dir "$STAGING_DIR" >/dev/null + + mkdir -p "$TEST_DIR/var/lib/pkgtools/packages" + touch "$TEST_DIR/var/lib/pkgtools/packages/bubblewrap-0.7.0-x86_64-1_SBo" + $INSTANCE sbosnap fetch +) + +echo "" +echo "Running autoupdate..." +echo "" + +# Display a helpful message and successful exit code by tracking total success. +TESTS_PASS=true + +if ! $INSTANCE bash $(dirname "${BASH_SOURCE[0]}")/../autoupdate; then + TESTS_PASS=false + + echo "autoupdate failed" + cat "$TEST_DIR/$PACKAGE_DIR/error.txt" +elif [ -f "$TEST_DIR/$PACKAGE_DIR/error.txt" ]; then + TESTS_PASS=false + + cat "$TEST_DIR/$PACKAGE_DIR/error.txt" +fi + +if [ ! -f "$TEST_DIR/$PACKAGE_DIR/info.txt" ]; then + TESTS_PASS=false + + echo "expected '$PACKAGE_DIR/info.txt' file to be created" +fi + +$INSTANCE slackpkg -mirror="file:///$LOCAL_MIRROR/" check-updates >/dev/null +if [ "$?" -ne 100 ]; then + TESTS_PASS=false + + echo "slackpkg: expected to have updates available but had exit code $?" +else + echo "slackpkg: ok" +fi + +if [ -f "$TEST_DIR/etc/sbotools/sbotools.conf" ] \ + && [ -z "$(find "$TEST_DIR/$PACKAGE_DIR" -name 'bubblewrap-*.t*z')" ]; then + TESTS_PASS=false + + echo "sbotools: expected to have bubblewrap package update" +else + echo "sbotools: ok" +fi + +if [ "$TESTS_PASS" = true ]; then + echo "all tests pass" +else + exit 1 +fi |