mirror of
https://github.com/StuffAnThings/qbit_manage.git
synced 2025-10-10 05:46:55 +08:00
# Requirements Updated - "humanize==4.13.0" - "ruff==0.12.11" # Breaking Changes - **DEPRECATE `QBT_CONFIG` / `--config-file` OPTION** - No longer supporting `QBT_CONFIG` / `--config-file`. Instead please switch over to **`QBT_CONFIG_DIR` / `--config-dir`**. - `QBT_CONFIG` / `--config-file` option will still work for now but is now considered legacy and will be removed in a future release. - **Note**: All yml/yaml files will be treated as valid configuration files and loaded in the `QBT_CONFIG_DIR` path. Please ensure you **remove** any old/unused configurations that you don't want to be loaded prior to using this path. # Improvements - Adds docker support for PUID/PGID environment variables - Dockerfile copies the latest `config.yml.sample` in the config folder - Add `QBT_HOST` / `--host` option to specify webUI host address (#929 Thanks to @QuixThe2nd) - WebUI: Quick action settings persist now # Bug Fixes - WebUI: Fix loading spinner to be centered in the webUI **Full Changelog**: https://github.com/StuffAnThings/qbit_manage/compare/v4.5.5...v4.6.0 --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Fabricio Silva <hi@fabricio.dev> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Parsa Yazdani <parsa@yazdani.au> Co-authored-by: Actionbot <actions@github.com>
180 lines
5.1 KiB
Bash
180 lines
5.1 KiB
Bash
#!/bin/bash
|
|
set -euo pipefail # Exit on error, undefined vars, pipe failures
|
|
|
|
# Configuration
|
|
readonly SOURCE_FILE="/app/config/config.yml.sample"
|
|
readonly DEST_DIR="${QBT_CONFIG_DIR:-/config}"
|
|
readonly DEST_FILE="${DEST_DIR}/config.yml.sample"
|
|
|
|
# Logging function for consistent output
|
|
log() {
|
|
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >&2
|
|
}
|
|
|
|
# Validate numeric environment variables
|
|
validate_numeric_env() {
|
|
local var_name="$1"
|
|
local var_value="$2"
|
|
|
|
if [[ -n "$var_value" ]] && ! [[ "$var_value" =~ ^[0-9]+$ ]]; then
|
|
log "Warning: $var_name must be numeric. Got $var_name='$var_value' - ignoring PUID/PGID and running as root"
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Validate and set PUID/PGID
|
|
validate_user_group_ids() {
|
|
local puid_valid=0
|
|
local pgid_valid=0
|
|
|
|
if ! validate_numeric_env "PUID" "${PUID:-}"; then
|
|
puid_valid=1
|
|
fi
|
|
|
|
if ! validate_numeric_env "PGID" "${PGID:-}"; then
|
|
pgid_valid=1
|
|
fi
|
|
|
|
# If either is invalid, clear both
|
|
if [[ $puid_valid -eq 1 ]] || [[ $pgid_valid -eq 1 ]]; then
|
|
PUID=""
|
|
PGID=""
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Safely copy file with atomic operation and error handling
|
|
safe_copy() {
|
|
local src="$1"
|
|
local dest="$2"
|
|
local temp_file="${dest}.tmp"
|
|
|
|
# Validate source file exists and is readable
|
|
if [[ ! -f "$src" ]] || [[ ! -r "$src" ]]; then
|
|
log "Error: Source file '$src' does not exist or is not readable"
|
|
return 1
|
|
fi
|
|
|
|
# Create parent directory if it doesn't exist
|
|
local dest_dir
|
|
dest_dir="$(dirname "$dest")"
|
|
if [[ ! -d "$dest_dir" ]]; then
|
|
mkdir -p "$dest_dir" || {
|
|
log "Error: Could not create destination directory '$dest_dir'"
|
|
return 1
|
|
}
|
|
fi
|
|
|
|
# Atomic copy operation
|
|
if cp "$src" "$temp_file" && mv "$temp_file" "$dest"; then
|
|
log "Successfully copied $src to $dest"
|
|
return 0
|
|
else
|
|
# Clean up temp file on failure
|
|
[[ -f "$temp_file" ]] && rm -f "$temp_file"
|
|
log "Error: Failed to copy $src to $dest"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Optimized permission fixing with better performance
|
|
fix_permissions() {
|
|
local path="$1"
|
|
|
|
# Skip if PUID or PGID are not set
|
|
if [[ -z "${PUID:-}" ]] || [[ -z "${PGID:-}" ]]; then
|
|
log "Skipping permission fix for $path - PUID or PGID not set"
|
|
return 0
|
|
fi
|
|
|
|
# Check if we're running as root
|
|
if [[ "$(id -u)" != "0" ]]; then
|
|
log "Skipping permission fix for $path - not running as root"
|
|
return 0
|
|
fi
|
|
|
|
local needs_fix=0
|
|
|
|
if [[ -d "$path" ]]; then
|
|
# Check if any files in directory need ownership change
|
|
if find "$path" -xdev \( -not -user "$PUID" -o -not -group "$PGID" \) -print -quit 2>/dev/null | grep -q .; then
|
|
needs_fix=1
|
|
fi
|
|
elif [[ -e "$path" ]]; then
|
|
# Check if file needs ownership change
|
|
if [[ "$(stat -c '%u:%g' "$path" 2>/dev/null || echo "0:0")" != "$PUID:$PGID" ]]; then
|
|
needs_fix=1
|
|
fi
|
|
else
|
|
log "Warning: Path '$path' does not exist, skipping permission fix"
|
|
return 0
|
|
fi
|
|
|
|
if [[ $needs_fix -eq 1 ]]; then
|
|
if chown -R "$PUID:$PGID" "$path" 2>/dev/null; then
|
|
local type_msg="file"
|
|
[[ -d "$path" ]] && type_msg="directory"
|
|
log "Corrected ownership of $type_msg $path to $PUID:$PGID"
|
|
return 0
|
|
else
|
|
log "Warning: Could not change ownership of $path"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Execute command with appropriate privilege level
|
|
execute_command() {
|
|
local current_uid
|
|
current_uid="$(id -u)"
|
|
|
|
if [[ "$current_uid" = "0" ]]; then
|
|
if [[ -n "${PUID:-}" ]] && [[ -n "${PGID:-}" ]]; then
|
|
log "Changing privileges to PUID:PGID = $PUID:$PGID"
|
|
exec /sbin/su-exec "${PUID}:${PGID}" "$@" || {
|
|
log "Warning: Could not drop privileges to ${PUID}:${PGID}, continuing as root"
|
|
exec "$@"
|
|
}
|
|
else
|
|
log "PUID/PGID not set, running as root"
|
|
exec "$@"
|
|
fi
|
|
else
|
|
log "Already running as non-root user (UID: $current_uid), executing command"
|
|
exec "$@"
|
|
fi
|
|
}
|
|
|
|
# Main execution
|
|
main() {
|
|
# Validate user/group IDs
|
|
validate_user_group_ids
|
|
|
|
# Handle config file setup
|
|
if [[ -d "$DEST_DIR" ]]; then
|
|
if [[ -f "$SOURCE_FILE" ]] && [[ -s "$SOURCE_FILE" ]]; then
|
|
# Check if destination needs updating
|
|
if [[ ! -f "$DEST_FILE" ]] || ! cmp -s "$SOURCE_FILE" "$DEST_FILE" 2>/dev/null; then
|
|
if safe_copy "$SOURCE_FILE" "$DEST_FILE"; then
|
|
# Fix permissions if running as root and IDs are set
|
|
if [[ "$(id -u)" = "0" ]] && [[ -n "${PUID:-}" ]] && [[ -n "${PGID:-}" ]]; then
|
|
fix_permissions "$DEST_FILE"
|
|
fi
|
|
fi
|
|
fi
|
|
elif [[ ! -f "$SOURCE_FILE" ]]; then
|
|
log "Warning: Source file $SOURCE_FILE does not exist, skipping config setup"
|
|
fi
|
|
fi
|
|
|
|
# Execute the main command
|
|
execute_command "$@"
|
|
}
|
|
|
|
# Run main function with all arguments
|
|
main "$@"
|