Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/bin/bash
- # Xanmod4Slack - Universal XanMod Kernel Builder and Package Manager
- # Compatible with: Slackware, Debian, Devuan, and derivatives
- # Supports: systemd, OpenRC, runit, dinit, shepherd, sysvinit
- # Supports: GRUB2, GRUB Legacy, LILO, ELILO, SYSLINUX, systemd-boot, EFISTUB
- # Version: 2.1.0 (bugfix revision)
- set -o pipefail
- # --- Color definitions for terminal output ---
- RED='\033[0;31m'
- GREEN='\033[0;32m'
- YELLOW='\033[0;33m'
- BLUE='\033[0;34m'
- NC='\033[0m' # No Color
- # --- Configuration ---
- VERSION="2.1.0"
- CONFIG_DIR="${HOME}/.config/xanmod4slack"
- CONFIG_FILE="${CONFIG_DIR}/xanmod4slack.conf"
- LOG_DIR="${HOME}/.local/log/xanmod4slack"
- LOG_FILE="${LOG_DIR}/xanmod4slack.log"
- WORK_DIR="${HOME}/src/xanmod"
- XANMOD_REPO="https://github.com/xanmod/linux.git"
- XANMOD_BRANCH="master"
- NOTIFICATION_SENT_FILE="${CONFIG_DIR}/last_notification"
- # --- Default Configuration Values ---
- DEFAULT_UPDATE_FREQ="weekly"
- DEFAULT_INTERFACE="auto"
- DEFAULT_KEEP_OLD="3"
- DEFAULT_AUTO_UPDATE="false"
- DEFAULT_AUTO_CLEANUP="false"
- DEFAULT_SILENT_NOTIFICATIONS="false"
- DEFAULT_DETECT_HARDWARE="true"
- DEFAULT_CUSTOM_CONFIG=""
- DEFAULT_MARCH="native"
- # --- Initialize directories ---
- mkdir -p "${CONFIG_DIR}" "${LOG_DIR}" "${WORK_DIR}"
- touch "${LOG_FILE}"
- # --- Functions ---
- # FIX: log() now writes ONLY to the log file and to stderr (fd 2).
- # The original wrote to stdout via `tee`, which silently corrupted
- # every function whose return value was captured with $(function_name),
- # since log messages got mixed into the captured string.
- log() {
- local msg="[$(date '+%Y-%m-%d %H:%M:%S')] $1"
- echo "$msg" >> "${LOG_FILE}"
- echo "$msg" >&2
- }
- # error() is for genuinely fatal, top-level failures only.
- # It is intentionally NOT called from inside functions that are invoked
- # via command substitution $(...), because exit inside a subshell only
- # kills that subshell, not the parent script (see functions below, which
- # use `log "ERROR: ..."; return 1` instead and let the caller decide).
- error() {
- log "ERROR: $1"
- if [ -n "$2" ]; then
- show_msg "Error" "$1" "error"
- fi
- exit 1
- }
- # FIX: added — nothing in the original checked for root before doing
- # privileged work (installing packages, writing to /boot, editing
- # bootloader configs). It would just fail confusingly partway through.
- require_root() {
- if [ "$(id -u)" -ne 0 ]; then
- log "ERROR: This action requires root privileges. Re-run with sudo."
- return 1
- fi
- return 0
- }
- load_config() {
- if [ -f "${CONFIG_FILE}" ]; then
- source "${CONFIG_FILE}"
- log "Loaded configuration from ${CONFIG_FILE}"
- else
- log "No configuration file found. Using defaults."
- UPDATE_FREQ="${DEFAULT_UPDATE_FREQ}"
- INTERFACE="${DEFAULT_INTERFACE}"
- KEEP_OLD="${DEFAULT_KEEP_OLD}"
- AUTO_UPDATE="${DEFAULT_AUTO_UPDATE}"
- AUTO_CLEANUP="${DEFAULT_AUTO_CLEANUP}"
- SILENT_NOTIFICATIONS="${DEFAULT_SILENT_NOTIFICATIONS}"
- DETECT_HARDWARE="${DEFAULT_DETECT_HARDWARE}"
- CUSTOM_CONFIG="${DEFAULT_CUSTOM_CONFIG}"
- MARCH="${DEFAULT_MARCH}"
- fi
- }
- save_config() {
- cat > "${CONFIG_FILE}" << EOF
- # Xanmod4Slack Configuration
- UPDATE_FREQ="${UPDATE_FREQ:-$DEFAULT_UPDATE_FREQ}"
- INTERFACE="${INTERFACE:-$DEFAULT_INTERFACE}"
- KEEP_OLD="${KEEP_OLD:-$DEFAULT_KEEP_OLD}"
- AUTO_UPDATE="${AUTO_UPDATE:-$DEFAULT_AUTO_UPDATE}"
- AUTO_CLEANUP="${AUTO_CLEANUP:-$DEFAULT_AUTO_CLEANUP}"
- SILENT_NOTIFICATIONS="${SILENT_NOTIFICATIONS:-$DEFAULT_SILENT_NOTIFICATIONS}"
- DETECT_HARDWARE="${DETECT_HARDWARE:-$DEFAULT_DETECT_HARDWARE}"
- CUSTOM_CONFIG="${CUSTOM_CONFIG:-$DEFAULT_CUSTOM_CONFIG}"
- MARCH="${MARCH:-$DEFAULT_MARCH}"
- EOF
- log "Configuration saved to ${CONFIG_FILE}"
- }
- detect_distro() {
- if [ -f /etc/debian_version ]; then
- echo "debian"
- elif [ -f /etc/slackware-version ]; then
- echo "slackware"
- else
- echo "unknown"
- fi
- }
- detect_init() {
- if pidof -q systemd 2>/dev/null && [ -d /run/systemd/system ]; then
- echo "systemd"
- return
- fi
- if command -v openrc-init &> /dev/null; then
- echo "openrc"
- return
- fi
- if command -v runsvdir &> /dev/null; then
- echo "runit"
- return
- fi
- if command -v dinit &> /dev/null; then
- echo "dinit"
- return
- fi
- if command -v shepherd &> /dev/null; then
- echo "shepherd"
- return
- fi
- if [ -f /sbin/init ] && file /sbin/init 2>/dev/null | grep -q "sysvinit"; then
- echo "sysvinit"
- return
- fi
- echo "unknown"
- }
- # FIX: the original efistub test was `[ -f /boot/vmlinuz-* ]`, which does
- # NOT expand the wildcard inside single-bracket test — it just tests the
- # literal string "/boot/vmlinuz-*", which never exists, so this branch
- # could never actually trigger. Replaced with `compgen -G`, which is the
- # correct way to test "does at least one file match this glob".
- detect_bootloader() {
- if command -v grub-mkconfig &> /dev/null; then
- echo "grub2"
- return
- elif [ -f /boot/grub/menu.lst ] || [ -f /boot/grub/grub.conf ]; then
- echo "grub-legacy"
- return
- elif command -v lilo &> /dev/null && [ -f /etc/lilo.conf ]; then
- echo "lilo"
- return
- elif command -v elilo &> /dev/null && [ -f /etc/elilo.conf ]; then
- echo "elilo"
- return
- elif command -v extlinux &> /dev/null || [ -f /boot/extlinux/extlinux.conf ]; then
- echo "syslinux"
- return
- elif [ -d /boot/efi/EFI/systemd ] || [ -d /boot/EFI/systemd ]; then
- echo "systemd-boot"
- return
- elif [ -d /sys/firmware/efi ] && compgen -G "/boot/vmlinuz-*" > /dev/null; then
- echo "efistub"
- return
- else
- echo "unknown"
- return
- fi
- }
- detect_interface() {
- if [ -n "$DISPLAY" ] && [ -x "$(command -v zenity)" ]; then
- echo "gui"
- elif [ -n "$DISPLAY" ] && [ -x "$(command -v kdialog)" ]; then
- echo "gui"
- elif [ -x "$(command -v dialog)" ]; then
- echo "dialog"
- else
- echo "text"
- fi
- }
- show_msg() {
- local title="$1"
- local message="$2"
- local type="${3:-info}"
- local interface="${INTERFACE:-auto}"
- if [ "$interface" = "auto" ]; then
- interface=$(detect_interface)
- fi
- case "$interface" in
- gui)
- if [ -x "$(command -v zenity)" ]; then
- zenity --${type} --title="${title}" --text="${message}" --width=400 --timeout=30 2>/dev/null || true
- elif [ -x "$(command -v kdialog)" ]; then
- kdialog --${type} "${message}" --title "${title}" 2>/dev/null || true
- else
- echo "=== ${title} ==="
- echo "${message}"
- fi
- ;;
- dialog)
- dialog --title "${title}" --msgbox "${message}" 10 60 2>/dev/null || true
- ;;
- *)
- echo "=== ${title} ==="
- echo "${message}"
- ;;
- esac
- }
- show_question() {
- local title="$1"
- local message="$2"
- local interface="${INTERFACE:-auto}"
- if [ "$interface" = "auto" ]; then
- interface=$(detect_interface)
- fi
- case "$interface" in
- gui)
- if [ -x "$(command -v zenity)" ]; then
- zenity --question --title="${title}" --text="${message}" --width=400 2>/dev/null && return 0 || return 1
- elif [ -x "$(command -v kdialog)" ]; then
- kdialog --yesno "${message}" --title "${title}" 2>/dev/null && return 0 || return 1
- else
- echo "${message} (y/N): "
- read -r answer
- [[ "$answer" =~ ^[Yy]$ ]] && return 0 || return 1
- fi
- ;;
- dialog)
- dialog --title "${title}" --yesno "${message}" 10 60 2>/dev/null && return 0 || return 1
- ;;
- *)
- echo "${message} (y/N): "
- read -r answer
- [[ "$answer" =~ ^[Yy]$ ]] && return 0 || return 1
- ;;
- esac
- }
- show_menu() {
- local title="$1"
- local prompt="$2"
- shift 2
- local options=("$@")
- local interface="${INTERFACE:-auto}"
- local choice=""
- local i=0
- if [ "$interface" = "auto" ]; then
- interface=$(detect_interface)
- fi
- case "$interface" in
- gui)
- if [ -x "$(command -v zenity)" ]; then
- local menu_items=()
- i=0
- while [ $i -lt ${#options[@]} ]; do
- menu_items+=("${options[$i]}" "${options[$i+1]}")
- i=$((i+2))
- done
- choice=$(zenity --list --title="${title}" --text="${prompt}" \
- --column="Option" --column="Description" \
- "${menu_items[@]}" --width=600 --height=400 2>/dev/null || echo "cancel")
- echo "$choice"
- return
- elif [ -x "$(command -v kdialog)" ]; then
- local menu_string=""
- i=0
- while [ $i -lt ${#options[@]} ]; do
- menu_string="${menu_string}${options[$i]} \"${options[$i+1]}\" "
- i=$((i+2))
- done
- choice=$(kdialog --menu "${prompt}" ${menu_string} --title "${title}" 2>/dev/null || echo "cancel")
- echo "$choice"
- return
- else
- echo "cancel"
- return
- fi
- ;;
- dialog)
- local menu_items=()
- i=0
- while [ $i -lt ${#options[@]} ]; do
- menu_items+=("${options[$i]}" "${options[$i+1]}")
- i=$((i+2))
- done
- choice=$(dialog --title "${title}" --menu "${prompt}" 20 60 10 "${menu_items[@]}" 2>&1 >/dev/tty || echo "cancel")
- echo "$choice"
- return
- ;;
- *)
- echo "=== ${title} ==="
- echo "${prompt}"
- i=0
- while [ $i -lt ${#options[@]} ]; do
- echo " ${options[$i]}) ${options[$i+1]}"
- i=$((i+2))
- done
- echo -n "Select option: "
- read -r choice
- echo "${choice}"
- return
- ;;
- esac
- }
- detect_hardware() {
- log "Detecting hardware..."
- local hw_profile="${WORK_DIR}/hw_profile.txt"
- mkdir -p "$(dirname "$hw_profile")"
- {
- echo "# Hardware Profile for Xanmod Kernel"
- echo "Generated: $(date)"
- echo ""
- echo "=== CPU ==="
- lscpu 2>/dev/null || cat /proc/cpuinfo 2>/dev/null | head -20
- echo ""
- echo "=== PCI Devices ==="
- lspci -k 2>/dev/null || echo "lspci not available"
- echo ""
- echo "=== USB Devices ==="
- lsusb 2>/dev/null || echo "lsusb not available"
- echo ""
- echo "=== Block Devices ==="
- lsblk 2>/dev/null || echo "lsblk not available"
- echo ""
- echo "=== Network ==="
- ip link show 2>/dev/null || ifconfig -a 2>/dev/null
- echo ""
- echo "=== DMI Info ==="
- dmidecode -t system 2>/dev/null || echo "dmidecode not available (needs root)"
- echo ""
- echo "=== Kernel Modules ==="
- lsmod 2>/dev/null | head -20
- } > "$hw_profile"
- log "Hardware profile saved to $hw_profile"
- return 0
- }
- generate_optimized_config() {
- log "Generating optimized kernel config..."
- if ! command -v make &> /dev/null; then
- log "ERROR: make is required but not installed"
- return 1
- fi
- if [ -f "${WORK_DIR}/.config" ]; then
- rm "${WORK_DIR}/.config"
- fi
- make -C "${WORK_DIR}" defconfig 2>&1 | while IFS= read -r line; do log "$line"; done
- if [ ! -f "${WORK_DIR}/.config" ]; then
- log "ERROR: Failed to generate default config"
- return 1
- fi
- if [ "${DETECT_HARDWARE}" = "true" ]; then
- log "Applying localmodconfig to strip unnecessary drivers..."
- make -C "${WORK_DIR}" localmodconfig 2>&1 | while IFS= read -r line; do log "$line"; done \
- || log "Warning: localmodconfig failed"
- fi
- local march_flag=""
- case "${MARCH}" in
- native) march_flag="-march=native" ;;
- v3) march_flag="-march=x86-64-v3" ;;
- v4) march_flag="-march=x86-64-v4" ;;
- generic) march_flag="-march=x86-64" ;;
- *) march_flag="-march=native" ;;
- esac
- log "Using CPU optimization flag: ${march_flag}"
- "${WORK_DIR}/scripts/config" --file "${WORK_DIR}/.config" --set-val CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE y 2>/dev/null || true
- if [ -n "${CUSTOM_CONFIG}" ] && [ -f "${CUSTOM_CONFIG}" ]; then
- log "Applying custom configuration from ${CUSTOM_CONFIG}"
- cp "${CUSTOM_CONFIG}" "${WORK_DIR}/.config" || { log "ERROR: Failed to apply custom config"; return 1; }
- fi
- log "Hardware detection and optimization completed"
- return 0
- }
- # FIX: the original tag regex `refs/tags/v[0-9]+\.[0-9]+\.[0-9]+$` requires
- # the tag to end exactly at X.Y.Z. Real XanMod release tags are typically
- # named like v6.9.1-xanmod1 (a build-number suffix after the kernel
- # version), so the old pattern would likely never match a real tag at all.
- # This version accepts an optional -xanmodN suffix.
- check_updates() {
- log "Checking for XanMod updates..."
- if ! command -v git &> /dev/null; then
- log "ERROR: git is not installed"
- show_msg "Error" "git is required but not installed. Please install git first." "error"
- return 1
- fi
- mkdir -p "${WORK_DIR}"
- local remote_version=""
- local local_version=""
- remote_version=$(git ls-remote --tags "${XANMOD_REPO}" 2>/dev/null \
- | grep -E "refs/tags/v[0-9]+\.[0-9]+(\.[0-9]+)?(-xanmod[0-9]+)?$" \
- | sed 's|.*refs/tags/||' | sort -V | tail -n1)
- if [ -d "${WORK_DIR}/.git" ]; then
- local_version=$(git -C "${WORK_DIR}" describe --tags --abbrev=0 2>/dev/null)
- fi
- if [ -z "$remote_version" ]; then
- log "ERROR: Could not determine latest version (check network / tag format)"
- return 1
- fi
- if [ -z "$local_version" ] || [ "$remote_version" != "$local_version" ]; then
- log "New version available: $remote_version (current: ${local_version:-none})"
- echo "$remote_version"
- return 0
- else
- log "Already up to date: $local_version"
- echo "$local_version"
- return 1
- fi
- }
- send_notification() {
- local title="$1"
- local message="$2"
- local urgency="${3:-normal}"
- if [ "${SILENT_NOTIFICATIONS}" = "true" ]; then
- log "Notifications silenced. Would have sent: $title"
- return 0
- fi
- local interface
- interface=$(detect_interface)
- case "$interface" in
- gui)
- if [ -x "$(command -v notify-send)" ]; then
- notify-send -u "${urgency}" "${title}" "${message}" 2>/dev/null || true
- elif [ -x "$(command -v zenity)" ]; then
- zenity --notification --text="${title}: ${message}" 2>/dev/null || true
- fi
- ;;
- *)
- echo "${title}: ${message}"
- ;;
- esac
- log "Notification sent: $title - $message"
- }
- # FIX: this is the function that most needed the log()/stdout separation.
- # It is routinely called as `local new_version=$(build_kernel)`, so ANY
- # plain command output that used to land on stdout (git clone/fetch text,
- # make's build output via the old `2>&1`) would get captured right along
- # with the intended return value, corrupting $new_version. Every
- # diagnostic/build command below is now redirected into the log file
- # instead of stdout. The ONLY thing this function prints to stdout is the
- # final `echo "$latest_version"` on success.
- build_kernel() {
- log "Building XanMod kernel..."
- if ! command -v make &> /dev/null || ! command -v gcc &> /dev/null; then
- log "ERROR: Build tools (make, gcc) are not installed. Please install them first."
- return 1
- fi
- if [ "$(id -u)" -eq 0 ]; then
- log "Warning: running the build as root is not recommended (source tree will be root-owned). Consider building as a regular user and only using sudo for the install step."
- fi
- if [ ! -d "${WORK_DIR}/.git" ]; then
- log "Cloning XanMod repository (this can take a while)..."
- git clone "${XANMOD_REPO}" "${WORK_DIR}" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to clone repository"; return 1; }
- else
- log "Updating XanMod repository..."
- git -C "${WORK_DIR}" fetch --tags >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to fetch updates"; return 1; }
- fi
- local latest_version
- latest_version=$(git -C "${WORK_DIR}" describe --tags --abbrev=0 2>/dev/null)
- if [ -z "$latest_version" ]; then
- log "ERROR: Failed to determine latest version from repository"
- return 1
- fi
- log "Checking out version: $latest_version"
- git -C "${WORK_DIR}" checkout "${latest_version}" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to checkout latest version"; return 1; }
- if [ "${DETECT_HARDWARE}" = "true" ]; then
- detect_hardware
- fi
- generate_optimized_config || { log "ERROR: Config generation failed"; return 1; }
- local cpu_count
- cpu_count=$(nproc 2>/dev/null || echo 1)
- log "Compiling kernel with $cpu_count parallel jobs (this will take a long time)..."
- make -C "${WORK_DIR}" -j"${cpu_count}" all >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Kernel compilation failed. See ${LOG_FILE} for details."; return 1; }
- local distro
- distro=$(detect_distro)
- log "Packaging for distribution: $distro"
- case "$distro" in
- debian)
- make -C "${WORK_DIR}" deb-pkg -j"${cpu_count}" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Debian package creation failed"; return 1; }
- log "Debian packages created successfully"
- ;;
- slackware)
- if [ -f "${WORK_DIR}/build-all-kernels.sh" ]; then
- "${WORK_DIR}/build-all-kernels.sh" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Slackware package creation failed"; return 1; }
- log "Slackware packages created successfully"
- else
- local package_name="kernel-xanmod-${latest_version#v}"
- mkdir -p "${WORK_DIR}/pkg" "${WORK_DIR}/pkg/boot" "${WORK_DIR}/pkg/lib/modules"
- make -C "${WORK_DIR}" modules_install INSTALL_MOD_PATH="${WORK_DIR}/pkg" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Module installation failed"; return 1; }
- cp "${WORK_DIR}/arch/x86/boot/bzImage" "${WORK_DIR}/pkg/boot/vmlinuz-${latest_version#v}" \
- || { log "ERROR: Failed to copy kernel image"; return 1; }
- cp "${WORK_DIR}/System.map" "${WORK_DIR}/pkg/boot/System.map-${latest_version#v}" \
- || { log "ERROR: Failed to copy System.map"; return 1; }
- cp "${WORK_DIR}/.config" "${WORK_DIR}/pkg/boot/config-${latest_version#v}" \
- || { log "ERROR: Failed to copy kernel config"; return 1; }
- ( cd "${WORK_DIR}/pkg" && tar czf "../${package_name}.txz" ./* ) >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Package creation failed"; return 1; }
- log "Manual package created: ${package_name}.txz"
- PACKAGE_FILE="${WORK_DIR}/${package_name}.txz"
- fi
- ;;
- *)
- log "ERROR: Unsupported distribution for packaging: $distro"
- return 1
- ;;
- esac
- log "Kernel build and packaging completed successfully"
- echo "$latest_version"
- return 0
- }
- # FIX: added require_root — the original just ran dpkg -i / installpkg
- # directly, which fails with a permission error mid-run if not root,
- # rather than telling you upfront.
- install_kernel() {
- log "Installing kernel..."
- require_root || return 1
- local distro
- distro=$(detect_distro)
- local kernel_version=""
- case "$distro" in
- debian)
- local latest_deb
- latest_deb=$(ls -t "${WORK_DIR}"/*.deb 2>/dev/null | head -1)
- if [ -n "$latest_deb" ] && [ -f "$latest_deb" ]; then
- kernel_version=$(basename "$latest_deb" | sed 's/linux-image-//' | sed 's/_.*$//' | sed 's/.*-//')
- log "Installing: $(basename "$latest_deb")"
- dpkg -i "$latest_deb" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to install Debian package"; return 1; }
- else
- log "ERROR: No Debian packages found to install"
- return 1
- fi
- ;;
- slackware)
- local latest_txz
- latest_txz=$(ls -t "${WORK_DIR}"/*.txz 2>/dev/null | head -1)
- if [ -n "$latest_txz" ] && [ -f "$latest_txz" ]; then
- kernel_version=$(basename "$latest_txz" | sed 's/kernel-xanmod-//' | sed 's/\.txz$//')
- log "Installing: $(basename "$latest_txz")"
- installpkg "$latest_txz" >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to install Slackware package"; return 1; }
- local modules_txz="${WORK_DIR}/kernel-modules-${kernel_version}.txz"
- if [ -f "$modules_txz" ]; then
- installpkg "$modules_txz" >> "${LOG_FILE}" 2>&1 || log "Warning: Failed to install modules package"
- fi
- else
- log "ERROR: No Slackware packages found to install"
- return 1
- fi
- ;;
- *)
- log "ERROR: Unsupported distribution for installation: $distro"
- return 1
- ;;
- esac
- if [ -z "$kernel_version" ]; then
- case "$distro" in
- debian)
- kernel_version=$(dpkg -l 2>/dev/null | grep -E 'linux-image-[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}' | sort -V | tail -n1 | sed 's/linux-image-//')
- ;;
- slackware)
- kernel_version=$(ls -1 /boot/vmlinuz-* 2>/dev/null | sort -V | tail -n1 | sed 's|/boot/vmlinuz-||')
- ;;
- esac
- fi
- if [ -n "$kernel_version" ]; then
- log "Installed kernel version: $kernel_version"
- update_bootloader "$kernel_version"
- update_initramfs "$kernel_version"
- else
- log "Warning: Could not determine installed kernel version"
- fi
- log "Kernel installation completed successfully"
- return 0
- }
- update_initramfs() {
- local kernel_version="$1"
- if [ -z "$kernel_version" ]; then
- log "No kernel version provided for initramfs update"
- return 1
- fi
- require_root || return 1
- log "Updating initramfs for kernel: $kernel_version"
- local distro
- distro=$(detect_distro)
- case "$distro" in
- debian)
- if command -v update-initramfs &> /dev/null; then
- update-initramfs -u -k "$kernel_version" >> "${LOG_FILE}" 2>&1 || log "Warning: update-initramfs failed"
- elif command -v mkinitramfs &> /dev/null; then
- mkinitramfs -o "/boot/initrd.img-$kernel_version" "$kernel_version" >> "${LOG_FILE}" 2>&1 || log "Warning: mkinitramfs failed"
- else
- log "Warning: No initramfs tool found"
- fi
- ;;
- slackware)
- if command -v mkinitrd &> /dev/null; then
- mkinitrd -c -k "$kernel_version" >> "${LOG_FILE}" 2>&1 || log "Warning: mkinitrd failed"
- else
- log "Warning: mkinitrd not found"
- fi
- ;;
- *)
- log "Warning: Unknown distribution for initramfs update"
- ;;
- esac
- log "Initramfs update completed"
- return 0
- }
- # NOTE: the original script also defined an update_grub() function that
- # was never called anywhere, and its logic was backwards for automation
- # (it SKIPPED updating GRUB unless a graphical $DISPLAY was present, which
- # would silently break unattended `--auto-update` cron runs). It's been
- # removed here since update_bootloader's own grub2 case below already
- # does the real work, independent of whether a display is attached.
- update_bootloader() {
- local kernel_version="$1"
- require_root || return 1
- log "Updating bootloader..."
- local bootloader
- bootloader=$(detect_bootloader)
- local distro
- distro=$(detect_distro)
- if [ -z "$kernel_version" ]; then
- case "$distro" in
- debian)
- kernel_version=$(dpkg -l 2>/dev/null | grep -E 'linux-image-[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}' | sort -V | tail -n1 | sed 's/linux-image-//')
- ;;
- slackware)
- kernel_version=$(ls -1 /boot/vmlinuz-* 2>/dev/null | sort -V | tail -n1 | sed 's|/boot/vmlinuz-||')
- ;;
- *)
- kernel_version=$(uname -r)
- ;;
- esac
- fi
- if [ -z "$kernel_version" ]; then
- log "ERROR: Could not determine kernel version for bootloader update"
- return 1
- fi
- log "Detected bootloader: $bootloader"
- log "Kernel version: $kernel_version"
- case "$bootloader" in
- grub2)
- log "Updating GRUB2 configuration..."
- if [ -f /etc/default/grub ] && grep -q "^GRUB_DISABLE_OS_PROBER=true" /etc/default/grub; then
- log "Note: OS_PROBER is disabled. Other OSes may not be detected."
- fi
- if command -v grub-mkconfig &> /dev/null; then
- grub-mkconfig -o /boot/grub/grub.cfg >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to update GRUB configuration"; return 1; }
- log "GRUB2 configuration updated"
- elif command -v update-grub &> /dev/null; then
- update-grub >> "${LOG_FILE}" 2>&1 \
- || { log "ERROR: Failed to update GRUB configuration"; return 1; }
- log "GRUB2 configuration updated (via update-grub)"
- else
- log "ERROR: No GRUB2 update command found"
- return 1
- fi
- ;;
- grub-legacy)
- log "Updating GRUB Legacy configuration..."
- if [ -f /boot/grub/menu.lst ]; then
- if ! grep -q "vmlinuz-${kernel_version}" /boot/grub/menu.lst; then
- local root_partition
- root_partition=$(grep "^kernel" /boot/grub/menu.lst | head -1 | sed 's/.*root=\([^ ]*\).*/\1/')
- [ -z "$root_partition" ] && root_partition="/dev/sda1"
- cat >> /boot/grub/menu.lst << EOF
- title Linux ${kernel_version}
- root (hd0,0)
- kernel /boot/vmlinuz-${kernel_version} root=${root_partition} ro
- initrd /boot/initrd-${kernel_version}
- EOF
- log "Added new kernel entry to GRUB Legacy menu.lst"
- else
- log "Kernel already present in GRUB Legacy menu.lst"
- fi
- else
- log "Warning: GRUB Legacy menu.lst not found"
- fi
- ;;
- lilo)
- log "Updating LILO configuration..."
- if [ -f /etc/lilo.conf ]; then
- if ! grep -q "vmlinuz-${kernel_version}" /etc/lilo.conf; then
- local root_partition
- root_partition=$(grep "^root=" /etc/lilo.conf | head -1 | sed 's/root=//' | tr -d ' ')
- [ -z "$root_partition" ] && root_partition="/dev/sda1"
- cp /etc/lilo.conf /etc/lilo.conf.bak
- cat >> /etc/lilo.conf << EOF
- image = /boot/vmlinuz-${kernel_version}
- root = ${root_partition}
- label = Linux-${kernel_version}
- read-only
- EOF
- log "Added new kernel entry to LILO configuration"
- else
- log "Kernel already present in LILO configuration"
- fi
- if command -v lilo &> /dev/null; then
- lilo >> "${LOG_FILE}" 2>&1 || { log "ERROR: Failed to run lilo"; return 1; }
- log "LILO updated successfully"
- else
- log "ERROR: lilo command not found"
- return 1
- fi
- else
- log "ERROR: LILO configuration file /etc/lilo.conf not found"
- return 1
- fi
- ;;
- elilo)
- log "Updating ELILO configuration..."
- if [ -f /etc/elilo.conf ]; then
- if ! grep -q "vmlinuz-${kernel_version}" /etc/elilo.conf; then
- local root_partition
- root_partition=$(grep "^root=" /etc/elilo.conf | head -1 | sed 's/root=//' | tr -d ' ')
- [ -z "$root_partition" ] && root_partition="/dev/sda1"
- {
- echo ""
- echo "image = /boot/vmlinuz-${kernel_version}"
- echo "root = ${root_partition}"
- echo "label = Linux-${kernel_version}"
- echo "read-only"
- } >> /etc/elilo.conf
- log "Added new kernel entry to ELILO configuration"
- fi
- if command -v elilo &> /dev/null; then
- elilo >> "${LOG_FILE}" 2>&1 || { log "ERROR: Failed to run elilo"; return 1; }
- log "ELILO updated successfully"
- else
- log "ERROR: elilo command not found"
- return 1
- fi
- else
- log "ERROR: ELILO configuration file /etc/elilo.conf not found"
- return 1
- fi
- ;;
- syslinux)
- log "Updating SYSLINUX configuration..."
- local syslinux_conf=""
- if [ -f /boot/extlinux/extlinux.conf ]; then
- syslinux_conf="/boot/extlinux/extlinux.conf"
- elif [ -f /boot/syslinux/syslinux.cfg ]; then
- syslinux_conf="/boot/syslinux/syslinux.cfg"
- fi
- if [ -n "$syslinux_conf" ]; then
- if ! grep -q "vmlinuz-${kernel_version}" "$syslinux_conf"; then
- {
- echo ""
- echo "label Linux-${kernel_version}"
- echo "kernel /boot/vmlinuz-${kernel_version}"
- echo "append initrd=/boot/initrd-${kernel_version} root=/dev/sda1 ro"
- } >> "$syslinux_conf"
- log "Added new kernel entry to $syslinux_conf"
- fi
- if command -v extlinux &> /dev/null && [ -f /boot/extlinux/extlinux.conf ]; then
- extlinux --update /boot/extlinux >> "${LOG_FILE}" 2>&1 || log "Warning: extlinux update failed"
- fi
- else
- log "Warning: SYSLINUX configuration not found"
- fi
- ;;
- systemd-boot)
- log "Updating systemd-boot configuration..."
- local boot_dir=""
- if [ -d /boot/efi/EFI/systemd ]; then
- boot_dir="/boot/efi/EFI/systemd"
- elif [ -d /boot/EFI/systemd ]; then
- boot_dir="/boot/EFI/systemd"
- fi
- if [ -n "$boot_dir" ]; then
- mkdir -p "${boot_dir}/entries"
- local entry_file="${boot_dir}/entries/linux-${kernel_version}.conf"
- cat > "${entry_file}" << EOF
- title Linux ${kernel_version}
- linux /vmlinuz-${kernel_version}
- initrd /initrd-${kernel_version}
- options root=/dev/sda1 ro quiet
- EOF
- log "Created systemd-boot entry: ${entry_file}"
- if [ -f "${boot_dir}/loader/loader.conf" ]; then
- sed -i "s/default .*/default linux-${kernel_version}/" "${boot_dir}/loader/loader.conf" 2>/dev/null || true
- fi
- log "systemd-boot updated successfully"
- else
- log "Warning: systemd-boot directory not found"
- fi
- ;;
- efistub)
- log "EFISTUB detected. No bootloader to update."
- log "You may need to update your UEFI boot entries manually using efibootmgr."
- if command -v efibootmgr &> /dev/null; then
- log "Current EFI boot entries logged to ${LOG_FILE}"
- efibootmgr >> "${LOG_FILE}" 2>&1 || true
- else
- log "efibootmgr not found. Install it to manage EFI entries."
- fi
- ;;
- unknown)
- log "Warning: Unknown bootloader. Please update your boot configuration manually."
- ;;
- *)
- log "ERROR: Unsupported bootloader: $bootloader"
- return 1
- ;;
- esac
- log "Bootloader update completed"
- return 0
- }
- cleanup_kernels() {
- log "Cleaning up old kernels..."
- local keep_count=${KEEP_OLD:-3}
- local distro
- distro=$(detect_distro)
- local installed_kernels=()
- local current_kernel
- current_kernel=$(uname -r)
- case "$distro" in
- debian)
- mapfile -t installed_kernels < <(dpkg -l 2>/dev/null | grep -E 'linux-image-[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}' | sort -V)
- ;;
- slackware)
- mapfile -t installed_kernels < <(ls -1 /boot/vmlinuz-* 2>/dev/null | sed 's|/boot/vmlinuz-||' | sort -V)
- ;;
- *)
- log "Warning: Unknown distribution for cleanup"
- return 1
- ;;
- esac
- if [ ${#installed_kernels[@]} -eq 0 ]; then
- log "No kernels found to clean up"
- return 0
- fi
- local keep_list=()
- local remove_list=()
- local count=0
- for kernel in "${installed_kernels[@]}"; do
- if [ "$kernel" = "$current_kernel" ]; then
- keep_list+=("$kernel")
- continue
- fi
- if [ $count -lt "$keep_count" ]; then
- keep_list+=("$kernel")
- ((count++))
- else
- remove_list+=("$kernel")
- fi
- done
- if [ ${#remove_list[@]} -eq 0 ]; then
- log "No old kernels to remove"
- return 0
- fi
- local message="The following kernels will be removed:\n\n"
- for kernel in "${remove_list[@]}"; do
- message+=" - $kernel\n"
- done
- message+="\nKeep count: $keep_count (current + $((keep_count-1)) most recent)\n\nProceed with removal?"
- if ! show_question "Cleanup Confirmation" "$message"; then
- log "Cleanup cancelled by user"
- return 0
- fi
- require_root || return 1
- for kernel in "${remove_list[@]}"; do
- log "Removing kernel: $kernel"
- case "$distro" in
- debian)
- if echo "$kernel" | grep -q "^linux-image-\|^[0-9]"; then
- dpkg --purge "linux-image-${kernel#linux-image-}" >> "${LOG_FILE}" 2>&1 || log "Warning: Failed to remove $kernel"
- fi
- ;;
- slackware)
- removepkg "kernel-${kernel}" >> "${LOG_FILE}" 2>&1 || log "Warning: Failed to remove kernel-$kernel"
- rm -rf "/lib/modules/${kernel}" 2>/dev/null
- rm -f "/boot/vmlinuz-${kernel}" "/boot/System.map-${kernel}" "/boot/config-${kernel}" 2>/dev/null
- ;;
- esac
- done
- log "Removed ${#remove_list[@]} old kernels"
- return 0
- }
- setup_cron() {
- local freq="${1:-$UPDATE_FREQ}"
- local script_path
- script_path=$(realpath "$0" 2>/dev/null || echo "$0")
- local cron_cmd="${script_path} --auto-update"
- ( crontab -l 2>/dev/null | grep -vF "$cron_cmd" ) | crontab - 2>/dev/null || true
- if [ "$freq" = "never" ]; then
- log "Cron job disabled"
- return 0
- fi
- local cron_schedule=""
- case "$freq" in
- daily) cron_schedule="0 3 * * *" ;;
- weekly) cron_schedule="0 3 * * 0" ;;
- monthly) cron_schedule="0 3 1 * *" ;;
- *) log "Unknown frequency: $freq"; return 1 ;;
- esac
- ( crontab -l 2>/dev/null; echo "$cron_schedule $cron_cmd" ) | crontab - 2>/dev/null || {
- log "ERROR: Failed to install cron job"
- return 1
- }
- log "Cron job installed: $freq updates at $cron_schedule"
- return 0
- }
- uninstall_kernel_menu() {
- log "Kernel uninstallation menu"
- local distro
- distro=$(detect_distro)
- local installed_kernels=()
- local current_kernel
- current_kernel=$(uname -r)
- case "$distro" in
- debian)
- mapfile -t installed_kernels < <(dpkg -l 2>/dev/null | grep -E 'linux-image-[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}' | sort -V)
- ;;
- slackware)
- mapfile -t installed_kernels < <(ls -1 /boot/vmlinuz-* 2>/dev/null | sed 's|/boot/vmlinuz-||' | sort -V)
- ;;
- *)
- log "Warning: Unknown distribution"
- return 1
- ;;
- esac
- if [ ${#installed_kernels[@]} -eq 0 ]; then
- show_msg "No Kernels" "No kernels found to uninstall."
- return 0
- fi
- local menu_options=()
- for kernel in "${installed_kernels[@]}"; do
- local label="$kernel"
- if [ "$kernel" = "$current_kernel" ]; then
- label="$kernel (CURRENT)"
- fi
- menu_options+=("$kernel" "$label")
- done
- menu_options+=("back" "Return to main menu")
- local choice
- choice=$(show_menu "Uninstall Kernel" "Select kernel to uninstall:" "${menu_options[@]}")
- if [ "$choice" = "back" ] || [ -z "$choice" ]; then
- return 0
- fi
- if [ "$choice" = "$current_kernel" ]; then
- show_msg "Cannot Remove" "You cannot remove the currently running kernel."
- return 0
- fi
- if show_question "Confirm Removal" "Are you sure you want to remove kernel: $choice?"; then
- require_root || { show_msg "Permission Denied" "Removing kernels requires root. Re-run with sudo."; return 1; }
- log "Removing kernel: $choice"
- case "$distro" in
- debian)
- dpkg --purge "linux-image-$choice" >> "${LOG_FILE}" 2>&1 || log "Warning: Failed to remove $choice"
- ;;
- slackware)
- removepkg "kernel-$choice" >> "${LOG_FILE}" 2>&1 || log "Warning: Failed to remove $choice"
- rm -rf "/lib/modules/$choice" 2>/dev/null
- rm -f "/boot/vmlinuz-$choice" "/boot/System.map-$choice" "/boot/config-$choice" 2>/dev/null
- ;;
- esac
- update_bootloader "$(uname -r)"
- show_msg "Removal Complete" "Kernel $choice has been removed."
- fi
- }
- # FIX: throughout this function, every instance of
- # local new_version=$(some_function)
- # if [ $? -eq 0 ]; then
- # has been split into
- # local new_version
- # new_version=$(some_function)
- # local rc=$?
- # if [ "$rc" -eq 0 ]; then
- # because `local var=$(cmd)` always makes $? reflect `local`'s own
- # success (0), never the command's real exit status. This was silently
- # masking every build/update failure in the original script.
- main_menu() {
- while true; do
- local choice
- choice=$(show_menu "Xanmod4Slack v$VERSION" "Choose an action:" \
- "update" "Check for kernel updates" \
- "build" "Build and install new kernel" \
- "cleanup" "Remove old kernels" \
- "config" "Configure settings" \
- "cron" "Manage automatic updates" \
- "uninstall" "Uninstall a specific kernel" \
- "quit" "Exit")
- case "$choice" in
- "update"|"Update")
- local new_version
- new_version=$(check_updates)
- local rc=$?
- if [ "$rc" -eq 0 ]; then
- local current_version
- current_version=$(uname -r)
- send_notification "Kernel Update Available" "XanMod $new_version is available (current: $current_version)" "normal"
- if show_question "Update Available" "XanMod $new_version is available.\nCurrent: $current_version\n\nBuild and install now?"; then
- build_kernel
- if [ $? -eq 0 ]; then
- install_kernel
- if [ "${AUTO_CLEANUP}" = "true" ]; then
- cleanup_kernels
- fi
- show_msg "Complete" "Kernel $new_version installed successfully."
- else
- show_msg "Build Failed" "Kernel build failed. Check ${LOG_FILE} for details."
- fi
- fi
- else
- show_msg "Up to Date" "Your XanMod kernel is current: $new_version"
- fi
- ;;
- "build"|"Build")
- if show_question "Confirm Build" "This will take a long time.\nProceed with kernel build?"; then
- local new_version
- new_version=$(build_kernel)
- local rc=$?
- if [ "$rc" -eq 0 ]; then
- install_kernel
- if [ "${AUTO_CLEANUP}" = "true" ]; then
- cleanup_kernels
- fi
- show_msg "Complete" "Kernel $new_version built and installed successfully."
- else
- show_msg "Build Failed" "Kernel build failed. Check ${LOG_FILE} for details."
- fi
- fi
- ;;
- "cleanup"|"Cleanup")
- cleanup_kernels
- show_msg "Cleanup Complete" "Old kernels have been removed."
- ;;
- "config"|"Config")
- local config_menu_choice
- config_menu_choice=$(show_menu "Configuration" "Select setting to change:" \
- "freq" "Update frequency (${UPDATE_FREQ:-$DEFAULT_UPDATE_FREQ})" \
- "interface" "Interface type (${INTERFACE:-$DEFAULT_INTERFACE})" \
- "keep" "Kernels to keep (${KEEP_OLD:-$DEFAULT_KEEP_OLD})" \
- "auto" "Auto-update (${AUTO_UPDATE:-$DEFAULT_AUTO_UPDATE})" \
- "clean" "Auto-cleanup (${AUTO_CLEANUP:-$DEFAULT_AUTO_CLEANUP})" \
- "silent" "Silent notifications (${SILENT_NOTIFICATIONS:-$DEFAULT_SILENT_NOTIFICATIONS})" \
- "hardware" "Hardware detection (${DETECT_HARDWARE:-$DEFAULT_DETECT_HARDWARE})" \
- "march" "CPU optimization (${MARCH:-$DEFAULT_MARCH})" \
- "back" "Return to main menu")
- case "$config_menu_choice" in
- "freq")
- local new_freq
- new_freq=$(show_menu "Update Frequency" "Choose frequency:" \
- "daily" "Check daily" \
- "weekly" "Check weekly" \
- "monthly" "Check monthly" \
- "never" "Never check automatically")
- if [ -n "$new_freq" ]; then
- UPDATE_FREQ="$new_freq"
- save_config
- setup_cron "$UPDATE_FREQ"
- log "Update frequency set to $UPDATE_FREQ"
- fi
- ;;
- "interface")
- local new_interface
- new_interface=$(show_menu "Interface Type" "Choose interface:" \
- "auto" "Auto-detect" \
- "gui" "GUI (zenity/kdialog)" \
- "dialog" "Dialog (ncurses)" \
- "text" "Text (CLI)")
- if [ -n "$new_interface" ]; then
- INTERFACE="$new_interface"
- save_config
- log "Interface set to $INTERFACE"
- fi
- ;;
- "keep")
- local new_keep
- new_keep=$(show_menu "Kernels to Keep" "Choose number to keep:" \
- "1" "Keep 1 (most recent)" \
- "2" "Keep 2" \
- "3" "Keep 3" \
- "4" "Keep 4" \
- "5" "Keep 5")
- if [[ "$new_keep" =~ ^[0-9]+$ ]]; then
- KEEP_OLD="$new_keep"
- save_config
- log "Keeping $KEEP_OLD kernels"
- fi
- ;;
- "auto")
- local new_auto
- new_auto=$(show_menu "Auto-Update" "Enable automatic updates?" \
- "true" "Yes" \
- "false" "No")
- if [ -n "$new_auto" ]; then
- AUTO_UPDATE="$new_auto"
- save_config
- log "Auto-update set to $AUTO_UPDATE"
- if [ "$AUTO_UPDATE" = "true" ]; then
- setup_cron "$UPDATE_FREQ"
- fi
- fi
- ;;
- "clean")
- local new_clean
- new_clean=$(show_menu "Auto-Cleanup" "Automatically remove old kernels after update?" \
- "true" "Yes" \
- "false" "No")
- if [ -n "$new_clean" ]; then
- AUTO_CLEANUP="$new_clean"
- save_config
- log "Auto-cleanup set to $AUTO_CLEANUP"
- fi
- ;;
- "silent")
- local new_silent
- new_silent=$(show_menu "Silent Notifications" "Silence update notifications?" \
- "true" "Yes" \
- "false" "No")
- if [ -n "$new_silent" ]; then
- SILENT_NOTIFICATIONS="$new_silent"
- save_config
- log "Silent notifications set to $SILENT_NOTIFICATIONS"
- fi
- ;;
- "hardware")
- local new_hardware
- new_hardware=$(show_menu "Hardware Detection" "Detect hardware for optimized config?" \
- "true" "Yes" \
- "false" "No")
- if [ -n "$new_hardware" ]; then
- DETECT_HARDWARE="$new_hardware"
- save_config
- log "Hardware detection set to $DETECT_HARDWARE"
- fi
- ;;
- "march")
- local new_march
- new_march=$(show_menu "CPU Optimization" "Choose optimization level:" \
- "native" "Optimize for this CPU (-march=native)" \
- "v3" "x86-64-v3 (Haswell/Excavator)" \
- "v4" "x86-64-v4 (Skylake/Zen3)" \
- "generic" "Generic x86-64")
- if [ -n "$new_march" ]; then
- MARCH="$new_march"
- save_config
- log "CPU optimization set to $MARCH"
- fi
- ;;
- esac
- ;;
- "cron"|"Cron")
- local cron_choice
- cron_choice=$(show_menu "Automatic Updates" "Manage cron job:" \
- "enable" "Enable automatic updates" \
- "disable" "Disable automatic updates" \
- "status" "Show current status" \
- "back" "Return to main menu")
- case "$cron_choice" in
- "enable")
- local freq_choice
- freq_choice=$(show_menu "Update Frequency" "Choose frequency:" \
- "daily" "Daily" \
- "weekly" "Weekly" \
- "monthly" "Monthly")
- if [ -n "$freq_choice" ]; then
- UPDATE_FREQ="$freq_choice"
- save_config
- setup_cron "$freq_choice"
- show_msg "Cron Enabled" "Automatic updates enabled: $freq_choice"
- fi
- ;;
- "disable")
- setup_cron "never"
- UPDATE_FREQ="never"
- save_config
- show_msg "Cron Disabled" "Automatic updates disabled."
- ;;
- "status")
- local cron_status
- cron_status=$(crontab -l 2>/dev/null | grep "$(realpath "$0" 2>/dev/null || echo "$0")" || echo "No cron job found")
- show_msg "Cron Status" "Current cron jobs:\n\n$cron_status"
- ;;
- esac
- ;;
- "uninstall"|"Uninstall")
- uninstall_kernel_menu
- ;;
- "quit"|"Quit")
- show_msg "Goodbye" "Exiting Xanmod4Slack."
- exit 0
- ;;
- *)
- exit 0
- ;;
- esac
- sleep 2
- done
- }
- # --- Main Execution ---
- # FIX: the original used `local new_version=...` inside this top-level
- # case statement. `local` is only valid INSIDE a function — used here at
- # script top level, bash rejects it with "local: can only be used in a
- # function", the variable is never actually set, and --auto-update /
- # --force-update were effectively broken. Plain variables (no `local`)
- # are used below instead, plus the same declare/assign separation as
- # above so exit-status checks are accurate.
- case "$1" in
- --auto-update)
- log "Running automatic update check..."
- load_config
- if [ "${AUTO_UPDATE}" != "true" ]; then
- log "Auto-update is disabled in configuration. Exiting."
- exit 0
- fi
- new_version=$(check_updates)
- rc=$?
- if [ "$rc" -eq 0 ]; then
- send_notification "Kernel Update Available" "XanMod $new_version is available. Building now..." "normal"
- new_version=$(build_kernel)
- rc=$?
- if [ "$rc" -eq 0 ]; then
- install_kernel
- if [ "${AUTO_CLEANUP}" = "true" ]; then
- cleanup_kernels
- fi
- send_notification "Kernel Update Complete" "XanMod $new_version installed successfully." "low"
- log "Automatic update completed successfully"
- else
- send_notification "Kernel Build Failed" "Automatic build of XanMod $new_version failed. Check ${LOG_FILE}." "critical"
- log "Automatic update FAILED during build"
- exit 1
- fi
- fi
- exit 0
- ;;
- --force-update)
- log "Forcing kernel update..."
- load_config
- new_version=$(build_kernel)
- rc=$?
- if [ "$rc" -eq 0 ]; then
- install_kernel
- if [ "${AUTO_CLEANUP}" = "true" ]; then
- cleanup_kernels
- fi
- send_notification "Kernel Update Complete" "XanMod $new_version installed successfully." "low"
- else
- log "Forced update FAILED during build"
- exit 1
- fi
- exit 0
- ;;
- --help|-h)
- echo "Xanmod4Slack v$VERSION - Universal XanMod Kernel Builder"
- echo ""
- echo "Usage: $0 [OPTIONS]"
- echo " --auto-update Run automatic update check and build (cron mode)"
- echo " --force-update Force update to latest version"
- echo " --help, -h Show this help message"
- echo " No options Run interactive menu"
- echo ""
- echo "Configuration file: $CONFIG_FILE"
- echo "Log file: $LOG_FILE"
- echo "Work directory: $WORK_DIR"
- exit 0
- ;;
- *)
- load_config
- if [ $# -eq 0 ]; then
- main_menu
- else
- echo "Unknown option: $1"
- echo "Try '$0 --help' for usage information."
- exit 1
- fi
- ;;
- esac
- exit 0
Advertisement
Add Comment
Please, Sign In to add comment