mirror of
https://github.com/tw93/Mole.git
synced 2026-02-15 17:30:05 +00:00
feat: harden user file handling and gate LaunchServices rebuild (#159)
- add ensure_user_dir/ensure_user_file helpers in lib/core/base.sh, including sudo-aware ownership correction under the invoking user’s home - use the helpers across clean/optimize/purge/uninstall/whitelist to create cache and export files safely (no naked mkdir/touch), including log files and dry-run exports - ensure purge stats/count files and update message caches are pre-created with safe permissions - add Darwin version helpers and skip LaunchServices/dyld rebuild on macOS 15+, keeping the existing corruption protection for earlier versions - guard brew cache timestamp writes and TCC permission flags with safe file creation to avoid root-owned artifacts
This commit is contained in:
@@ -159,6 +159,7 @@ start_section() {
|
|||||||
|
|
||||||
# Write section header to export list in dry-run mode
|
# Write section header to export list in dry-run mode
|
||||||
if [[ "$DRY_RUN" == "true" ]]; then
|
if [[ "$DRY_RUN" == "true" ]]; then
|
||||||
|
ensure_user_file "$EXPORT_LIST_FILE"
|
||||||
echo "" >> "$EXPORT_LIST_FILE"
|
echo "" >> "$EXPORT_LIST_FILE"
|
||||||
echo "=== $1 ===" >> "$EXPORT_LIST_FILE"
|
echo "=== $1 ===" >> "$EXPORT_LIST_FILE"
|
||||||
fi
|
fi
|
||||||
@@ -452,7 +453,7 @@ start_cleanup() {
|
|||||||
SYSTEM_CLEAN=false
|
SYSTEM_CLEAN=false
|
||||||
|
|
||||||
# Initialize export list file
|
# Initialize export list file
|
||||||
mkdir -p "$(dirname "$EXPORT_LIST_FILE")"
|
ensure_user_file "$EXPORT_LIST_FILE"
|
||||||
cat > "$EXPORT_LIST_FILE" << EOF
|
cat > "$EXPORT_LIST_FILE" << EOF
|
||||||
# Mole Cleanup Preview - $(date '+%Y-%m-%d %H:%M:%S')
|
# Mole Cleanup Preview - $(date '+%Y-%m-%d %H:%M:%S')
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ cleanup_path() {
|
|||||||
ensure_directory() {
|
ensure_directory() {
|
||||||
local raw_path="$1"
|
local raw_path="$1"
|
||||||
local expanded_path="${raw_path/#\~/$HOME}"
|
local expanded_path="${raw_path/#\~/$HOME}"
|
||||||
mkdir -p "$expanded_path" > /dev/null 2>&1 || true
|
ensure_user_dir "$expanded_path"
|
||||||
}
|
}
|
||||||
|
|
||||||
count_local_snapshots() {
|
count_local_snapshots() {
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ start_purge() {
|
|||||||
|
|
||||||
# Initialize stats file in user cache directory
|
# Initialize stats file in user cache directory
|
||||||
local stats_dir="${XDG_CACHE_HOME:-$HOME/.cache}/mole"
|
local stats_dir="${XDG_CACHE_HOME:-$HOME/.cache}/mole"
|
||||||
mkdir -p "$stats_dir"
|
ensure_user_dir "$stats_dir"
|
||||||
|
ensure_user_file "$stats_dir/purge_stats"
|
||||||
|
ensure_user_file "$stats_dir/purge_count"
|
||||||
echo "0" > "$stats_dir/purge_stats"
|
echo "0" > "$stats_dir/purge_stats"
|
||||||
echo "0" > "$stats_dir/purge_count"
|
echo "0" > "$stats_dir/purge_count"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ scan_applications() {
|
|||||||
local cache_ttl=86400 # 24 hours
|
local cache_ttl=86400 # 24 hours
|
||||||
local force_rescan="${1:-false}"
|
local force_rescan="${1:-false}"
|
||||||
|
|
||||||
mkdir -p "$cache_dir" 2> /dev/null
|
ensure_user_dir "$cache_dir"
|
||||||
|
|
||||||
# Check if cache exists and is fresh
|
# Check if cache exists and is fresh
|
||||||
if [[ $force_rescan == false && -f "$cache_file" ]]; then
|
if [[ $force_rescan == false && -f "$cache_file" ]]; then
|
||||||
@@ -310,6 +310,7 @@ scan_applications() {
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
ensure_user_file "$cache_file"
|
||||||
cp "${temp_file}.sorted" "$cache_file" 2> /dev/null || true
|
cp "${temp_file}.sorted" "$cache_file" 2> /dev/null || true
|
||||||
|
|
||||||
if [[ -f "${temp_file}.sorted" ]]; then
|
if [[ -f "${temp_file}.sorted" ]]; then
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ scan_applications() {
|
|||||||
local cache_ttl=86400 # 24 hours
|
local cache_ttl=86400 # 24 hours
|
||||||
local force_rescan="${1:-false}"
|
local force_rescan="${1:-false}"
|
||||||
|
|
||||||
mkdir -p "$cache_dir" 2> /dev/null
|
ensure_user_dir "$cache_dir"
|
||||||
|
|
||||||
# Check if cache exists and is fresh
|
# Check if cache exists and is fresh
|
||||||
if [[ $force_rescan == false && -f "$cache_file" ]]; then
|
if [[ $force_rescan == false && -f "$cache_file" ]]; then
|
||||||
@@ -344,6 +344,7 @@ scan_applications() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Save to cache (simplified - no metadata)
|
# Save to cache (simplified - no metadata)
|
||||||
|
ensure_user_file "$cache_file"
|
||||||
cp "${temp_file}.sorted" "$cache_file" 2> /dev/null || true
|
cp "${temp_file}.sorted" "$cache_file" 2> /dev/null || true
|
||||||
|
|
||||||
# Return sorted file
|
# Return sorted file
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ CACHE_DIR="${HOME}/.cache/mole"
|
|||||||
CACHE_TTL=600 # 10 minutes in seconds
|
CACHE_TTL=600 # 10 minutes in seconds
|
||||||
|
|
||||||
# Ensure cache directory exists
|
# Ensure cache directory exists
|
||||||
mkdir -p "$CACHE_DIR" 2> /dev/null || true
|
ensure_user_dir "$CACHE_DIR"
|
||||||
|
|
||||||
clear_cache_file() {
|
clear_cache_file() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
@@ -302,6 +302,7 @@ check_mole_update() {
|
|||||||
latest_version=$(curl -fsSL https://api.github.com/repos/tw93/mole/releases/latest 2> /dev/null | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/' || echo "")
|
latest_version=$(curl -fsSL https://api.github.com/repos/tw93/mole/releases/latest 2> /dev/null | grep '"tag_name"' | sed -E 's/.*"v?([^"]+)".*/\1/' || echo "")
|
||||||
# Save to cache
|
# Save to cache
|
||||||
if [[ -n "$latest_version" ]]; then
|
if [[ -n "$latest_version" ]]; then
|
||||||
|
ensure_user_file "$cache_file"
|
||||||
echo "$latest_version" > "$cache_file" 2> /dev/null || true
|
echo "$latest_version" > "$cache_file" 2> /dev/null || true
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ clean_homebrew() {
|
|||||||
|
|
||||||
# Update cache timestamp on successful completion
|
# Update cache timestamp on successful completion
|
||||||
if [[ "$brew_success" == "true" || "$autoremove_success" == "true" ]]; then
|
if [[ "$brew_success" == "true" || "$autoremove_success" == "true" ]]; then
|
||||||
mkdir -p "$(dirname "$brew_cache_file")"
|
ensure_user_file "$brew_cache_file"
|
||||||
date +%s > "$brew_cache_file"
|
date +%s > "$brew_cache_file"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ check_tcc_permissions() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Mark permissions as granted (won't prompt again)
|
# Mark permissions as granted (won't prompt again)
|
||||||
mkdir -p "$(dirname "$permission_flag")" 2> /dev/null || true
|
ensure_user_file "$permission_flag"
|
||||||
touch "$permission_flag" 2> /dev/null || true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Clean browser Service Worker cache, protecting web editing tools (capcut, photopea, pixlr)
|
# Clean browser Service Worker cache, protecting web editing tools (capcut, photopea, pixlr)
|
||||||
|
|||||||
193
lib/core/base.sh
193
lib/core/base.sh
@@ -167,6 +167,25 @@ get_free_space() {
|
|||||||
command df -h / | awk 'NR==2 {print $4}'
|
command df -h / | awk 'NR==2 {print $4}'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Get Darwin kernel major version (e.g., 24 for 24.2.0)
|
||||||
|
get_darwin_major() {
|
||||||
|
local kernel
|
||||||
|
kernel=$(uname -r 2> /dev/null || true)
|
||||||
|
local major="${kernel%%.*}"
|
||||||
|
if [[ ! "$major" =~ ^[0-9]+$ ]]; then
|
||||||
|
major=0
|
||||||
|
fi
|
||||||
|
echo "$major"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if Darwin kernel major version meets minimum
|
||||||
|
is_darwin_ge() {
|
||||||
|
local minimum="$1"
|
||||||
|
local major
|
||||||
|
major=$(get_darwin_major)
|
||||||
|
[[ "$major" -ge "$minimum" ]]
|
||||||
|
}
|
||||||
|
|
||||||
# Get optimal parallel jobs for operation type (scan|io|compute|default)
|
# Get optimal parallel jobs for operation type (scan|io|compute|default)
|
||||||
get_optimal_parallel_jobs() {
|
get_optimal_parallel_jobs() {
|
||||||
local operation_type="${1:-default}"
|
local operation_type="${1:-default}"
|
||||||
@@ -185,6 +204,180 @@ get_optimal_parallel_jobs() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# User Context Utilities
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
is_root_user() {
|
||||||
|
[[ "$(id -u)" == "0" ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
get_user_home() {
|
||||||
|
local user="$1"
|
||||||
|
local home=""
|
||||||
|
|
||||||
|
if [[ -z "$user" ]]; then
|
||||||
|
echo ""
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v dscl > /dev/null 2>&1; then
|
||||||
|
home=$(dscl . -read "/Users/$user" NFSHomeDirectory 2> /dev/null | awk '{print $2}' | head -1 || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$home" ]]; then
|
||||||
|
home=$(eval echo "~$user" 2> /dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "$home" == "~"* ]]; then
|
||||||
|
home=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$home"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_invoking_user() {
|
||||||
|
if [[ -n "${SUDO_USER:-}" && "${SUDO_USER:-}" != "root" ]]; then
|
||||||
|
echo "$SUDO_USER"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
echo "${USER:-}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_invoking_uid() {
|
||||||
|
if [[ -n "${SUDO_UID:-}" ]]; then
|
||||||
|
echo "$SUDO_UID"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local uid
|
||||||
|
uid=$(id -u 2> /dev/null || true)
|
||||||
|
echo "$uid"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_invoking_gid() {
|
||||||
|
if [[ -n "${SUDO_GID:-}" ]]; then
|
||||||
|
echo "$SUDO_GID"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local gid
|
||||||
|
gid=$(id -g 2> /dev/null || true)
|
||||||
|
echo "$gid"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_invoking_home() {
|
||||||
|
if [[ -n "${SUDO_USER:-}" && "${SUDO_USER:-}" != "root" ]]; then
|
||||||
|
get_user_home "$SUDO_USER"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "${HOME:-}"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_user_dir() {
|
||||||
|
local raw_path="$1"
|
||||||
|
if [[ -z "$raw_path" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local target_path="$raw_path"
|
||||||
|
if [[ "$target_path" == "~"* ]]; then
|
||||||
|
target_path="${target_path/#\~/$HOME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p "$target_path" 2> /dev/null || true
|
||||||
|
|
||||||
|
if ! is_root_user; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local sudo_user="${SUDO_USER:-}"
|
||||||
|
if [[ -z "$sudo_user" || "$sudo_user" == "root" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local user_home
|
||||||
|
user_home=$(get_user_home "$sudo_user")
|
||||||
|
if [[ -z "$user_home" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
user_home="${user_home%/}"
|
||||||
|
|
||||||
|
if [[ "$target_path" != "$user_home" && "$target_path" != "$user_home/"* ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local owner_uid="${SUDO_UID:-}"
|
||||||
|
local owner_gid="${SUDO_GID:-}"
|
||||||
|
if [[ -z "$owner_uid" || -z "$owner_gid" ]]; then
|
||||||
|
owner_uid=$(id -u "$sudo_user" 2> /dev/null || true)
|
||||||
|
owner_gid=$(id -g "$sudo_user" 2> /dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$owner_uid" || -z "$owner_gid" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local dir="$target_path"
|
||||||
|
while [[ -n "$dir" && "$dir" != "/" ]]; do
|
||||||
|
chown "$owner_uid:$owner_gid" "$dir" 2> /dev/null || true
|
||||||
|
if [[ "$dir" == "$user_home" ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
dir=$(dirname "$dir")
|
||||||
|
if [[ "$dir" == "." ]]; then
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_user_file() {
|
||||||
|
local raw_path="$1"
|
||||||
|
if [[ -z "$raw_path" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local target_path="$raw_path"
|
||||||
|
if [[ "$target_path" == "~"* ]]; then
|
||||||
|
target_path="${target_path/#\~/$HOME}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_user_dir "$(dirname "$target_path")"
|
||||||
|
touch "$target_path" 2> /dev/null || true
|
||||||
|
|
||||||
|
if ! is_root_user; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local sudo_user="${SUDO_USER:-}"
|
||||||
|
if [[ -z "$sudo_user" || "$sudo_user" == "root" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local user_home
|
||||||
|
user_home=$(get_user_home "$sudo_user")
|
||||||
|
if [[ -z "$user_home" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
user_home="${user_home%/}"
|
||||||
|
|
||||||
|
if [[ "$target_path" != "$user_home" && "$target_path" != "$user_home/"* ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
local owner_uid="${SUDO_UID:-}"
|
||||||
|
local owner_gid="${SUDO_GID:-}"
|
||||||
|
if [[ -z "$owner_uid" || -z "$owner_gid" ]]; then
|
||||||
|
owner_uid=$(id -u "$sudo_user" 2> /dev/null || true)
|
||||||
|
owner_gid=$(id -g "$sudo_user" 2> /dev/null || true)
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$owner_uid" && -n "$owner_gid" ]]; then
|
||||||
|
chown "$owner_uid:$owner_gid" "$target_path" 2> /dev/null || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Formatting Utilities
|
# Formatting Utilities
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ readonly DEBUG_LOG_FILE="${HOME}/.config/mole/mole_debug_session.log"
|
|||||||
readonly LOG_MAX_SIZE_DEFAULT=1048576 # 1MB
|
readonly LOG_MAX_SIZE_DEFAULT=1048576 # 1MB
|
||||||
|
|
||||||
# Ensure log directory exists
|
# Ensure log directory exists
|
||||||
mkdir -p "$(dirname "$LOG_FILE")" 2> /dev/null || true
|
ensure_user_dir "$(dirname "$LOG_FILE")"
|
||||||
|
if is_root_user && [[ -n "${SUDO_USER:-}" && "${SUDO_USER:-}" != "root" ]]; then
|
||||||
|
ensure_user_file "$LOG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Log Rotation
|
# Log Rotation
|
||||||
@@ -41,7 +44,7 @@ rotate_log_once() {
|
|||||||
local max_size="${MOLE_MAX_LOG_SIZE:-$LOG_MAX_SIZE_DEFAULT}"
|
local max_size="${MOLE_MAX_LOG_SIZE:-$LOG_MAX_SIZE_DEFAULT}"
|
||||||
if [[ -f "$LOG_FILE" ]] && [[ $(get_file_size "$LOG_FILE") -gt "$max_size" ]]; then
|
if [[ -f "$LOG_FILE" ]] && [[ $(get_file_size "$LOG_FILE") -gt "$max_size" ]]; then
|
||||||
mv "$LOG_FILE" "${LOG_FILE}.old" 2> /dev/null || true
|
mv "$LOG_FILE" "${LOG_FILE}.old" 2> /dev/null || true
|
||||||
touch "$LOG_FILE" 2> /dev/null || true
|
ensure_user_file "$LOG_FILE"
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,6 +107,7 @@ log_system_info() {
|
|||||||
export MOLE_SYS_INFO_LOGGED=1
|
export MOLE_SYS_INFO_LOGGED=1
|
||||||
|
|
||||||
# Reset debug log file for this new session
|
# Reset debug log file for this new session
|
||||||
|
ensure_user_file "$DEBUG_LOG_FILE"
|
||||||
: > "$DEBUG_LOG_FILE"
|
: > "$DEBUG_LOG_FILE"
|
||||||
|
|
||||||
# Start block in debug log file
|
# Start block in debug log file
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ save_whitelist_patterns() {
|
|||||||
header_text="# Mole Whitelist - Protected paths won't be deleted\n# Default protections: Playwright browsers, HuggingFace models, Maven repo, Ollama models, Surge Mac, R renv, Finder metadata\n# Add one pattern per line to keep items safe."
|
header_text="# Mole Whitelist - Protected paths won't be deleted\n# Default protections: Playwright browsers, HuggingFace models, Maven repo, Ollama models, Surge Mac, R renv, Finder metadata\n# Add one pattern per line to keep items safe."
|
||||||
fi
|
fi
|
||||||
|
|
||||||
mkdir -p "$(dirname "$config_file")"
|
ensure_user_file "$config_file"
|
||||||
|
|
||||||
echo -e "$header_text" > "$config_file"
|
echo -e "$header_text" > "$config_file"
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,16 @@ flush_dns_cache() {
|
|||||||
|
|
||||||
# Rebuild databases and flush caches
|
# Rebuild databases and flush caches
|
||||||
opt_system_maintenance() {
|
opt_system_maintenance() {
|
||||||
# DISABLED: Causes System Settings corruption - Issue #136
|
local darwin_major
|
||||||
echo -e "${GRAY}⊘${NC} LaunchServices rebuild disabled"
|
darwin_major=$(get_darwin_major)
|
||||||
# run_with_timeout 10 /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user > /dev/null 2>&1 || true
|
|
||||||
|
if [[ "$darwin_major" -ge 24 ]]; then
|
||||||
|
echo -e "${GRAY}⊘${NC} LaunchServices/dyld rebuild skipped on macOS 15+ (Darwin ${darwin_major})"
|
||||||
|
else
|
||||||
|
# DISABLED: Causes System Settings corruption - Issue #136
|
||||||
|
echo -e "${GRAY}⊘${NC} LaunchServices rebuild disabled"
|
||||||
|
# run_with_timeout 10 /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
echo -e "${BLUE}${ICON_ARROW}${NC} Clearing DNS cache..."
|
echo -e "${BLUE}${ICON_ARROW}${NC} Clearing DNS cache..."
|
||||||
if flush_dns_cache; then
|
if flush_dns_cache; then
|
||||||
|
|||||||
7
mole
7
mole
@@ -58,7 +58,8 @@ is_homebrew_install() {
|
|||||||
# Check for updates (non-blocking, always check in background)
|
# Check for updates (non-blocking, always check in background)
|
||||||
check_for_updates() {
|
check_for_updates() {
|
||||||
local msg_cache="$HOME/.cache/mole/update_message"
|
local msg_cache="$HOME/.cache/mole/update_message"
|
||||||
mkdir -p "$(dirname "$msg_cache")" 2> /dev/null
|
ensure_user_dir "$(dirname "$msg_cache")"
|
||||||
|
ensure_user_file "$msg_cache"
|
||||||
|
|
||||||
# Background version check
|
# Background version check
|
||||||
# Always check in background, display result from previous check
|
# Always check in background, display result from previous check
|
||||||
@@ -634,11 +635,11 @@ interactive_main_menu() {
|
|||||||
if [[ -n "$tty_name" ]]; then
|
if [[ -n "$tty_name" ]]; then
|
||||||
local flag_file
|
local flag_file
|
||||||
local cache_dir="$HOME/.cache/mole"
|
local cache_dir="$HOME/.cache/mole"
|
||||||
mkdir -p "$cache_dir" 2> /dev/null
|
ensure_user_dir "$cache_dir"
|
||||||
flag_file="$cache_dir/intro_$(echo "$tty_name" | tr -c '[:alnum:]_' '_')"
|
flag_file="$cache_dir/intro_$(echo "$tty_name" | tr -c '[:alnum:]_' '_')"
|
||||||
if [[ ! -f "$flag_file" ]]; then
|
if [[ ! -f "$flag_file" ]]; then
|
||||||
animate_mole_intro
|
animate_mole_intro
|
||||||
touch "$flag_file" 2> /dev/null || true
|
ensure_user_file "$flag_file"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user