testing & remove some things

This commit is contained in:
CanbiZ 2025-07-21 11:59:23 +02:00
parent 436026dc1c
commit 8a875044f0
9 changed files with 8 additions and 3469 deletions

View File

@ -22,19 +22,19 @@ $STD apt-get install -y \
htop \
ca-certificates \
apt-transport-https \
tesseract-ocr \
tesseract-ocr-deu \
tesseract-ocr-eng \
unpaper \
unoconv \
wkhtmltopdf \
ocrmypdf
tesseract-ocr
#tesseract-ocr-deu \
#tesseract-ocr-eng \
#unpaper \
#unoconv \
#wkhtmltopdf \
#ocrmypdf
msg_ok "Installed Dependencies"
setup_gs
JAVA_VERSION="21" setup_java
POSTGRES_VERSION="16" setup_postgres
POSTGRES_VERSION="16" setup_postgresql
setup_yq
msg_info "Set up PostgreSQL Database"

View File

@ -1,277 +0,0 @@
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# Co-Author: MickLesk
# License: MIT
# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
load_functions
# This function sets color variables for formatting output in the terminal
# color() {
# # Colors
# YW=$(echo "\033[33m")
# YWB=$(echo "\033[93m")
# BL=$(echo "\033[36m")
# RD=$(echo "\033[01;31m")
# GN=$(echo "\033[1;92m")
# # Formatting
# CL=$(echo "\033[m")
# BFR="\\r\\033[K"
# BOLD=$(echo "\033[1m")
# TAB=" "
# # System
# RETRY_NUM=10
# RETRY_EVERY=3
# i=$RETRY_NUM
# # Icons
# CM="${TAB}✔️${TAB}${CL}"
# CROSS="${TAB}✖️${TAB}${CL}"
# INFO="${TAB}💡${TAB}${CL}"
# NETWORK="${TAB}📡${TAB}${CL}"
# OS="${TAB}🖥️${TAB}${CL}"
# OSVERSION="${TAB}🌟${TAB}${CL}"
# HOSTNAME="${TAB}🏠${TAB}${CL}"
# GATEWAY="${TAB}🌐${TAB}${CL}"
# DEFAULT="${TAB}⚙️${TAB}${CL}"
# }
# Function to set STD mode based on verbosity
set_std_mode() {
if [ "$VERBOSE" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
"$@" >/dev/null 2>&1
}
# This function enables IPv6 if it's not disabled and sets verbose mode
verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE
if [ "$DISABLEIPV6" == "yes" ]; then
$STD sysctl -w net.ipv6.conf.all.disable_ipv6=1
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
$STD rc-update add sysctl default
fi
}
# This function catches errors and handles them with the error handler function
catch_errors() {
unset SPINNER_PID
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function handles errors
error_handler() {
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message\n"
[[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" &>/dev/null || true
}
# # This function displays an informational message with logging support.
# declare -A MSG_INFO_SHOWN
# SPINNER_ACTIVE=0
# SPINNER_PID=""
# SPINNER_MSG=""
# trap 'stop_spinner' EXIT INT TERM HUP
# start_spinner() {
# local msg="$1"
# local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
# local spin_i=0
# local interval=0.1
# SPINNER_MSG="$msg"
# printf "\r\e[2K" >&2
# {
# while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
# printf "\r\e[2K%s %b" "${frames[spin_i]}" "${YW}${SPINNER_MSG}${CL}" >&2
# spin_i=$(((spin_i + 1) % ${#frames[@]}))
# sleep "$interval"
# done
# } &
# SPINNER_PID=$!
# disown "$SPINNER_PID"
# }
# stop_spinner() {
# if [[ ${SPINNER_PID+v} && -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
# kill "$SPINNER_PID" 2>/dev/null
# sleep 0.1
# kill -0 "$SPINNER_PID" 2>/dev/null && kill -9 "$SPINNER_PID" 2>/dev/null
# wait "$SPINNER_PID" 2>/dev/null || true
# fi
# SPINNER_ACTIVE=0
# unset SPINNER_PID
# }
# spinner_guard() {
# if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "$SPINNER_PID" ]]; then
# kill "$SPINNER_PID" 2>/dev/null
# wait "$SPINNER_PID" 2>/dev/null || true
# SPINNER_ACTIVE=0
# unset SPINNER_PID
# fi
# }
# msg_info() {
# local msg="$1"
# [[ -n "${MSG_INFO_SHOWN["$msg"]+x}" ]] && return
# MSG_INFO_SHOWN["$msg"]=1
# spinner_guard
# SPINNER_ACTIVE=1
# start_spinner "$msg"
# }
# msg_ok() {
# local msg="$1"
# stop_spinner
# printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
# unset MSG_INFO_SHOWN["$msg"]
# }
# msg_error() {
# stop_spinner
# local msg="$1"
# printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
# #log_message "ERROR" "$msg"
# }
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
setting_up_container() {
msg_info "Setting up Container OS"
while [ $i -gt 0 ]; do
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" != "" ]; then
break
fi
echo 1>&2 -en "${CROSS}${RD} No Network! "
sleep $RETRY_EVERY
i=$((i - 1))
done
if [ "$(ip addr show | grep 'inet ' | grep -v '127.0.0.1' | awk '{print $2}' | cut -d'/' -f1)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
echo -e "${NETWORK}Check Network Settings"
exit 1
fi
msg_ok "Set up Container OS"
msg_ok "Network Connected: ${BL}$(ip addr show | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1 | tail -n1)${CL}"
}
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
network_check() {
set +e
trap - ERR
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
msg_ok "Internet Connected"
else
msg_error "Internet NOT Connected"
read -r -p "Would you like to continue anyway? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else
echo -e "${NETWORK}Check Network Settings"
exit 1
fi
fi
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi
set -e
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function updates the Container OS by running apt-get update and upgrade
update_os() {
msg_info "Updating Container OS"
$STD apk update
$STD apk upgrade
msg_ok "Updated Container OS"
msg_info "Installing core dependencies"
$STD apk update
$STD apk add newt curl openssh nano mc ncurses
msg_ok "Core dependencies installed"
}
# This function modifies the message of the day (motd) and SSH settings
motd_ssh() {
echo "export TERM='xterm-256color'" >>/root/.bashrc
IP=$(ip -4 addr show eth0 | awk '/inet / {print $2}' | cut -d/ -f1 | head -n 1)
if [ -f "/etc/os-release" ]; then
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
else
OS_NAME="Alpine Linux"
OS_VERSION="Unknown"
fi
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
echo "echo -e \"\"" >"$PROFILE_FILE"
echo -e "echo -e \"${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} IP Address: ${GN}${IP}${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}\"" >>"$PROFILE_FILE"
echo "echo \"\"" >>"$PROFILE_FILE"
if [[ "${SSH_ROOT}" == "yes" ]]; then
$STD rc-update add sshd
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
$STD /etc/init.d/sshd start
fi
}
# Validate Timezone for some LXC's
validate_tz() {
[[ -f "/usr/share/zoneinfo/$1" ]]
}
# This function customizes the container and enables passwordless login for the root user
customize() {
if [[ "$PASSWORD" == "" ]]; then
msg_info "Customizing Container"
passwd -d root >/dev/null 2>&1
# Ensure agetty is available
apk add --no-cache --force-broken-world util-linux >/dev/null 2>&1
# Create persistent autologin boot script
mkdir -p /etc/local.d
cat <<'EOF' >/etc/local.d/autologin.start
#!/bin/sh
sed -i 's|^tty1::respawn:.*|tty1::respawn:/sbin/agetty --autologin root --noclear tty1 38400 linux|' /etc/inittab
kill -HUP 1
EOF
touch /root/.hushlogin
chmod +x /etc/local.d/autologin.start
rc-update add local >/dev/null 2>&1
# Apply autologin immediately for current session
/etc/local.d/autologin.start
msg_ok "Customized Container"
fi
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
chmod +x /usr/bin/update
}

View File

@ -1,189 +0,0 @@
# Copyright (c) 2021-2025 community-scripts ORG
# Author: michelroegl-brunner
# License: MIT | https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/LICENSE
get_error_description() {
local exit_code="$1"
case "$exit_code" in
0) echo " " ;;
1) echo "General error: An unspecified error occurred." ;;
2) echo "Incorrect shell usage or invalid command arguments." ;;
3) echo "Unexecuted function or invalid shell condition." ;;
4) echo "Error opening a file or invalid path." ;;
5) echo "I/O error: An input/output failure occurred." ;;
6) echo "No such device or address." ;;
7) echo "Insufficient memory or resource exhaustion." ;;
8) echo "Non-executable file or invalid file format." ;;
9) echo "Failed child process execution." ;;
18) echo "Connection to a remote server failed." ;;
22) echo "Invalid argument or faulty network connection." ;;
28) echo "No space left on device." ;;
35) echo "Timeout while establishing a connection." ;;
56) echo "Faulty TLS connection." ;;
60) echo "SSL certificate error." ;;
100) echo "LXC install error: Unexpected error in create_lxc.sh." ;;
101) echo "LXC install error: No network connection detected." ;;
200) echo "LXC creation failed." ;;
201) echo "LXC error: Invalid Storage class." ;;
202) echo "User aborted menu in create_lxc.sh." ;;
203) echo "CTID not set in create_lxc.sh." ;;
204) echo "PCT_OSTYPE not set in create_lxc.sh." ;;
205) echo "CTID cannot be less than 100 in create_lxc.sh." ;;
206) echo "CTID already in use in create_lxc.sh." ;;
207) echo "Template not found in create_lxc.sh." ;;
208) echo "Error downloading template in create_lxc.sh." ;;
209) echo "Container creation failed, but template is intact in create_lxc.sh." ;;
125) echo "Docker error: Container could not start." ;;
126) echo "Command not executable: Incorrect permissions or missing dependencies." ;;
127) echo "Command not found: Incorrect path or missing dependency." ;;
128) echo "Invalid exit signal, e.g., incorrect Git command." ;;
129) echo "Signal 1 (SIGHUP): Process terminated due to hangup." ;;
130) echo "Signal 2 (SIGINT): Manual termination via Ctrl+C." ;;
132) echo "Signal 4 (SIGILL): Illegal machine instruction." ;;
133) echo "Signal 5 (SIGTRAP): Debugging error or invalid breakpoint signal." ;;
134) echo "Signal 6 (SIGABRT): Program aborted itself." ;;
135) echo "Signal 7 (SIGBUS): Memory error, invalid memory address." ;;
137) echo "Signal 9 (SIGKILL): Process forcibly terminated (OOM-killer or 'kill -9')." ;;
139) echo "Signal 11 (SIGSEGV): Segmentation fault, possibly due to invalid pointer access." ;;
141) echo "Signal 13 (SIGPIPE): Pipe closed unexpectedly." ;;
143) echo "Signal 15 (SIGTERM): Process terminated normally." ;;
152) echo "Signal 24 (SIGXCPU): CPU time limit exceeded." ;;
255) echo "Unknown critical error, often due to missing permissions or broken scripts." ;;
*) echo "Unknown error code ($exit_code)." ;;
esac
}
post_to_api() {
if ! command -v curl &>/dev/null; then
return
fi
if [ "$DIAGNOSTICS" = "no" ]; then
return
fi
if [ -z "$RANDOM_UUID" ]; then
return
fi
local API_URL="http://api.community-scripts.org/dev/upload"
local pve_version="not found"
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": $CT_TYPE,
"type":"lxc",
"disk_size": $DISK_SIZE,
"core_count": $CORE_COUNT,
"ram_size": $RAM_SIZE,
"os_type": "$var_os",
"os_version": "$var_version",
"disableip6": "$DISABLEIP6",
"nsapp": "$NSAPP",
"method": "$METHOD",
"pve_version": "$pve_version",
"status": "installing",
"random_id": "$RANDOM_UUID"
}
EOF
)
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
}
post_to_api_vm() {
if [[ ! -f /usr/local/community-scripts/diagnostics ]]; then
return
fi
DIAGNOSTICS=$(grep -i "^DIAGNOSTICS=" /usr/local/community-scripts/diagnostics | awk -F'=' '{print $2}')
if ! command -v curl &>/dev/null; then
return
fi
if [ "$DIAGNOSTICS" = "no" ]; then
return
fi
if [ -z "$RANDOM_UUID" ]; then
return
fi
local API_URL="http://api.community-scripts.org/dev/upload"
local pve_version="not found"
pve_version=$(pveversion | awk -F'[/ ]' '{print $2}')
DISK_SIZE_API=${DISK_SIZE%G}
JSON_PAYLOAD=$(
cat <<EOF
{
"ct_type": 2,
"type":"vm",
"disk_size": $DISK_SIZE_API,
"core_count": $CORE_COUNT,
"ram_size": $RAM_SIZE,
"os_type": "$var_os",
"os_version": "$var_version",
"disableip6": "",
"nsapp": "$NSAPP",
"method": "$METHOD",
"pve_version": "$pve_version",
"status": "installing",
"random_id": "$RANDOM_UUID"
}
EOF
)
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
}
POST_UPDATE_DONE=false
post_update_to_api() {
if ! command -v curl &>/dev/null; then
return
fi
if [ "$POST_UPDATE_DONE" = true ]; then
return 0
fi
exit_code=${2:-1}
local API_URL="http://api.community-scripts.org/dev/upload/updatestatus"
local status="${1:-failed}"
if [[ "$status" == "failed" ]]; then
local exit_code="${2:-1}"
elif [[ "$status" == "success" ]]; then
local exit_code="${2:-0}"
fi
if [[ -z "$exit_code" ]]; then
exit_code=1
fi
error=$(get_error_description "$exit_code")
if [ -z "$error" ]; then
error="Unknown error"
fi
JSON_PAYLOAD=$(
cat <<EOF
{
"status": "$status",
"error": "$error",
"random_id": "$RANDOM_UUID"
}
EOF
)
RESPONSE=$(curl -s -w "%{http_code}" -L -X POST "$API_URL" --post301 --post302 \
-H "Content-Type: application/json" \
-d "$JSON_PAYLOAD") || true
POST_UPDATE_DONE=true
}

View File

@ -1,139 +0,0 @@
# backup.func Snapshot/Backup-Logik mit Rollback via trap + Rotation + flexible Pfaderkennung
# Globale Variable (automatisch gesetzt)
SNAPSHOT_DIR=""
create_snapshot() {
local app_name=$1
local base_dir
# Autodetect base_dir, bevorzugt /opt/<app>, sonst Arbeitsverzeichnis oder APP_DIR gesetzt vom Script
base_dir="${APP_DIR:-/opt/$app_name}"
if [[ ! -d "$base_dir" ]]; then
msg_error "Cannot determine base directory for $app_name"
return 1
fi
local snapshot_base="${base_dir}-snapshot"
SNAPSHOT_DIR="${snapshot_base}-$(date +%F_%T | tr ':' '-')"
msg_info "Creating snapshot for $app_name"
mkdir -p "$SNAPSHOT_DIR"
cp -a "$base_dir" "$SNAPSHOT_DIR/base" || {
msg_error "Failed to backup base directory"
return 1
}
mkdir -p "$SNAPSHOT_DIR/systemd"
cp -a /etc/systemd/system/${app_name}-*.service "$SNAPSHOT_DIR/systemd/" 2>/dev/null || true
[[ -f "/etc/default/$app_name" ]] && cp "/etc/default/$app_name" "$SNAPSHOT_DIR/"
[[ -f "$base_dir/${app_name}_version.txt" ]] && cp "$base_dir/${app_name}_version.txt" "$SNAPSHOT_DIR/"
rotate_snapshots "$snapshot_base"
msg_ok "Snapshot created at $SNAPSHOT_DIR"
return 0
}
rotate_snapshots() {
local snapshot_base=$1
local snapshots
# Sortiert nach Datum absteigend, behalte nur die 3 neuesten
mapfile -t snapshots < <(ls -dt ${snapshot_base}-* 2>/dev/null)
if ((${#snapshots[@]} > 3)); then
for ((i = 3; i < ${#snapshots[@]}; i++)); do
rm -rf "${snapshots[$i]}"
msg_info "Old snapshot removed: ${snapshots[$i]}"
done
fi
}
rollback_snapshot() {
local app_name=$1
local base_dir
base_dir="${APP_DIR:-/opt/$app_name}"
if [[ -z "$SNAPSHOT_DIR" || ! -d "$SNAPSHOT_DIR" ]]; then
msg_error "No snapshot found. Cannot rollback."
return 1
fi
msg_info "Rolling back $app_name from snapshot"
systemctl stop ${app_name}-* 2>/dev/null || true
rm -rf "$base_dir"
cp -a "$SNAPSHOT_DIR/base" "$base_dir" || {
msg_error "Failed to restore base directory"
return 1
}
if [[ -d "$SNAPSHOT_DIR/systemd" ]]; then
cp "$SNAPSHOT_DIR/systemd/"*.service /etc/systemd/system/ 2>/dev/null || true
systemctl daemon-reload
fi
[[ -f "$SNAPSHOT_DIR/$app_name" ]] && cp "$SNAPSHOT_DIR/$app_name" "/etc/default/$app_name"
[[ -f "$SNAPSHOT_DIR/${app_name}_version.txt" ]] && cp "$SNAPSHOT_DIR/${app_name}_version.txt" "$base_dir/"
systemctl start ${app_name}-* 2>/dev/null || true
msg_ok "Rollback for $app_name completed"
return 0
}
cleanup_snapshot() {
if [[ -n "$SNAPSHOT_DIR" && -d "$SNAPSHOT_DIR" ]]; then
rm -rf "$SNAPSHOT_DIR"
msg_ok "Cleaned up snapshot at $SNAPSHOT_DIR"
fi
}
handle_failure() {
local app_name=$1
local line=$2
msg_error "Update failed at line $line. Rolling back..."
rollback_snapshot "$app_name"
exit 1
}
safe_run_update_script() {
local app_name="${APP:-paperless}"
if ! create_snapshot "$app_name"; then
msg_error "Snapshot creation failed. Aborting update."
exit 1
fi
trap 'handle_failure "$app_name" $LINENO' ERR
set -eE
update_script
cleanup_snapshot
}
wrap_update_script_with_snapshot() {
local original_func
original_func=$(declare -f update_script) || return 1
eval "
original_update_script() {
${original_func#*\{}
}
update_script() {
local app_name=\"\${APP:-paperless}\"
if ! create_snapshot \"\$app_name\"; then
msg_error \"Snapshot creation failed. Aborting update.\"
exit 1
fi
trap 'handle_failure \"\$app_name\" \$LINENO' ERR
set -eE
original_update_script
cleanup_snapshot
}
"
}

File diff suppressed because it is too large Load Diff

View File

@ -1,220 +0,0 @@
# Copyright (c) 2021-2025 community-scripts ORG
# Author: michelroegl-brunner
# License: MIT | https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/LICENSE
color() {
# Colors
YW=$(echo "\033[33m")
YWB=$(echo "\033[93m")
BL=$(echo "\033[36m")
RD=$(echo "\033[01;31m")
BGN=$(echo "\033[4;92m")
GN=$(echo "\033[1;92m")
DGN=$(echo "\033[32m")
# Formatting
CL=$(echo "\033[m")
BOLD=$(echo "\033[1m")
HOLD=" "
TAB=" "
# Icons
CM="${TAB}✔️${TAB}"
CROSS="${TAB}✖️${TAB}${CL}"
INFO="${TAB}💡${TAB}${CL}"
OS="${TAB}🖥️${TAB}${CL}"
OSVERSION="${TAB}🌟${TAB}${CL}"
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
DISKSIZE="${TAB}💾${TAB}${CL}"
CPUCORE="${TAB}🧠${TAB}${CL}"
RAMSIZE="${TAB}🛠️${TAB}${CL}"
SEARCH="${TAB}🔍${TAB}${CL}"
VERBOSE_CROPPED="🔍${TAB}"
VERIFYPW="${TAB}🔐${TAB}${CL}"
CONTAINERID="${TAB}🆔${TAB}${CL}"
HOSTNAME="${TAB}🏠${TAB}${CL}"
BRIDGE="${TAB}🌉${TAB}${CL}"
NETWORK="${TAB}📡${TAB}${CL}"
GATEWAY="${TAB}🌐${TAB}${CL}"
DISABLEIPV6="${TAB}🚫${TAB}${CL}"
DEFAULT="${TAB}⚙️${TAB}${CL}"
MACADDRESS="${TAB}🔗${TAB}${CL}"
VLANTAG="${TAB}🏷️${TAB}${CL}"
ROOTSSH="${TAB}🔑${TAB}${CL}"
CREATING="${TAB}🚀${TAB}${CL}"
ADVANCED="${TAB}🧩${TAB}${CL}"
FUSE="${TAB}🔧${TAB}${CL}"
}
declare -A MSG_INFO_SHOWN
SPINNER_ACTIVE=0
SPINNER_PID=""
SPINNER_MSG=""
start_spinner() {
local msg="$1"
local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
local spin_i=0
local interval=0.1
SPINNER_MSG="$msg"
printf "\r\e[2K" >&2
{
while [[ "$SPINNER_ACTIVE" -eq 1 ]]; do
printf "\r\e[2K%s %b" "${frames[spin_i]}" "${YW}${SPINNER_MSG}${CL}" >&2
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
} &
SPINNER_PID=$!
disown "$SPINNER_PID"
}
stop_spinner() {
if [[ ${SPINNER_PID+v} && -n "$SPINNER_PID" ]] && kill -0 "$SPINNER_PID" 2>/dev/null; then
kill "$SPINNER_PID" 2>/dev/null
sleep 0.1
kill -0 "$SPINNER_PID" 2>/dev/null && kill -9 "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null || true
fi
SPINNER_ACTIVE=0
unset SPINNER_PID
}
spinner_guard() {
if [[ "$SPINNER_ACTIVE" -eq 1 ]] && [[ -n "$SPINNER_PID" ]]; then
kill "$SPINNER_PID" 2>/dev/null
wait "$SPINNER_PID" 2>/dev/null || true
SPINNER_ACTIVE=0
unset SPINNER_PID
fi
}
log_message() {
local level="$1"
local message="$2"
local timestamp
local logdate
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
logdate=$(date '+%Y-%m-%d')
LOGDIR="/usr/local/community-scripts/logs"
mkdir -p "$LOGDIR"
LOGFILE="${LOGDIR}/${logdate}_${NSAPP}.log"
echo "$timestamp - $level: $message" >>"$LOGFILE"
}
msg_info() {
local msg="$1"
if [ "${SPINNER_ACTIVE:-0}" -eq 1 ]; then
return
fi
SPINNER_ACTIVE=1
start_spinner "$msg"
}
msg_ok() {
if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then
kill "$SPINNER_PID" >/dev/null 2>&1
wait "$SPINNER_PID" 2>/dev/null || true
fi
local msg="$1"
printf "\r\e[2K${CM}${GN}%b${CL}\n" "$msg" >&2
unset SPINNER_PID
SPINNER_ACTIVE=0
log_message "OK" "$msg"
}
msg_error() {
if [ -n "${SPINNER_PID:-}" ] && ps -p "$SPINNER_PID" >/dev/null 2>&1; then
kill "$SPINNER_PID" >/dev/null 2>&1
wait "$SPINNER_PID" 2>/dev/null || true
fi
local msg="$1"
printf "\r\e[2K${CROSS}${RD}%b${CL}\n" "$msg" >&2
unset SPINNER_PID
SPINNER_ACTIVE=0
log_message "ERROR" "$msg"
}
shell_check() {
if [[ "$(basename "$SHELL")" != "bash" ]]; then
clear
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..."
sleep 2
exit
fi
}
root_check() {
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
clear
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit
fi
}
pve_check() {
if ! pveversion | grep -Eq "pve-manager/8\.[1-9](\.[0-9]+)*"; then
msg_error "${CROSS}${RD}This version of Proxmox Virtual Environment is not supported"
echo -e "Requires Proxmox Virtual Environment Version 8.1 or later."
echo -e "Exiting..."
sleep 2
exit
fi
}
arch_check() {
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
echo -e "Exiting..."
sleep 2
exit
fi
}
ssh_check() {
if command -v pveversion >/dev/null 2>&1; then
if [ -n "${SSH_CLIENT:+x}" ]; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
echo "you've been warned"
else
clear
exit
fi
fi
fi
}
exit-script() {
clear
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
exit
}
set_std_mode() {
if [ "$VERB" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
silent() {
if [ "$VERB" = "no" ]; then
"$@" >>"$LOGFILE" 2>&1
else
"$@" 2>&1 | tee -a "$LOGFILE"
fi
}

View File

@ -1,850 +0,0 @@
# dialog_input() {
# local title="$1"
# local prompt="$2"
# local default="$3"
# local result
# apt-get install -y dialog
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "$title" \
# --extra-button --extra-label "Back" \
# --ok-label "Next" --cancel-label "Exit" \
# --inputbox "$prompt" 10 58 "$default" 2>&1 >/dev/tty)
# local exitcode=$?
# case $exitcode in
# 0)
# REPLY_RESULT="$result"
# return 0
# ;; # OK
# 3) return 2 ;; # Back
# *) return 1 ;; # Cancel/Exit
# esac
# }
# advanced_settings() {
# local step=1
# while true; do
# case $step in
# 1)
# show_intro_messages && ((step++))
# ;;
# 2)
# select_distribution
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 3)
# select_version
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 4)
# select_container_type
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 5)
# set_root_password
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 6)
# set_container_id
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 7)
# set_hostname
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 8)
# set_disk_size
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 9)
# set_cpu_cores
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 10)
# set_ram_size
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 11)
# set_bridge
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 12)
# set_ip_address
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 13)
# set_gateway
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 14)
# set_apt_cacher
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 15)
# toggle_ipv6
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 16)
# set_mtu
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 17)
# set_dns_search_domain
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 18)
# set_dns_server
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 19)
# set_mac_address
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 20)
# set_vlan
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 21)
# set_tags
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 22)
# set_ssh_access
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 23)
# set_fuse
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 24)
# set_verbose
# result=$?
# [[ $result -eq 0 ]] && ((step++))
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# 25)
# confirm_creation
# result=$?
# [[ $result -eq 0 ]] && break
# [[ $result -eq 2 && $step -gt 1 ]] && ((step--))
# [[ $result -eq 1 ]] && return
# ;;
# esac
# done
# }
# show_intro_messages() {
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "Instructional Tip" \
# --msgbox "To make a selection, use the Spacebar." 8 58 || return 1
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "Default distribution for $APP" \
# --msgbox "Default is: ${var_os} ${var_version}\n\nIf the default Linux distribution is not adhered to, script support will be discontinued." 10 58 || return 1
# return 0
# }
# select_distribution() {
# [[ "$var_os" == "alpine" ]] && return 0
# local default result exitcode
# default="${var_os:-debian}"
# var_os=""
# local debian_flag ubuntu_flag
# [[ "$default" == "debian" ]] && debian_flag="on" || debian_flag="off"
# [[ "$default" == "ubuntu" ]] && ubuntu_flag="on" || ubuntu_flag="off"
# while [[ -z "$var_os" ]]; do
# exec 3>&1
# result=$(dialog --clear \
# --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "DISTRIBUTION" \
# --radiolist "Choose Distribution:" 15 60 4 \
# "debian" "" "$debian_flag" \
# "ubuntu" "" "$ubuntu_flag" \
# --ok-label "Next" \
# --cancel-label "Exit" \
# --extra-button \
# --extra-label "Back" \
# 2>&1 1>&3)
# exitcode=$?
# exec 3>&-
# case "$exitcode" in
# 0)
# if [[ "$result" =~ ^(debian|ubuntu)$ ]]; then
# var_os="$result"
# printf "%bOperating System: %b%s%b\n" "$OS$BOLD$DGN" "$BGN" "$var_os" "$CL"
# return 0
# else
# printf "[DEBUG] No valid selection made (result='%s'), repeating...\n" "$result"
# fi
# ;;
# 3)
# return 2
# ;;
# 1 | 255)
# return 1
# ;;
# *)
# printf "[DEBUG] Unexpected exit code: %s\n" "$exitcode" >&2
# return 1
# ;;
# esac
# done
# }
# select_version() {
# local default="${var_version}"
# var_version=""
# local list result exitcode
# if [[ "$var_os" == "debian" ]]; then
# case "$default" in
# 11) list=("11" "Bullseye" on "12" "Bookworm" off) ;;
# 12) list=("11" "Bullseye" off "12" "Bookworm" on) ;;
# *) list=("11" "Bullseye" off "12" "Bookworm" off) ;;
# esac
# elif [[ "$var_os" == "ubuntu" ]]; then
# case "$default" in
# 20.04) list=("20.04" "Focal" on "22.04" "Jammy" off "24.04" "Noble" off "24.10" "Oracular" off) ;;
# 22.04) list=("20.04" "Focal" off "22.04" "Jammy" on "24.04" "Noble" off "24.10" "Oracular" off) ;;
# 24.04) list=("20.04" "Focal" off "22.04" "Jammy" off "24.04" "Noble" on "24.10" "Oracular" off) ;;
# 24.10) list=("20.04" "Focal" off "22.04" "Jammy" off "24.04" "Noble" off "24.10" "Oracular" on) ;;
# *) list=("20.04" "Focal" off "22.04" "Jammy" off "24.04" "Noble" off "24.10" "Oracular" off) ;;
# esac
# fi
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "VERSION" \
# --radiolist "Choose Version:" 15 58 5 \
# "${list[@]}" \
# --ok-label "Next" \
# --cancel-label "Exit" \
# --extra-button --extra-label "Back" \
# 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# var_version="$result"
# printf "%bVersion: %b%s%b\n" "$OSVERSION$BOLD$DGN" "$BGN" "$var_version" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# select_container_type() {
# local default="${CT_TYPE}"
# CT_TYPE=""
# local list result exitcode
# [[ "$default" == "1" ]] && list=("1" "Unprivileged" on "0" "Privileged" off) || list=("1" "Unprivileged" off "0" "Privileged" on)
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "CONTAINER TYPE" \
# --radiolist "Choose Type:" 10 58 2 "${list[@]}" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# CT_TYPE="$result"
# [[ "$CT_TYPE" == "0" ]] && desc="Privileged" || desc="Unprivileged"
# printf "%bContainer Type: %b%s%b\n" "$CONTAINERTYPE$BOLD$DGN" "$BGN" "$desc" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_root_password() {
# local pw1 pw2 exitcode
# while true; do
# pw1=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "PASSWORD (leave blank for automatic login)" \
# --insecure --passwordbox "\nSet Root Password (needed for root ssh access)" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$pw1" ]]; then
# PW1="Automatic Login"
# PW=""
# printf "%bRoot Password: %b%s%b\n" "$VERIFYPW$BOLD$DGN" "$BGN" "$PW1" "$CL"
# return 0
# fi
# if [[ "$pw1" == *" "* ]]; then
# dialog --msgbox "Password cannot contain spaces. Please try again." 8 58
# continue
# fi
# if [[ ${#pw1} -lt 5 ]]; then
# dialog --msgbox "Password must be at least 5 characters long. Please try again." 8 58
# continue
# fi
# pw2=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "PASSWORD VERIFICATION" \
# --insecure --passwordbox "\nVerify Root Password" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ "$pw1" == "$pw2" ]]; then
# PW="-password $pw1"
# printf "%bRoot Password: %b********%b\n" "$VERIFYPW$BOLD$DGN" "$BGN" "$CL"
# return 0
# else
# dialog --msgbox "Passwords do not match. Please try again." 8 58
# continue
# fi
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# done
# }
# set_container_id() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "CONTAINER ID" \
# --inputbox "Set Container ID" 8 58 "$NEXTID" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# CT_ID="${result:-$NEXTID}"
# printf "%bContainer ID: %b%s%b\n" "$CONTAINERID$BOLD$DGN" "$BGN" "$CT_ID" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_hostname() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "HOSTNAME" \
# --inputbox "Set Hostname" 8 58 "$NSAPP" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# HN="$NSAPP"
# else
# HN=$(tr -d ' ' <<<"${result,,}")
# fi
# printf "%bHostname: %b%s%b\n" "$HOSTNAME$BOLD$DGN" "$BGN" "$HN" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_disk_size() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "DISK SIZE" \
# --inputbox "Set Disk Size in GB" 8 58 "$var_disk" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# DISK_SIZE="$var_disk"
# elif [[ "$result" =~ ^[0-9]+$ ]]; then
# DISK_SIZE="$result"
# else
# dialog --msgbox "Disk size must be an integer!" 8 58
# return 2
# fi
# printf "%bDisk Size: %b%s GB%b\n" "$DISKSIZE$BOLD$DGN" "$BGN" "$DISK_SIZE" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_cpu_cores() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "CORE COUNT" \
# --inputbox "Allocate CPU Cores" 8 58 "$var_cpu" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# CORE_COUNT="${result:-$var_cpu}"
# printf "%bCPU Cores: %b%s%b\n" "$CPUCORE$BOLD$DGN" "$BGN" "$CORE_COUNT" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_ram_size() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "RAM" \
# --inputbox "Allocate RAM in MiB" 8 58 "$var_ram" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# RAM_SIZE="${result:-$var_ram}"
# printf "%bRAM Size: %b%s MiB%b\n" "$RAMSIZE$BOLD$DGN" "$BGN" "$RAM_SIZE" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_bridge() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "BRIDGE" \
# --inputbox "Set a Bridge" 8 58 "vmbr0" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# BRG="${result:-vmbr0}"
# printf "%bBridge: %b%s%b\n" "$BRIDGE$BOLD$DGN" "$BGN" "$BRG" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_ip_address() {
# local result exitcode
# while true; do
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "IP ADDRESS" \
# --inputbox "Set a Static IPv4 CIDR Address (/24)" 8 58 "dhcp" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ "$result" == "dhcp" ]]; then
# NET="dhcp"
# printf "%bIP Address: %b%s%b\n" "$NETWORK$BOLD$DGN" "$BGN" "$NET" "$CL"
# return 0
# elif [[ "$result" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$ ]]; then
# NET="$result"
# printf "%bIP Address: %b%s%b\n" "$NETWORK$BOLD$DGN" "$BGN" "$NET" "$CL"
# return 0
# else
# dialog --msgbox "$result is an invalid IPv4 CIDR address. Please enter a valid address or 'dhcp'." 8 58
# continue
# fi
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# done
# }
# set_gateway() {
# local result exitcode
# if [[ "$NET" == "dhcp" ]]; then
# GATE=""
# printf "%bGateway IP Address: %bDefault%b\n" "$GATEWAY$BOLD$DGN" "$BGN" "$CL"
# return 0
# fi
# while true; do
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "Gateway IP" \
# --inputbox "Enter gateway IP address" 8 58 \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# dialog --msgbox "Gateway IP address cannot be empty" 8 58
# continue
# elif [[ "$result" =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]]; then
# GATE=",gw=$result"
# printf "%bGateway IP Address: %b%s%b\n" "$GATEWAY$BOLD$DGN" "$BGN" "$result" "$CL"
# return 0
# else
# dialog --msgbox "Invalid IP address format" 8 58
# fi
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# done
# }
# set_apt_cacher() {
# local result exitcode
# if [[ "$var_os" == "alpine" ]]; then
# APT_CACHER=""
# APT_CACHER_IP=""
# return 0
# fi
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "APT-Cacher IP" \
# --inputbox "Set APT-Cacher IP (leave blank for none)" 8 58 \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# APT_CACHER_IP="$result"
# APT_CACHER="${APT_CACHER_IP:+yes}"
# printf "%bAPT-Cacher IP Address: %b%s%b\n" "$NETWORK$BOLD$DGN" "$BGN" "${APT_CACHER_IP:-Default}" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# toggle_ipv6() {
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "IPv6" \
# --yesno "Disable IPv6?" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Yes" --cancel-label "No"
# case $? in
# 0) DISABLEIP6="yes" ;;
# 1) DISABLEIP6="no" ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# printf "%bDisable IPv6: %b%s%b\n" "$DISABLEIPV6$BOLD$DGN" "$BGN" "$DISABLEIP6" "$CL"
# return 0
# }
# set_mtu() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "MTU SIZE" \
# --inputbox "Set Interface MTU Size (leave blank for default [1500])" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# MTU1="Default"
# MTU=""
# else
# MTU1="$result"
# MTU=",mtu=$MTU1"
# fi
# printf "%bInterface MTU Size: %b%s%b\n" "$DEFAULT$BOLD$DGN" "$BGN" "$MTU1" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_dns_search_domain() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "DNS Search Domain" \
# --inputbox "Set a DNS Search Domain (leave blank for HOST)" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# SX="Host"
# SD=""
# else
# SX="$result"
# SD="-searchdomain=$result"
# fi
# printf "%bDNS Search Domain: %b%s%b\n" "$SEARCH$BOLD$DGN" "$BGN" "$SX" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_dns_server() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "DNS SERVER IP" \
# --inputbox "Set a DNS Server IP (leave blank for HOST)" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# NX="Host"
# NS=""
# else
# NX="$result"
# NS="-nameserver=$result"
# fi
# printf "%bDNS Server IP Address: %b%s%b\n" "$NETWORK$BOLD$DGN" "$BGN" "$NX" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_mac_address() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "MAC ADDRESS" \
# --inputbox "Set a MAC Address (leave blank for generated MAC)" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# MAC1="Default"
# MAC=""
# else
# MAC1="$result"
# MAC=",hwaddr=$MAC1"
# fi
# printf "%bMAC Address: %b%s%b\n" "$MACADDRESS$BOLD$DGN" "$BGN" "$MAC1" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_vlan() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "VLAN" \
# --inputbox "Set a VLAN (leave blank for no VLAN)" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -z "$result" ]]; then
# VLAN1="Default"
# VLAN=""
# else
# VLAN1="$result"
# VLAN=",tag=$VLAN1"
# fi
# printf "%bVlan: %b%s%b\n" "$VLANTAG$BOLD$DGN" "$BGN" "$VLAN1" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_tags() {
# local result exitcode
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "Advanced Tags" \
# --inputbox "Set Custom Tags? [If you remove all, there will be no tags!]" 8 58 "$TAGS" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# if [[ -n "$result" ]]; then
# ADV_TAGS=$(tr -d '[:space:]' <<<"$result")
# TAGS="$ADV_TAGS"
# else
# TAGS=";"
# fi
# printf "%bTags: %b%s%b\n" "$NETWORK$BOLD$DGN" "$BGN" "$TAGS" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }
# set_ssh_access() {
# local result exitcode
# if [[ "$PW" == -password* ]]; then
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "SSH ACCESS" \
# --yesno "Enable Root SSH Access?" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Yes" --cancel-label "No"
# exitcode=$?
# case $exitcode in
# 0) SSH="yes" ;;
# 1) SSH="no" ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# else
# SSH="no"
# fi
# printf "%bRoot SSH Access: %b%s%b\n" "$ROOTSSH$BOLD$DGN" "$BGN" "$SSH" "$CL"
# if [[ "$SSH" == "yes" ]]; then
# result=$(dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "SSH Key" \
# --inputbox "SSH Authorized key for root (leave empty for none)" 8 58 "" \
# --extra-button --extra-label "Back" --ok-label "Next" --cancel-label "Exit" 3>&1 1>&2 2>&3)
# exitcode=$?
# case $exitcode in
# 0)
# SSH_AUTHORIZED_KEY="$result"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# else
# SSH_AUTHORIZED_KEY=""
# return 0
# fi
# }
# set_fuse() {
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "FUSE Support" \
# --yesno "Enable FUSE (Filesystem in Userspace) support in the container?" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Yes" --cancel-label "No"
# case $? in
# 0) ENABLE_FUSE="yes" ;;
# 1) ENABLE_FUSE="no" ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# printf "%bFUSE (Filesystem in Userspace) Support: %b%s%b\n" "$FUSE$BOLD$DGN" "$BGN" "$ENABLE_FUSE" "$CL"
# return 0
# }
# set_verbose() {
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "VERBOSE MODE" \
# --yesno "Enable Verbose Mode?" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Yes" --cancel-label "No"
# case $? in
# 0) VERB="yes" ;;
# 1) VERB="no" ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# printf "%bVerbose Mode: %b%s%b\n" "$SEARCH$BOLD$DGN" "$BGN" "$VERB" "$CL"
# return 0
# }
# confirm_creation() {
# dialog --backtitle "[dev] Proxmox VE Helper Scripts" \
# --title "ADVANCED SETTINGS COMPLETE" \
# --yesno "Ready to create ${APP} LXC?" 10 58 \
# --extra-button --extra-label "Back" --ok-label "Yes" --cancel-label "No"
# case $? in
# 0)
# printf "%bCreating a %s LXC using the above advanced settings%b\n" "$CREATING$BOLD$RD" "$APP" "$CL"
# return 0
# ;;
# 3) return 2 ;;
# *) return 1 ;;
# esac
# }

View File

@ -1,281 +0,0 @@
# Copyright (c) 2021-2025 tteck
# Author: tteck (tteckster)
# Co-Author: MickLesk
# Co-Author: michelroegl-brunner
# License: MIT
# https://github.com/community-scripts/ProxmoxVED/raw/main/LICENSE
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/core.func)
load_functions
# color() {
# # Colors
# YW=$(echo "\033[33m")
# YWB=$(echo "\033[93m")
# BL=$(echo "\033[36m")
# RD=$(echo "\033[01;31m")
# GN=$(echo "\033[1;92m")
# # Formatting
# CL=$(echo "\033[m")
# BFR="\\r\\033[K"
# BOLD=$(echo "\033[1m")
# HOLD=" "
# TAB=" "
# # System
# RETRY_NUM=10
# RETRY_EVERY=3
# # Icons
# CM="${TAB}✔️${TAB}${CL}"
# CROSS="${TAB}✖️${TAB}${CL}"
# INFO="${TAB}💡${TAB}${CL}"
# NETWORK="${TAB}📡${TAB}${CL}"
# OS="${TAB}🖥️${TAB}${CL}"
# OSVERSION="${TAB}🌟${TAB}${CL}"
# HOSTNAME="${TAB}🏠${TAB}${CL}"
# GATEWAY="${TAB}🌐${TAB}${CL}"
# DEFAULT="${TAB}⚙️${TAB}${CL}"
# }
# Function to set STD mode based on verbosity
set_std_mode() {
if [ "$VERBOSE" = "yes" ]; then
STD=""
else
STD="silent"
fi
}
# Silent execution function
silent() {
"$@" >/dev/null 2>&1
}
# This function enables IPv6 if it's not disabled and sets verbose mode
verb_ip6() {
set_std_mode # Set STD mode based on VERBOSE
if [ "$DISABLEIPV6" == "yes" ]; then
echo "net.ipv6.conf.all.disable_ipv6 = 1" >>/etc/sysctl.conf
$STD sysctl -p
fi
}
# This function sets error handling options and defines the error_handler function to handle errors
catch_errors() {
set -Eeuo pipefail
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function handles errors
error_handler() {
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/api.func)
if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
printf "\e[?25h"
local exit_code="$?"
local line_number="$1"
local command="$2"
local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}"
echo -e "\n$error_message"
[[ -n "${SPINNER_PID:-}" ]] && kill "$SPINNER_PID" &>/dev/null || true
if [[ "$line_number" -eq 50 ]]; then
echo -e "The silent function has suppressed the error, run the script with verbose mode enabled, which will provide more detailed output.\n"
post_update_to_api "failed" "No error message, script ran in silent mode"
else
post_update_to_api "failed" "${command}"
fi
}
# # This function displays a spinner.
# spinner() {
# local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
# local spin_i=0
# local interval=0.1
# printf "\e[?25l"
# local color="${YWB}"
# while true; do
# printf "\r ${color}%s${CL}" "${frames[spin_i]}"
# spin_i=$(((spin_i + 1) % ${#frames[@]}))
# sleep "$interval"
# done
# }
# # This function displays an informational message with a yellow color.
# msg_info() {
# local msg="$1"
# echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
# spinner &
# SPINNER_PID=$!
# }
# # This function displays a success message with a green color.
# msg_ok() {
# if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
# printf "\e[?25h"
# local msg="$1"
# echo -e "${BFR}${CM}${GN}${msg}${CL}"
# }
# # This function displays a error message with a red color.
# msg_error() {
# if [ -n "$SPINNER_PID" ] && ps -p "$SPINNER_PID" >/dev/null; then kill "$SPINNER_PID" >/dev/null; fi
# printf "\e[?25h"
# local msg="$1"
# echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
# }
# This function sets up the Container OS by generating the locale, setting the timezone, and checking the network connection
setting_up_container() {
msg_info "Setting up Container OS"
sed -i "/$LANG/ s/\(^# \)//" /etc/locale.gen
locale_line=$(grep -v '^#' /etc/locale.gen | grep -E '^[a-zA-Z]' | awk '{print $1}' | head -n 1)
echo "LANG=${locale_line}" >/etc/default/locale
locale-gen >/dev/null
export LANG=${locale_line}
echo $tz >/etc/timezone
ln -sf /usr/share/zoneinfo/$tz /etc/localtime
for ((i = RETRY_NUM; i > 0; i--)); do
if [ "$(hostname -I)" != "" ]; then
break
fi
echo 1>&2 -en "${CROSS}${RD} No Network! "
sleep $RETRY_EVERY
done
if [ "$(hostname -I)" = "" ]; then
echo 1>&2 -e "\n${CROSS}${RD} No Network After $RETRY_NUM Tries${CL}"
echo -e "${NETWORK}Check Network Settings"
exit 1
fi
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
systemctl disable -q --now systemd-networkd-wait-online.service
msg_ok "Set up Container OS"
msg_ok "Network Connected: ${BL}$(hostname -I)"
}
# This function checks the network connection by pinging a known IP address and prompts the user to continue if the internet is not connected
network_check() {
set +e
trap - ERR
ipv4_connected=false
ipv6_connected=false
sleep 1
# Check IPv4 connectivity to Google, Cloudflare & Quad9 DNS servers.
if ping -c 1 -W 1 1.1.1.1 &>/dev/null || ping -c 1 -W 1 8.8.8.8 &>/dev/null || ping -c 1 -W 1 9.9.9.9 &>/dev/null; then
msg_ok "IPv4 Internet Connected"
ipv4_connected=true
else
msg_error "IPv4 Internet Not Connected"
fi
# Check IPv6 connectivity to Google, Cloudflare & Quad9 DNS servers.
if ping6 -c 1 -W 1 2606:4700:4700::1111 &>/dev/null || ping6 -c 1 -W 1 2001:4860:4860::8888 &>/dev/null || ping6 -c 1 -W 1 2620:fe::fe &>/dev/null; then
msg_ok "IPv6 Internet Connected"
ipv6_connected=true
else
msg_error "IPv6 Internet Not Connected"
fi
# If both IPv4 and IPv6 checks fail, prompt the user
if [[ $ipv4_connected == false && $ipv6_connected == false ]]; then
read -r -p "No Internet detected,would you like to continue anyway? <y/N> " prompt
if [[ "${prompt,,}" =~ ^(y|yes)$ ]]; then
echo -e "${INFO}${RD}Expect Issues Without Internet${CL}"
else
echo -e "${NETWORK}Check Network Settings"
exit 1
fi
fi
RESOLVEDIP=$(getent hosts github.com | awk '{ print $1 }')
if [[ -z "$RESOLVEDIP" ]]; then msg_error "DNS Lookup Failure"; else msg_ok "DNS Resolved github.com to ${BL}$RESOLVEDIP${CL}"; fi
set -e
trap 'error_handler $LINENO "$BASH_COMMAND"' ERR
}
# This function updates the Container OS by running apt-get update and upgrade
update_os() {
msg_info "Updating Container OS"
if [[ "$CACHER" == "yes" ]]; then
echo "Acquire::http::Proxy-Auto-Detect \"/usr/local/bin/apt-proxy-detect.sh\";" >/etc/apt/apt.conf.d/00aptproxy
cat <<EOF >/usr/local/bin/apt-proxy-detect.sh
#!/bin/bash
if nc -w1 -z "${CACHER_IP}" 3142; then
echo -n "http://${CACHER_IP}:3142"
else
echo -n "DIRECT"
fi
EOF
chmod +x /usr/local/bin/apt-proxy-detect.sh
fi
$STD apt-get update
$STD apt-get -o Dpkg::Options::="--force-confold" -y dist-upgrade
rm -rf /usr/lib/python3.*/EXTERNALLY-MANAGED
msg_ok "Updated Container OS"
msg_info "Installing core dependencies"
$STD apt-get update
$STD apt-get install -y sudo curl mc gnupg2
msg_ok "Core dependencies installed"
source <(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/tools.func)
}
# This function modifies the message of the day (motd) and SSH settings
motd_ssh() {
grep -qxF "export TERM='xterm-256color'" /root/.bashrc || echo "export TERM='xterm-256color'" >>/root/.bashrc
if [ -f "/etc/os-release" ]; then
OS_NAME=$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"')
OS_VERSION=$(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')
elif [ -f "/etc/debian_version" ]; then
OS_NAME="Debian"
OS_VERSION=$(cat /etc/debian_version)
fi
PROFILE_FILE="/etc/profile.d/00_lxc-details.sh"
echo "echo -e \"\"" >"$PROFILE_FILE"
echo -e "echo -e \"${BOLD}${YW}${APPLICATION} LXC Container - DEV Repository${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${RD}WARNING: This is a DEVELOPMENT version (ProxmoxVED). Do NOT use in production!${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} OS: ${GN}${OS_NAME} - Version: ${OS_VERSION}${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Hostname: ${GN}\$(hostname)${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} IP Address: ${GN}\$(hostname -I | awk '{print \$1}')${CL}\"" >>"$PROFILE_FILE"
echo -e "echo -e \"${YW} Repository: ${GN}https://github.com/community-scripts/ProxmoxVED${CL}\"" >>"$PROFILE_FILE"
echo "echo \"\"" >>"$PROFILE_FILE"
chmod -x /etc/update-motd.d/*
if [[ "${SSH_ROOT}" == "yes" ]]; then
sed -i "s/#PermitRootLogin prohibit-password/PermitRootLogin yes/g" /etc/ssh/sshd_config
systemctl restart sshd
fi
}
# This function customizes the container by modifying the getty service and enabling auto-login for the root user
customize() {
if [[ "$PASSWORD" == "" ]]; then
msg_info "Customizing Container"
GETTY_OVERRIDE="/etc/systemd/system/container-getty@1.service.d/override.conf"
mkdir -p $(dirname $GETTY_OVERRIDE)
cat <<EOF >$GETTY_OVERRIDE
[Service]
ExecStart=
ExecStart=-/sbin/agetty --autologin root --noclear --keep-baud tty%I 115200,38400,9600 \$TERM
EOF
systemctl daemon-reload
systemctl restart $(basename $(dirname $GETTY_OVERRIDE) | sed 's/\.d//')
msg_ok "Customized Container"
fi
echo "bash -c \"\$(curl -fsSL https://github.com/community-scripts/ProxmoxVED/raw/main/ct/${app}.sh)\"" >/usr/bin/update
chmod +x /usr/bin/update
if [[ -n "${SSH_AUTHORIZED_KEY}" ]]; then
mkdir -p /root/.ssh
echo "${SSH_AUTHORIZED_KEY}" >/root/.ssh/authorized_keys
chmod 700 /root/.ssh
chmod 600 /root/.ssh/authorized_keys
fi
}

View File

@ -1,98 +0,0 @@
#!/usr/bin/env bash
# Spinner state
declare -A SPINNER_PIDS
declare -A SPINNER_MSGS
declare -A MSG_SHOWN
# Color definitions (adjust as needed)
RD='\033[0;31m'
GN='\033[0;32m'
YW='\033[0;33m'
CL='\033[0m'
CM='✔'
CROSS='✘'
# Trap cleanup
trap cleanup_spinners EXIT INT TERM HUP
# Hash function for message ID
msg_hash() {
local input="$1"
echo -n "$input" | sha1sum | awk '{print $1}'
}
# Start a spinner for a specific message
start_spinner_for_msg() {
local msg="$1"
local id
id=$(msg_hash "$msg")
[[ -n "${MSG_SHOWN["$id"]+x}" ]] && return
MSG_SHOWN["$id"]=1
SPINNER_MSGS["$id"]="$msg"
local frames=(⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏)
local interval=0.1
local spin_i=0
{
while true; do
printf "\r\e[2K%s %b" "${frames[spin_i]}" "${YW}${msg}${CL}" >&2
spin_i=$(((spin_i + 1) % ${#frames[@]}))
sleep "$interval"
done
} &
SPINNER_PIDS["$id"]=$!
disown "${SPINNER_PIDS["$id"]}"
}
# Stop the spinner for a specific message
stop_spinner_for_msg() {
local msg="$1"
local id
id=$(msg_hash "$msg")
if [[ -n "${SPINNER_PIDS["$id"]+x}" ]] && ps -p "${SPINNER_PIDS["$id"]}" >/dev/null 2>&1; then
kill "${SPINNER_PIDS["$id"]}" 2>/dev/null
wait "${SPINNER_PIDS["$id"]}" 2>/dev/null || true
fi
unset SPINNER_PIDS["$id"]
unset SPINNER_MSGS["$id"]
unset MSG_SHOWN["$id"]
}
# Cleanup all active spinners
cleanup_spinners() {
for id in "${!SPINNER_PIDS[@]}"; do
if ps -p "${SPINNER_PIDS[$id]}" >/dev/null 2>&1; then
kill "${SPINNER_PIDS[$id]}" 2>/dev/null
wait "${SPINNER_PIDS[$id]}" 2>/dev/null || true
fi
unset SPINNER_PIDS["$id"]
unset SPINNER_MSGS["$id"]
unset MSG_SHOWN["$id"]
done
}
# Show info message with spinner
msg_info() {
local msg="$1"
start_spinner_for_msg "$msg"
}
# End spinner and show success message
msg_ok() {
local msg="$1"
stop_spinner_for_msg "$msg"
printf "\r\e[2K%s %b\n" "${CM}" "${GN}${msg}${CL}" >&2
}
# End spinner and show error message
msg_error() {
local msg="$1"
stop_spinner_for_msg "$msg"
printf "\r\e[2K%s %b\n" "${CROSS}" "${RD}${msg}${CL}" >&2
}