Copy QuecManager beta to non-beta
QM BETA --> regular/non-beta
This commit is contained in:
110
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/cleanup_logs.sh
Executable file
110
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/cleanup_logs.sh
Executable file
@@ -0,0 +1,110 @@
|
||||
#!/bin/sh
|
||||
|
||||
# QuecManager Log Cleanup Script
|
||||
# Periodically clean up old log files to prevent /tmp from filling up
|
||||
|
||||
. /www/cgi-bin/services/quecmanager_logger.sh
|
||||
|
||||
# Configuration
|
||||
MAX_LOG_AGE_DAYS=7 # Delete logs older than 7 days
|
||||
MAX_BACKUP_FILES=2 # Keep maximum 2 backup files (.1, .2)
|
||||
CLEANUP_LOG_SIZE=1000 # Run cleanup if any log exceeds 1MB
|
||||
|
||||
# Function to log cleanup activities
|
||||
log_cleanup() {
|
||||
qm_log_info "system" "log_cleanup" "$1"
|
||||
}
|
||||
|
||||
# Initialize
|
||||
qm_init_logs
|
||||
log_cleanup "Starting log cleanup process"
|
||||
|
||||
# Cleanup function
|
||||
perform_cleanup() {
|
||||
local files_cleaned=0
|
||||
local space_freed=0
|
||||
|
||||
# Clean up old backup files
|
||||
if [ -d "$QM_LOG_BASE" ]; then
|
||||
# Remove backup files older than specified days
|
||||
old_backups=$(find "$QM_LOG_BASE" -name "*.1" -o -name "*.2" -type f -mtime +$MAX_LOG_AGE_DAYS 2>/dev/null)
|
||||
for backup_file in $old_backups; do
|
||||
if [ -f "$backup_file" ]; then
|
||||
file_size=$(du -k "$backup_file" 2>/dev/null | cut -f1)
|
||||
rm -f "$backup_file" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
files_cleaned=$((files_cleaned + 1))
|
||||
space_freed=$((space_freed + ${file_size:-0}))
|
||||
log_cleanup "Removed old backup file: $(basename "$backup_file")"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Force rotation for large log files
|
||||
for category_dir in "$QM_LOG_DAEMONS" "$QM_LOG_SERVICES" "$QM_LOG_SETTINGS" "$QM_LOG_SYSTEM"; do
|
||||
if [ -d "$category_dir" ]; then
|
||||
for logfile in "$category_dir"/*.log; do
|
||||
if [ -f "$logfile" ]; then
|
||||
# Check file size in KB
|
||||
file_size_kb=$(du -k "$logfile" 2>/dev/null | cut -f1)
|
||||
|
||||
if [ "${file_size_kb:-0}" -gt $CLEANUP_LOG_SIZE ]; then
|
||||
log_cleanup "Rotating large log file: $(basename "$logfile") (${file_size_kb}KB)"
|
||||
qm_rotate_log "$logfile"
|
||||
files_cleaned=$((files_cleaned + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
# Additional cleanup: remove empty log files
|
||||
empty_logs=$(find "$QM_LOG_BASE" -name "*.log" -type f -size 0 2>/dev/null)
|
||||
for empty_log in $empty_logs; do
|
||||
rm -f "$empty_log" 2>/dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
files_cleaned=$((files_cleaned + 1))
|
||||
log_cleanup "Removed empty log file: $(basename "$empty_log")"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Log cleanup summary
|
||||
if [ $files_cleaned -gt 0 ]; then
|
||||
log_cleanup "Cleanup completed: $files_cleaned files processed, ${space_freed}KB freed"
|
||||
else
|
||||
log_cleanup "Cleanup completed: no files needed cleaning"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if we should run cleanup based on disk usage
|
||||
check_disk_usage() {
|
||||
# Check /tmp usage (OpenWrt compatible)
|
||||
local tmp_usage=""
|
||||
|
||||
# Try df first (most common)
|
||||
if command -v df >/dev/null 2>&1; then
|
||||
tmp_usage=$(df /tmp 2>/dev/null | awk 'NR==2 {print $5}' | tr -d '%')
|
||||
fi
|
||||
|
||||
# If we got a valid percentage and it's high, force cleanup
|
||||
if [ -n "$tmp_usage" ] && [ "$tmp_usage" -gt 80 ]; then
|
||||
log_cleanup "High /tmp usage detected (${tmp_usage}%), forcing cleanup"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Always run periodic cleanup
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main execution
|
||||
if check_disk_usage; then
|
||||
perform_cleanup
|
||||
else
|
||||
log_cleanup "Disk usage check passed, skipping cleanup"
|
||||
fi
|
||||
|
||||
# Clean up centralized log helper's old logs too
|
||||
qm_cleanup_logs
|
||||
|
||||
log_cleanup "Log cleanup process completed"
|
||||
227
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/interpret_qcainfo.sh
Executable file
227
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/interpret_qcainfo.sh
Executable file
@@ -0,0 +1,227 @@
|
||||
#!/bin/sh
|
||||
# Simple QCAINFO Interpreter
|
||||
|
||||
# Configuration
|
||||
QCAINFO_FILE="/www/signal_graphs/qcainfo.json"
|
||||
INTERPRETED_FILE="/tmp/interpreted_result.json"
|
||||
DEBUG_LOG="/tmp/qcainfo_interpreter.log"
|
||||
INTERVAL=15
|
||||
|
||||
# Simple logging function
|
||||
log() {
|
||||
echo "$(date): $1" >> "$DEBUG_LOG"
|
||||
}
|
||||
|
||||
# Parse QCAINFO output to extract band and EARFCN
|
||||
parse_entry() {
|
||||
local output="$1"
|
||||
local datetime="$2"
|
||||
|
||||
# Extract band and EARFCN using simple grep
|
||||
local band=$(echo "$output" | grep -o 'LTE BAND [0-9]*' | head -1)
|
||||
local earfcn=$(echo "$output" | grep -o '+QCAINFO: "PCC",[0-9]*' | grep -o '[0-9]*' | head -1)
|
||||
local pci=$(echo "$output" | grep -o '+QCAINFO: "PCC",[0-9]*,[0-9]*' | grep -o ',[0-9]*,' | tr -d ',' | head -1)
|
||||
|
||||
# Check for SCC (carrier aggregation)
|
||||
local has_scc=""
|
||||
if echo "$output" | grep -q '+QCAINFO: "SCC"'; then
|
||||
has_scc="yes"
|
||||
else
|
||||
has_scc="no"
|
||||
fi
|
||||
|
||||
echo "${datetime}|${band}|${earfcn}|${pci}|${has_scc}"
|
||||
}
|
||||
|
||||
# Compare two entries and generate interpretation
|
||||
generate_interpretation() {
|
||||
local old_entry="$1"
|
||||
local new_entry="$2"
|
||||
|
||||
# Parse entries
|
||||
local old_datetime=$(echo "$old_entry" | cut -d'|' -f1)
|
||||
local old_band=$(echo "$old_entry" | cut -d'|' -f2)
|
||||
local old_earfcn=$(echo "$old_entry" | cut -d'|' -f3)
|
||||
local old_pci=$(echo "$old_entry" | cut -d'|' -f4)
|
||||
local old_scc=$(echo "$old_entry" | cut -d'|' -f5)
|
||||
|
||||
local new_datetime=$(echo "$new_entry" | cut -d'|' -f1)
|
||||
local new_band=$(echo "$new_entry" | cut -d'|' -f2)
|
||||
local new_earfcn=$(echo "$new_entry" | cut -d'|' -f3)
|
||||
local new_pci=$(echo "$new_entry" | cut -d'|' -f4)
|
||||
local new_scc=$(echo "$new_entry" | cut -d'|' -f5)
|
||||
|
||||
local time_only=$(echo "$new_datetime" | awk '{print $2}' | cut -d: -f1,2)
|
||||
local interpretation=""
|
||||
|
||||
# Check for band change
|
||||
if [ "$old_band" != "$new_band" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary band from ${old_band} to ${new_band}. "
|
||||
fi
|
||||
|
||||
# Check for EARFCN change
|
||||
if [ "$old_earfcn" != "$new_earfcn" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary EARFCN from ${old_earfcn} to ${new_earfcn}. "
|
||||
fi
|
||||
|
||||
# Check for PCI change
|
||||
if [ "$old_pci" != "$new_pci" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem changed primary PCI from ${old_pci} to ${new_pci}. "
|
||||
fi
|
||||
|
||||
# Check for carrier aggregation changes
|
||||
if [ "$old_scc" = "no" ] && [ "$new_scc" = "yes" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem activated carrier aggregation. "
|
||||
elif [ "$old_scc" = "yes" ] && [ "$new_scc" = "no" ]; then
|
||||
interpretation="${interpretation}At ${time_only}, your modem deactivated carrier aggregation. "
|
||||
fi
|
||||
|
||||
echo "$interpretation"
|
||||
}
|
||||
|
||||
# Add interpretation to JSON file without jq
|
||||
add_interpretation() {
|
||||
local interpretation="$1"
|
||||
local datetime="$2"
|
||||
|
||||
if [ -z "$interpretation" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Initialize file if it doesn't exist
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]" > "$INTERPRETED_FILE"
|
||||
fi
|
||||
|
||||
# Read existing content
|
||||
local existing_content=$(cat "$INTERPRETED_FILE")
|
||||
|
||||
# Escape quotes in interpretation
|
||||
local escaped_interpretation=$(echo "$interpretation" | sed 's/"/\\"/g')
|
||||
|
||||
# Create new entry
|
||||
local new_entry="{\"datetime\":\"$datetime\",\"interpretation\":\"$escaped_interpretation\"}"
|
||||
|
||||
# Add to array
|
||||
if [ "$existing_content" = "[]" ]; then
|
||||
echo "[$new_entry]" > "$INTERPRETED_FILE"
|
||||
else
|
||||
# Remove closing bracket, add comma and new entry
|
||||
echo "$existing_content" | sed 's/]$//' > "$INTERPRETED_FILE.tmp"
|
||||
echo ",$new_entry]" >> "$INTERPRETED_FILE.tmp"
|
||||
mv "$INTERPRETED_FILE.tmp" "$INTERPRETED_FILE"
|
||||
fi
|
||||
|
||||
log "Added interpretation: $interpretation"
|
||||
}
|
||||
|
||||
# Main processing function
|
||||
process_qcainfo() {
|
||||
if [ ! -f "$QCAINFO_FILE" ]; then
|
||||
log "QCAINFO file not found: $QCAINFO_FILE"
|
||||
return
|
||||
fi
|
||||
|
||||
# Get total entries
|
||||
local total_entries=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
if [ -z "$total_entries" ] || [ "$total_entries" = "null" ] || [ "$total_entries" -lt 2 ]; then
|
||||
log "Not enough entries to compare (need at least 2, found: $total_entries)"
|
||||
return
|
||||
fi
|
||||
|
||||
log "Found $total_entries entries in QCAINFO file"
|
||||
|
||||
# Get last two entries
|
||||
local last_entry=$(jq -r '.[-1]' "$QCAINFO_FILE" 2>/dev/null)
|
||||
local second_last_entry=$(jq -r '.[-2]' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$last_entry" = "null" ] || [ "$second_last_entry" = "null" ]; then
|
||||
log "Failed to get last two entries"
|
||||
return
|
||||
fi
|
||||
|
||||
# Extract data from JSON entries
|
||||
local last_datetime=$(echo "$last_entry" | jq -r '.datetime')
|
||||
local last_output=$(echo "$last_entry" | jq -r '.output')
|
||||
local second_datetime=$(echo "$second_last_entry" | jq -r '.datetime')
|
||||
local second_output=$(echo "$second_last_entry" | jq -r '.output')
|
||||
|
||||
log "Comparing entries: $second_datetime vs $last_datetime"
|
||||
|
||||
# Parse entries
|
||||
local parsed_second=$(parse_entry "$second_output" "$second_datetime")
|
||||
local parsed_last=$(parse_entry "$last_output" "$last_datetime")
|
||||
|
||||
log "Parsed second: $parsed_second"
|
||||
log "Parsed last: $parsed_last"
|
||||
|
||||
# Generate interpretation
|
||||
local interpretation=$(generate_interpretation "$parsed_second" "$parsed_last")
|
||||
|
||||
if [ -n "$interpretation" ]; then
|
||||
add_interpretation "$interpretation" "$last_datetime"
|
||||
log "Generated interpretation for $last_datetime"
|
||||
else
|
||||
log "No changes detected between $second_datetime and $last_datetime"
|
||||
fi
|
||||
}
|
||||
|
||||
# Initialize
|
||||
log "QCAINFO Interpreter started (PID: $$)"
|
||||
|
||||
# Initialize interpreted results file
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]" > "$INTERPRETED_FILE"
|
||||
log "Initialized interpreted results file"
|
||||
fi
|
||||
|
||||
# Process all existing data once at startup
|
||||
log "Processing all existing QCAINFO data..."
|
||||
if [ -f "$QCAINFO_FILE" ]; then
|
||||
total=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
if [ "$total" -gt 1 ]; then
|
||||
# Process all consecutive pairs
|
||||
i=1
|
||||
while [ $i -lt $total ]; do
|
||||
prev_entry=$(jq -r ".[$((i-1))]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
curr_entry=$(jq -r ".[$i]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$prev_entry" != "null" ] && [ "$curr_entry" != "null" ]; then
|
||||
prev_datetime=$(echo "$prev_entry" | jq -r '.datetime')
|
||||
prev_output=$(echo "$prev_entry" | jq -r '.output')
|
||||
curr_datetime=$(echo "$curr_entry" | jq -r '.datetime')
|
||||
curr_output=$(echo "$curr_entry" | jq -r '.output')
|
||||
|
||||
parsed_prev=$(parse_entry "$prev_output" "$prev_datetime")
|
||||
parsed_curr=$(parse_entry "$curr_output" "$curr_datetime")
|
||||
|
||||
interpretation=$(generate_interpretation "$parsed_prev" "$parsed_curr")
|
||||
|
||||
if [ -n "$interpretation" ]; then
|
||||
add_interpretation "$interpretation" "$curr_datetime"
|
||||
fi
|
||||
fi
|
||||
i=$((i + 1))
|
||||
done
|
||||
log "Completed processing all existing data ($total entries)"
|
||||
else
|
||||
log "Not enough existing data to process"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Remember last processed entry count
|
||||
last_count=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
# Main monitoring loop
|
||||
log "Starting continuous monitoring (checking every $INTERVAL seconds)"
|
||||
while true; do
|
||||
sleep "$INTERVAL"
|
||||
|
||||
current_count=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
if [ "$current_count" -gt "$last_count" ]; then
|
||||
log "New entries detected: $last_count -> $current_count"
|
||||
process_qcainfo
|
||||
last_count="$current_count"
|
||||
fi
|
||||
done
|
||||
@@ -164,7 +164,23 @@ process_all_metrics() {
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# QCAINFO with time stamp
|
||||
local usage_output=$(execute_at_command "AT+QCAINFO")
|
||||
if [ -n "$usage_output" ] && echo "$usage_output" | grep -q "QCAINFO"; then
|
||||
local logfile="$LOGDIR/qcainfo.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$usage_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$metrics_id"
|
||||
logger -t at_queue -p daemon.info "Metrics processing completed"
|
||||
|
||||
201
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/memory_daemon.sh
Executable file
201
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/memory_daemon.sh
Executable file
@@ -0,0 +1,201 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Memory Daemon - Monitors system memory usage and writes to JSON file
|
||||
# This daemon only runs when memory monitoring is enabled via settings
|
||||
|
||||
set -eu
|
||||
|
||||
# Ensure PATH for OpenWrt/BusyBox
|
||||
export PATH="/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
|
||||
|
||||
# Load centralized logging
|
||||
. /www/cgi-bin/services/quecmanager_logger.sh
|
||||
|
||||
# Configuration
|
||||
TMP_DIR="/tmp/quecmanager"
|
||||
OUT_JSON="$TMP_DIR/memory.json"
|
||||
PID_FILE="$TMP_DIR/memory_daemon.pid"
|
||||
CONFIG_FILE="/etc/quecmanager/settings/memory_settings.conf"
|
||||
[ -f "$CONFIG_FILE" ] || CONFIG_FILE="/tmp/quecmanager/settings/memory_settings.conf"
|
||||
DEFAULT_INTERVAL=1
|
||||
SCRIPT_NAME="memory_daemon"
|
||||
|
||||
# Ensure temp directory exists
|
||||
ensure_tmp_dir() {
|
||||
[ -d "$TMP_DIR" ] || mkdir -p "$TMP_DIR" || exit 1
|
||||
}
|
||||
|
||||
# Logging function
|
||||
log() {
|
||||
qm_log_info "daemon" "$SCRIPT_NAME" "$1"
|
||||
}
|
||||
|
||||
# Check if this daemon instance is already running
|
||||
daemon_is_running() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||
if [ -n "${pid:-}" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
# Verify it's actually our daemon by checking process cmdline
|
||||
if [ -r "/proc/$pid/cmdline" ] && grep -q "memory_daemon.sh" "/proc/$pid/cmdline" 2>/dev/null; then
|
||||
return 0
|
||||
else
|
||||
# PID file is stale, remove it
|
||||
rm -f "$PID_FILE" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Write our PID to file
|
||||
write_pid() {
|
||||
echo "$$" > "$PID_FILE"
|
||||
}
|
||||
|
||||
# Cleanup function
|
||||
cleanup() {
|
||||
rm -f "$PID_FILE" 2>/dev/null || true
|
||||
log "Memory daemon stopped"
|
||||
}
|
||||
|
||||
# Create default config if none exists
|
||||
create_default_config() {
|
||||
local primary_config="/etc/quecmanager/settings/memory_settings.conf"
|
||||
local fallback_config="/tmp/quecmanager/settings/memory_settings.conf"
|
||||
|
||||
if [ ! -f "$primary_config" ] && [ ! -f "$fallback_config" ]; then
|
||||
log "No config file found, creating default configuration"
|
||||
|
||||
# Try primary location first
|
||||
if mkdir -p "/etc/quecmanager/settings" 2>/dev/null; then
|
||||
{
|
||||
echo "MEMORY_ENABLED=false"
|
||||
echo "MEMORY_INTERVAL=1"
|
||||
} > "$primary_config" 2>/dev/null && {
|
||||
chmod 644 "$primary_config" 2>/dev/null || true
|
||||
CONFIG_FILE="$primary_config"
|
||||
log "Created default config at $primary_config"
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
|
||||
# Fallback to tmp location
|
||||
mkdir -p "/tmp/quecmanager/settings" 2>/dev/null || true
|
||||
{
|
||||
echo "MEMORY_ENABLED=false"
|
||||
echo "MEMORY_INTERVAL=1"
|
||||
} > "$fallback_config" && {
|
||||
chmod 644 "$fallback_config" 2>/dev/null || true
|
||||
CONFIG_FILE="$fallback_config"
|
||||
log "Created default config at $fallback_config"
|
||||
return 0
|
||||
}
|
||||
|
||||
log "Failed to create default config file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Read configuration from file
|
||||
read_config() {
|
||||
ENABLED="false"
|
||||
INTERVAL="$DEFAULT_INTERVAL"
|
||||
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
MEMORY_ENABLED=$(grep -E "^MEMORY_ENABLED=" "$CONFIG_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2 | tr -d '\r' | tr -d '"')
|
||||
MEMORY_INTERVAL=$(grep -E "^MEMORY_INTERVAL=" "$CONFIG_FILE" 2>/dev/null | tail -n1 | cut -d'=' -f2 | tr -d '\r')
|
||||
|
||||
case "${MEMORY_ENABLED:-}" in
|
||||
true|1|on|yes|enabled) ENABLED="true" ;;
|
||||
*) ENABLED="false" ;;
|
||||
esac
|
||||
|
||||
if echo "${MEMORY_INTERVAL:-}" | grep -qE '^[0-9]+$'; then
|
||||
if [ "$MEMORY_INTERVAL" -ge 1 ] && [ "$MEMORY_INTERVAL" -le 10 ]; then
|
||||
INTERVAL="$MEMORY_INTERVAL"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Write JSON data atomically
|
||||
write_json_atomic() {
|
||||
local json_data="$1"
|
||||
local tmpfile="$(mktemp "$TMP_DIR/memory.XXXXXX" 2>/dev/null || echo "$TMP_DIR/memory.tmp.$$")"
|
||||
|
||||
if [ -n "$tmpfile" ] && printf '%s' "$json_data" > "$tmpfile" 2>/dev/null; then
|
||||
mv "$tmpfile" "$OUT_JSON" 2>/dev/null || {
|
||||
# Fallback if move fails
|
||||
printf '%s' "$json_data" > "$OUT_JSON" 2>/dev/null || true
|
||||
rm -f "$tmpfile" 2>/dev/null || true
|
||||
}
|
||||
else
|
||||
# Direct write fallback
|
||||
printf '%s' "$json_data" > "$OUT_JSON" 2>/dev/null || true
|
||||
rm -f "$tmpfile" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution starts here
|
||||
ensure_tmp_dir
|
||||
log "Starting memory daemon (PID: $$)"
|
||||
|
||||
# Check if already running
|
||||
if daemon_is_running; then
|
||||
log "Memory daemon already running, exiting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create default config if needed
|
||||
create_default_config
|
||||
|
||||
# Set up signal handlers
|
||||
trap cleanup EXIT INT TERM
|
||||
write_pid
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
read_config
|
||||
|
||||
# Exit if disabled
|
||||
if [ "$ENABLED" != "true" ]; then
|
||||
log "Memory monitoring disabled in config, exiting"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get current timestamp
|
||||
ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
|
||||
# Get memory information using /proc/meminfo (most reliable method)
|
||||
if [ -r "/proc/meminfo" ]; then
|
||||
# Extract values from /proc/meminfo (values are in kB)
|
||||
TOTAL_KB=$(grep "^MemTotal:" /proc/meminfo 2>/dev/null | awk '{print $2}' || echo "0")
|
||||
AVAIL_KB=$(grep "^MemAvailable:" /proc/meminfo 2>/dev/null | awk '{print $2}' || echo "0")
|
||||
FREE_KB=$(grep "^MemFree:" /proc/meminfo 2>/dev/null | awk '{print $2}' || echo "0")
|
||||
|
||||
# If MemAvailable is not available (older kernels), estimate it
|
||||
if [ "$AVAIL_KB" = "0" ]; then
|
||||
CACHED_KB=$(grep "^Cached:" /proc/meminfo 2>/dev/null | awk '{print $2}' || echo "0")
|
||||
BUFFERS_KB=$(grep "^Buffers:" /proc/meminfo 2>/dev/null | awk '{print $2}' || echo "0")
|
||||
AVAIL_KB=$((FREE_KB + CACHED_KB + BUFFERS_KB))
|
||||
fi
|
||||
|
||||
# Convert to bytes (multiply by 1024)
|
||||
TOTAL_BYTES=$((TOTAL_KB * 1024))
|
||||
AVAIL_BYTES=$((AVAIL_KB * 1024))
|
||||
USED_BYTES=$((TOTAL_BYTES - AVAIL_BYTES))
|
||||
|
||||
json="{\"total\": $TOTAL_BYTES, \"used\": $USED_BYTES, \"available\": $AVAIL_BYTES, \"timestamp\": \"$ts\"}"
|
||||
else
|
||||
# Fallback if /proc/meminfo is not available
|
||||
log "Warning: /proc/meminfo not readable, using error response"
|
||||
json="{\"total\": 0, \"used\": 0, \"available\": 0, \"timestamp\": \"$ts\", \"error\": \"meminfo_unavailable\"}"
|
||||
fi
|
||||
|
||||
# Write the JSON data
|
||||
write_json_atomic "$json"
|
||||
log "Updated memory data: total=${TOTAL_KB:-0}KB, used=${USED_BYTES:-0}B, available=${AVAIL_KB:-0}KB"
|
||||
|
||||
# Sleep for the configured interval
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
@@ -0,0 +1,372 @@
|
||||
#!/bin/sh
|
||||
# Network Insights Interpreter Service
|
||||
# Monitors qcainfo.json and generates network event interpretations
|
||||
# OpenWrt/BusyBox compatible version
|
||||
|
||||
# Configuration
|
||||
QCAINFO_FILE="/www/signal_graphs/qcainfo.json"
|
||||
INTERPRETED_FILE="/tmp/interpreted_result.json"
|
||||
LAST_ENTRY_FILE="/tmp/last_qcainfo_entry.json"
|
||||
LOCKFILE="/tmp/network_interpreter.lock"
|
||||
MAX_INTERPRETATIONS=50
|
||||
|
||||
# Logging function (OpenWrt compatible)
|
||||
log_message() {
|
||||
if command -v logger >/dev/null 2>&1; then
|
||||
logger -t network_interpreter -p daemon.info "$1"
|
||||
else
|
||||
# Use simpler date format for BusyBox
|
||||
echo "$(date) [network_interpreter] $1" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# Convert datetime to timestamp (OpenWrt/BusyBox compatible)
|
||||
datetime_to_timestamp() {
|
||||
local datetime="$1"
|
||||
# Try GNU date first, fallback to string comparison for BusyBox
|
||||
if date -d "$datetime" +%s >/dev/null 2>&1; then
|
||||
date -d "$datetime" +%s
|
||||
else
|
||||
# For BusyBox, just return the datetime string for string comparison
|
||||
# This is less precise but works for sequential comparison
|
||||
echo "$datetime"
|
||||
fi
|
||||
}
|
||||
|
||||
# Compare timestamps/datetime strings (OpenWrt compatible)
|
||||
is_datetime_newer() {
|
||||
local datetime1="$1"
|
||||
local datetime2="$2"
|
||||
|
||||
local ts1=$(datetime_to_timestamp "$datetime1")
|
||||
local ts2=$(datetime_to_timestamp "$datetime2")
|
||||
|
||||
# If we got numeric timestamps, compare numerically
|
||||
if [ "$ts1" -eq "$ts1" ] 2>/dev/null && [ "$ts2" -eq "$ts2" ] 2>/dev/null; then
|
||||
[ "$ts1" -gt "$ts2" ]
|
||||
else
|
||||
# Fall back to string comparison (works for ISO format)
|
||||
[ "$datetime1" \> "$datetime2" ]
|
||||
fi
|
||||
}
|
||||
|
||||
# Parse QCAINFO output to extract band information
|
||||
parse_qcainfo_bands() {
|
||||
local output="$1"
|
||||
|
||||
# Clean up the output - remove escape sequences and extra characters
|
||||
local clean_output=$(echo "$output" | tr -d '\r' | sed 's/\\r//g; s/\\n/\n/g')
|
||||
|
||||
# Extract all band information from QCAINFO lines
|
||||
echo "$clean_output" | grep "+QCAINFO:" | while IFS= read -r line; do
|
||||
if echo "$line" | grep -q "LTE BAND"; then
|
||||
band=$(echo "$line" | sed -n 's/.*"LTE BAND \([0-9][0-9]*\)".*/B\1/p')
|
||||
if [ -n "$band" ]; then
|
||||
echo "LTE:$band"
|
||||
fi
|
||||
elif echo "$line" | grep -q "NR5G BAND"; then
|
||||
band=$(echo "$line" | sed -n 's/.*"NR5G BAND \([0-9][0-9]*\)".*/N\1/p')
|
||||
if [ -n "$band" ]; then
|
||||
echo "NR5G:$band"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Get network mode from bands
|
||||
get_network_mode() {
|
||||
local bands="$1"
|
||||
local has_lte=false
|
||||
local has_nr5g=false
|
||||
|
||||
if echo "$bands" | grep -q "LTE:"; then
|
||||
has_lte=true
|
||||
fi
|
||||
if echo "$bands" | grep -q "NR5G:"; then
|
||||
has_nr5g=true
|
||||
fi
|
||||
|
||||
if [ "$has_lte" = true ] && [ "$has_nr5g" = true ]; then
|
||||
echo "NSA"
|
||||
elif [ "$has_lte" = true ]; then
|
||||
echo "LTE"
|
||||
elif [ "$has_nr5g" = true ]; then
|
||||
echo "SA"
|
||||
else
|
||||
echo "NO_SIGNAL"
|
||||
fi
|
||||
}
|
||||
|
||||
# Get band list from parsed bands
|
||||
get_band_list() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
echo ""
|
||||
return
|
||||
fi
|
||||
echo "$bands" | sed 's/LTE://g; s/NR5G://g' | sort -u | tr '\n' ',' | sed 's/,$//'
|
||||
}
|
||||
|
||||
# Get carrier count
|
||||
get_carrier_count() {
|
||||
local bands="$1"
|
||||
if [ -z "$bands" ]; then
|
||||
echo "0"
|
||||
return
|
||||
fi
|
||||
echo "$bands" | wc -l
|
||||
}
|
||||
|
||||
# Compare two band configurations and generate interpretation
|
||||
compare_configurations() {
|
||||
local base_output="$1"
|
||||
local new_output="$2"
|
||||
local base_datetime="$3"
|
||||
local new_datetime="$4"
|
||||
|
||||
# Parse both configurations
|
||||
local base_bands=$(parse_qcainfo_bands "$base_output")
|
||||
local new_bands=$(parse_qcainfo_bands "$new_output")
|
||||
|
||||
local base_mode=$(get_network_mode "$base_bands")
|
||||
local new_mode=$(get_network_mode "$new_bands")
|
||||
|
||||
local base_band_list=$(get_band_list "$base_bands")
|
||||
local new_band_list=$(get_band_list "$new_bands")
|
||||
|
||||
local base_carrier_count=$(get_carrier_count "$base_bands")
|
||||
local new_carrier_count=$(get_carrier_count "$new_bands")
|
||||
|
||||
local interpretations=""
|
||||
|
||||
# Check for no signal condition
|
||||
if [ "$new_mode" = "NO_SIGNAL" ]; then
|
||||
if [ "$base_mode" != "NO_SIGNAL" ]; then
|
||||
interpretations="Signal lost - No cellular connection detected"
|
||||
fi
|
||||
# Check if signal was restored
|
||||
elif [ "$base_mode" = "NO_SIGNAL" ] && [ "$new_mode" != "NO_SIGNAL" ]; then
|
||||
interpretations="Signal restored - Connected to $new_mode network"
|
||||
if [ -n "$new_band_list" ]; then
|
||||
interpretations="$interpretations ($new_band_list)"
|
||||
fi
|
||||
# Check if CA was activated immediately upon signal restoration
|
||||
if [ "$new_carrier_count" -gt 1 ]; then
|
||||
interpretations="$interpretations; Carrier Aggregation activated - Now using $new_carrier_count carriers"
|
||||
fi
|
||||
else
|
||||
# Network mode changes
|
||||
if [ "$base_mode" != "$new_mode" ]; then
|
||||
case "$new_mode" in
|
||||
"LTE")
|
||||
if [ "$base_mode" = "NSA" ]; then
|
||||
interpretations="Network mode changed from NSA to LTE-only"
|
||||
elif [ "$base_mode" = "SA" ]; then
|
||||
interpretations="Network mode changed from 5G SA to LTE"
|
||||
fi
|
||||
;;
|
||||
"SA")
|
||||
if [ "$base_mode" = "LTE" ]; then
|
||||
interpretations="Network mode changed from LTE to 5G SA"
|
||||
elif [ "$base_mode" = "NSA" ]; then
|
||||
interpretations="Network mode changed from NSA to 5G SA"
|
||||
fi
|
||||
;;
|
||||
"NSA")
|
||||
if [ "$base_mode" = "LTE" ]; then
|
||||
interpretations="Network mode changed from LTE to NSA"
|
||||
elif [ "$base_mode" = "SA" ]; then
|
||||
interpretations="Network mode changed from 5G SA to NSA"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Band changes
|
||||
if [ "$base_band_list" != "$new_band_list" ]; then
|
||||
if [ -n "$interpretations" ]; then
|
||||
interpretations="$interpretations; "
|
||||
fi
|
||||
|
||||
# Find added and removed bands
|
||||
local added_bands=""
|
||||
local removed_bands=""
|
||||
|
||||
# Check for new bands
|
||||
for band in $(echo "$new_band_list" | tr ',' ' '); do
|
||||
if [ -n "$band" ] && ! echo "$base_band_list" | grep -q "$band"; then
|
||||
if [ -n "$added_bands" ]; then
|
||||
added_bands="$added_bands, $band"
|
||||
else
|
||||
added_bands="$band"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for removed bands
|
||||
for band in $(echo "$base_band_list" | tr ',' ' '); do
|
||||
if [ -n "$band" ] && ! echo "$new_band_list" | grep -q "$band"; then
|
||||
if [ -n "$removed_bands" ]; then
|
||||
removed_bands="$removed_bands, $band"
|
||||
else
|
||||
removed_bands="$band"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$added_bands" ] && [ -n "$removed_bands" ]; then
|
||||
interpretations="${interpretations}Band configuration changed - Added: $added_bands, Removed: $removed_bands"
|
||||
elif [ -n "$added_bands" ]; then
|
||||
interpretations="${interpretations}New bands added: $added_bands"
|
||||
elif [ -n "$removed_bands" ]; then
|
||||
interpretations="${interpretations}Bands removed: $removed_bands"
|
||||
else
|
||||
interpretations="${interpretations}Band sequence changed from ($base_band_list) to ($new_band_list)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Carrier Aggregation changes
|
||||
if [ "$base_carrier_count" != "$new_carrier_count" ]; then
|
||||
if [ -n "$interpretations" ]; then
|
||||
interpretations="$interpretations; "
|
||||
fi
|
||||
|
||||
if [ "$new_carrier_count" -gt 1 ] && [ "$base_carrier_count" -le 1 ]; then
|
||||
interpretations="${interpretations}Carrier Aggregation activated - Now using $new_carrier_count carriers"
|
||||
elif [ "$new_carrier_count" -le 1 ] && [ "$base_carrier_count" -gt 1 ]; then
|
||||
interpretations="${interpretations}Carrier Aggregation deactivated - Single carrier mode"
|
||||
elif [ "$new_carrier_count" -gt "$base_carrier_count" ]; then
|
||||
interpretations="${interpretations}Additional carriers aggregated - Carriers increased from $base_carrier_count to $new_carrier_count"
|
||||
elif [ "$new_carrier_count" -lt "$base_carrier_count" ]; then
|
||||
interpretations="${interpretations}Carriers reduced from $base_carrier_count to $new_carrier_count"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Return interpretation if any changes detected
|
||||
if [ -n "$interpretations" ]; then
|
||||
echo "$interpretations"
|
||||
fi
|
||||
}
|
||||
|
||||
# Add interpretation to JSON file
|
||||
add_interpretation() {
|
||||
local datetime="$1"
|
||||
local interpretation="$2"
|
||||
|
||||
# Initialize file if it doesn't exist
|
||||
if [ ! -f "$INTERPRETED_FILE" ]; then
|
||||
echo "[]" > "$INTERPRETED_FILE"
|
||||
fi
|
||||
|
||||
# Add new interpretation using jq
|
||||
local temp_file="${INTERPRETED_FILE}.tmp.$$"
|
||||
jq --arg dt "$datetime" \
|
||||
--arg interp "$interpretation" \
|
||||
'. + [{"datetime": $dt, "interpretation": $interp}] | .[-'"$MAX_INTERPRETATIONS"':]' \
|
||||
"$INTERPRETED_FILE" > "$temp_file" 2>/dev/null && mv "$temp_file" "$INTERPRETED_FILE"
|
||||
|
||||
chmod 644 "$INTERPRETED_FILE"
|
||||
log_message "Added interpretation: $interpretation"
|
||||
}
|
||||
|
||||
# Process QCAINFO entries and generate interpretations
|
||||
process_qcainfo_data() {
|
||||
if [ ! -f "$QCAINFO_FILE" ]; then
|
||||
log_message "QCAINFO file not found: $QCAINFO_FILE"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Get total number of entries
|
||||
local total_entries=$(jq 'length' "$QCAINFO_FILE" 2>/dev/null || echo "0")
|
||||
|
||||
if [ "$total_entries" -lt 2 ]; then
|
||||
log_message "Not enough entries to compare ($total_entries)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get the last processed entry timestamp
|
||||
local last_processed=""
|
||||
if [ -f "$LAST_ENTRY_FILE" ]; then
|
||||
last_processed=$(cat "$LAST_ENTRY_FILE" 2>/dev/null)
|
||||
fi
|
||||
|
||||
# Process entries sequentially
|
||||
local i=0
|
||||
while [ "$i" -lt $((total_entries - 1)) ]; do
|
||||
local base_entry=$(jq -r ".[$i]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
local next_entry=$(jq -r ".[$(($i + 1))]" "$QCAINFO_FILE" 2>/dev/null)
|
||||
|
||||
local base_datetime=$(echo "$base_entry" | jq -r '.datetime' 2>/dev/null)
|
||||
local next_datetime=$(echo "$next_entry" | jq -r '.datetime' 2>/dev/null)
|
||||
local base_output=$(echo "$base_entry" | jq -r '.output' 2>/dev/null)
|
||||
local next_output=$(echo "$next_entry" | jq -r '.output' 2>/dev/null)
|
||||
|
||||
# Skip if this entry was already processed
|
||||
if [ -n "$last_processed" ] && [ "$next_datetime" = "$last_processed" ]; then
|
||||
i=$((i + 1))
|
||||
continue
|
||||
fi
|
||||
|
||||
# Only process entries after the last processed one
|
||||
if [ -n "$last_processed" ]; then
|
||||
if ! is_datetime_newer "$next_datetime" "$last_processed"; then
|
||||
i=$((i + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Compare configurations and generate interpretation
|
||||
local interpretation=$(compare_configurations "$base_output" "$next_output" "$base_datetime" "$next_datetime")
|
||||
|
||||
if [ -n "$interpretation" ]; then
|
||||
add_interpretation "$next_datetime" "$interpretation"
|
||||
fi
|
||||
|
||||
i=$((i + 1))
|
||||
done
|
||||
|
||||
# Update last processed entry
|
||||
if [ "$total_entries" -gt 0 ]; then
|
||||
local last_datetime=$(jq -r '.[-1].datetime' "$QCAINFO_FILE" 2>/dev/null)
|
||||
echo "$last_datetime" > "$LAST_ENTRY_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
# Check for new entries every 61 seconds
|
||||
monitor_qcainfo() {
|
||||
log_message "Starting network insights interpreter monitoring"
|
||||
|
||||
while true; do
|
||||
# Acquire lock (OpenWrt compatible)
|
||||
if (set -C; echo $$ > "$LOCKFILE") 2>/dev/null; then
|
||||
trap 'rm -f "$LOCKFILE"; exit' INT TERM EXIT
|
||||
|
||||
process_qcainfo_data
|
||||
|
||||
# Release lock
|
||||
rm -f "$LOCKFILE"
|
||||
trap - INT TERM EXIT
|
||||
else
|
||||
log_message "Another instance is running, skipping this cycle"
|
||||
fi
|
||||
|
||||
sleep 61
|
||||
done
|
||||
}
|
||||
|
||||
# Main execution
|
||||
case "${1:-monitor}" in
|
||||
"monitor")
|
||||
monitor_qcainfo
|
||||
;;
|
||||
"process")
|
||||
process_qcainfo_data
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {monitor|process}"
|
||||
echo " monitor - Run continuous monitoring (default)"
|
||||
echo " process - Process current data once"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
137
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/ping_daemon.sh
Executable file
137
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/ping_daemon.sh
Executable file
@@ -0,0 +1,137 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
# Ensure PATH for OpenWrt/BusyBox
|
||||
export PATH="/usr/sbin:/usr/bin:/sbin:/bin:$PATH"
|
||||
|
||||
# Load centralized logging
|
||||
. /www/cgi-bin/services/quecmanager_logger.sh
|
||||
|
||||
TMP_DIR="/tmp/quecmanager"
|
||||
OUT_JSON="$TMP_DIR/ping_latency.json"
|
||||
PID_FILE="$TMP_DIR/ping_daemon.pid"
|
||||
CONFIG_FILE="/etc/quecmanager/settings/ping_settings.conf"
|
||||
[ -f "$CONFIG_FILE" ] || CONFIG_FILE="/tmp/quecmanager/settings/ping_settings.conf"
|
||||
DEFAULT_HOST="8.8.8.8"
|
||||
DEFAULT_INTERVAL=5
|
||||
SCRIPT_NAME="ping_daemon"
|
||||
|
||||
ensure_tmp_dir() { [ -d "$TMP_DIR" ] || mkdir -p "$TMP_DIR" || exit 1; }
|
||||
|
||||
log() {
|
||||
qm_log_info "daemon" "$SCRIPT_NAME" "$1"
|
||||
}
|
||||
|
||||
daemon_is_running() {
|
||||
if [ -f "$PID_FILE" ]; then
|
||||
pid="$(cat "$PID_FILE" 2>/dev/null || true)"
|
||||
if [ -n "${pid:-}" ] && kill -0 "$pid" 2>/dev/null; then
|
||||
# Avoid false positive if PID reused
|
||||
if [ -r "/proc/$pid/cmdline" ] && grep -q "ping_daemon.sh" "/proc/$pid/cmdline" 2>/dev/null; then
|
||||
return 0
|
||||
else
|
||||
rm -f "$PID_FILE" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
write_pid() { echo "$$" > "$PID_FILE"; }
|
||||
|
||||
cleanup() { rm -f "$PID_FILE" 2>/dev/null || true; }
|
||||
|
||||
read_config() {
|
||||
ENABLED="true"; HOST="$DEFAULT_HOST"; INTERVAL="$DEFAULT_INTERVAL"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
PING_ENABLED=$(grep -E "^PING_ENABLED=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2 | tr -d '\r') || true
|
||||
PING_HOST=$(grep -E "^PING_HOST=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2 | tr -d '\r') || true
|
||||
PING_INTERVAL=$(grep -E "^PING_INTERVAL=" "$CONFIG_FILE" | tail -n1 | cut -d'=' -f2 | tr -d '\r') || true
|
||||
case "${PING_ENABLED:-}" in true|1|on|yes|enabled) ENABLED=true ;; *) ENABLED=false ;; esac
|
||||
[ -n "${PING_HOST:-}" ] && HOST="$PING_HOST"
|
||||
if echo "${PING_INTERVAL:-}" | grep -qE '^[0-9]+$'; then
|
||||
if [ "$PING_INTERVAL" -ge 1 ] && [ "$PING_INTERVAL" -le 3600 ]; then
|
||||
INTERVAL="$PING_INTERVAL"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Create default config if none exists
|
||||
create_default_config() {
|
||||
local primary_config="/etc/quecmanager/settings/ping_settings.conf"
|
||||
local fallback_config="/tmp/quecmanager/settings/ping_settings.conf"
|
||||
|
||||
# Check if either config exists
|
||||
if [ -f "$primary_config" ] || [ -f "$fallback_config" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try to create in primary location first
|
||||
if mkdir -p "/etc/quecmanager/settings" 2>/dev/null; then
|
||||
{
|
||||
echo "PING_ENABLED=true"
|
||||
echo "PING_HOST=$DEFAULT_HOST"
|
||||
echo "PING_INTERVAL=$DEFAULT_INTERVAL"
|
||||
} > "$primary_config" 2>/dev/null && {
|
||||
chmod 644 "$primary_config" 2>/dev/null || true
|
||||
CONFIG_FILE="$primary_config"
|
||||
log "Created default config at $primary_config"
|
||||
return 0
|
||||
}
|
||||
fi
|
||||
|
||||
# Fallback to tmp location
|
||||
mkdir -p "/tmp/quecmanager/settings" 2>/dev/null || true
|
||||
{
|
||||
echo "PING_ENABLED=true"
|
||||
echo "PING_HOST=$DEFAULT_HOST"
|
||||
echo "PING_INTERVAL=$DEFAULT_INTERVAL"
|
||||
} > "$fallback_config" && {
|
||||
chmod 644 "$fallback_config" 2>/dev/null || true
|
||||
CONFIG_FILE="$fallback_config"
|
||||
log "Created default config at $fallback_config"
|
||||
return 0
|
||||
}
|
||||
|
||||
log "Failed to create default config file"
|
||||
return 1
|
||||
}
|
||||
|
||||
write_json_atomic() {
|
||||
tmpfile="$(mktemp "$TMP_DIR/ping_latency.XXXXXX" 2>/dev/null || true)"
|
||||
if [ -n "${tmpfile:-}" ] && [ -w "$TMP_DIR" ]; then
|
||||
printf '%s' "$1" > "$tmpfile" 2>/dev/null || true
|
||||
mv -f "$tmpfile" "$OUT_JSON" 2>/dev/null || printf '%s' "$1" > "$OUT_JSON"
|
||||
else
|
||||
printf '%s' "$1" > "$OUT_JSON"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_tmp_dir
|
||||
log "Starting ping daemon"
|
||||
if daemon_is_running; then log "Already running"; exit 0; fi
|
||||
|
||||
# Create default config if none exists
|
||||
create_default_config
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
write_pid
|
||||
|
||||
while true; do
|
||||
read_config
|
||||
if [ "$ENABLED" != "true" ]; then log "Disabled in config"; exit 0; fi
|
||||
ts="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
||||
PING_BIN="$(command -v ping || echo /bin/ping)"
|
||||
output="$("$PING_BIN" -c 1 -w 2 "$HOST" 2>/dev/null || true)"
|
||||
if echo "$output" | grep -q "time="; then
|
||||
latency_ms="$(echo "$output" | grep -o 'time=[0-9.]*' | head -n1 | cut -d'=' -f2 | cut -d'.' -f1)"; [ -z "$latency_ms" ] && latency_ms=0
|
||||
json="{\"timestamp\":\"$ts\",\"host\":\"$HOST\",\"latency\":$latency_ms,\"ok\":true}"
|
||||
else
|
||||
json="{\"timestamp\":\"$ts\",\"host\":\"$HOST\",\"latency\":null,\"ok\":false}"
|
||||
fi
|
||||
write_json_atomic "$json"
|
||||
log "Wrote: $json"
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
119
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/quecmanager_logger.sh
Executable file
119
ipk-source/sdxpinn-quecmanager/root/www/cgi-bin/services/quecmanager_logger.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/sh
|
||||
|
||||
# QuecManager Centralized Logging Helper
|
||||
# OpenWrt/BusyBox compatible logging system
|
||||
# Usage: source this file and use qm_log function
|
||||
|
||||
set -e
|
||||
|
||||
# Base log directory
|
||||
QM_LOG_BASE="/tmp/quecmanager/logs"
|
||||
|
||||
# Log categories
|
||||
QM_LOG_DAEMONS="$QM_LOG_BASE/daemons"
|
||||
QM_LOG_SERVICES="$QM_LOG_BASE/services"
|
||||
QM_LOG_SETTINGS="$QM_LOG_BASE/settings"
|
||||
QM_LOG_SYSTEM="$QM_LOG_BASE/system"
|
||||
|
||||
# Log levels
|
||||
QM_LOG_ERROR="ERROR"
|
||||
QM_LOG_WARN="WARN"
|
||||
QM_LOG_INFO="INFO"
|
||||
QM_LOG_DEBUG="DEBUG"
|
||||
|
||||
# Maximum log file size (in KB) - keep small for OpenWrt
|
||||
QM_LOG_MAX_SIZE=500
|
||||
|
||||
# Initialize log directories
|
||||
qm_init_logs() {
|
||||
mkdir -p "$QM_LOG_DAEMONS" "$QM_LOG_SERVICES" "$QM_LOG_SETTINGS" "$QM_LOG_SYSTEM" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Get log file path based on category and script name
|
||||
qm_get_logfile() {
|
||||
local category="$1"
|
||||
local script_name="$2"
|
||||
|
||||
case "$category" in
|
||||
"daemon"|"daemons")
|
||||
echo "$QM_LOG_DAEMONS/${script_name}.log"
|
||||
;;
|
||||
"service"|"services")
|
||||
echo "$QM_LOG_SERVICES/${script_name}.log"
|
||||
;;
|
||||
"setting"|"settings")
|
||||
echo "$QM_LOG_SETTINGS/${script_name}.log"
|
||||
;;
|
||||
"system")
|
||||
echo "$QM_LOG_SYSTEM/${script_name}.log"
|
||||
;;
|
||||
*)
|
||||
echo "$QM_LOG_SYSTEM/unknown.log"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Simple log rotation - keep it OpenWrt compatible
|
||||
qm_rotate_log() {
|
||||
local logfile="$1"
|
||||
|
||||
if [ -f "$logfile" ]; then
|
||||
# Get file size in KB (use du for BusyBox compatibility)
|
||||
local size_kb=$(du -k "$logfile" 2>/dev/null | cut -f1)
|
||||
|
||||
if [ "${size_kb:-0}" -gt "$QM_LOG_MAX_SIZE" ]; then
|
||||
# Simple rotation: keep last 2 versions
|
||||
[ -f "${logfile}.1" ] && mv "${logfile}.1" "${logfile}.2" 2>/dev/null || true
|
||||
mv "$logfile" "${logfile}.1" 2>/dev/null || true
|
||||
touch "$logfile" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main logging function
|
||||
# Usage: qm_log "category" "script_name" "level" "message"
|
||||
qm_log() {
|
||||
local category="$1"
|
||||
local script_name="$2"
|
||||
local level="$3"
|
||||
local message="$4"
|
||||
|
||||
# Initialize if needed
|
||||
qm_init_logs
|
||||
|
||||
# Get log file path
|
||||
local logfile=$(qm_get_logfile "$category" "$script_name")
|
||||
|
||||
# Rotate if needed
|
||||
qm_rotate_log "$logfile"
|
||||
|
||||
# Create log entry with OpenWrt compatible date
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date)
|
||||
local pid="$$"
|
||||
|
||||
# Write log entry
|
||||
printf '[%s] [%s] [%s] [PID:%s] %s\n' "$timestamp" "$level" "$script_name" "$pid" "$message" >> "$logfile" 2>/dev/null || true
|
||||
}
|
||||
|
||||
# Convenience functions for different log levels
|
||||
qm_log_error() {
|
||||
qm_log "$1" "$2" "$QM_LOG_ERROR" "$3"
|
||||
}
|
||||
|
||||
qm_log_warn() {
|
||||
qm_log "$1" "$2" "$QM_LOG_WARN" "$3"
|
||||
}
|
||||
|
||||
qm_log_info() {
|
||||
qm_log "$1" "$2" "$QM_LOG_INFO" "$3"
|
||||
}
|
||||
|
||||
qm_log_debug() {
|
||||
qm_log "$1" "$2" "$QM_LOG_DEBUG" "$3"
|
||||
}
|
||||
|
||||
# Cleanup old logs (called periodically)
|
||||
qm_cleanup_logs() {
|
||||
# Remove .2 backup files older than 1 day to save space
|
||||
find "$QM_LOG_BASE" -name "*.2" -type f -mtime +1 -delete 2>/dev/null || true
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
# Updated QuecProfiles daemon with enhanced SA/NSA NR5G band management and TTL support
|
||||
# Including profile application functions and fixed comparison logic
|
||||
|
||||
# Load centralized logging
|
||||
. /www/cgi-bin/services/quecmanager_logger.sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
@@ -15,25 +18,49 @@ DEFAULT_CHECK_INTERVAL=60 # Default check interval in seconds
|
||||
COMMAND_TIMEOUT=10 # Default timeout for AT commands in seconds
|
||||
QUEUE_PRIORITY=3 # Medium-high priority (1 is highest for cell scan)
|
||||
MAX_TOKEN_WAIT=15 # Maximum seconds to wait for token acquisition
|
||||
SCRIPT_NAME_LOG="quecprofiles_daemon"
|
||||
|
||||
# Initialize log file
|
||||
echo "$(date) - Starting QuecProfiles daemon with SA/NSA NR5G and TTL support (PID: $$)" >"$DEBUG_LOG"
|
||||
echo "$(date) - Starting QuecProfiles daemon with SA/NSA NR5G and TTL support (PID: $$)" >"$DETAILED_LOG"
|
||||
# Initialize log files and use centralized logging
|
||||
mkdir -p "$(dirname "$DEBUG_LOG")" "$(dirname "$DETAILED_LOG")"
|
||||
touch "$DEBUG_LOG" "$DETAILED_LOG"
|
||||
chmod 644 "$DEBUG_LOG" "$DETAILED_LOG"
|
||||
|
||||
# Function to log messages
|
||||
# Log startup message using centralized logging
|
||||
qm_log_info "service" "$SCRIPT_NAME_LOG" "Starting QuecProfiles daemon with SA/NSA NR5G and TTL support (PID: $$)"
|
||||
|
||||
# Also maintain file logging for compatibility
|
||||
echo "$(date) - Starting QuecProfiles daemon with SA/NSA NR5G and TTL support (PID: $$)" >"$DEBUG_LOG"
|
||||
echo "$(date) - Starting QuecProfiles daemon with SA/NSA NR5G and TTL support (PID: $$)" >"$DETAILED_LOG"
|
||||
|
||||
# Function to log messages - now uses centralized logging
|
||||
log_message() {
|
||||
local message="$1"
|
||||
local level="${2:-info}"
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Log to system log
|
||||
# Use centralized logging
|
||||
case "$level" in
|
||||
"error")
|
||||
qm_log_error "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
"warn")
|
||||
qm_log_warn "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
"debug")
|
||||
qm_log_debug "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
*)
|
||||
qm_log_info "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Also maintain system logging for compatibility
|
||||
logger -t quecprofiles_daemon -p "daemon.$level" "$message"
|
||||
|
||||
# Log to debug file
|
||||
# Log to debug file (maintain existing behavior)
|
||||
echo "[$timestamp] [$level] $message" >>"$DEBUG_LOG"
|
||||
|
||||
# For detailed logs or errors
|
||||
# For detailed logs or errors (maintain existing behavior)
|
||||
if [ "$level" = "error" ] || [ "$level" = "debug" ]; then
|
||||
echo "[$timestamp] [$level] $message" >>"$DETAILED_LOG"
|
||||
fi
|
||||
@@ -607,6 +634,7 @@ apply_profile_settings() {
|
||||
local current_nsa_nr5g_bands="${14}"
|
||||
local current_imei="${15}"
|
||||
local iccid="${16}"
|
||||
local mobile_provider="${17}"
|
||||
|
||||
# Set TTL to 0 (disabled) if not specified
|
||||
ttl="${ttl:-0}"
|
||||
@@ -619,6 +647,7 @@ apply_profile_settings() {
|
||||
log_message "- APN: $apn ($pdp_type)" "info"
|
||||
log_message "- IMEI: $imei" "info"
|
||||
log_message "- TTL: $ttl" "info"
|
||||
log_message "- Mobile Provider: $mobile_provider" "info"
|
||||
|
||||
# Check if any changes are needed using improved comparison
|
||||
local needs_apn_change=0
|
||||
@@ -630,6 +659,7 @@ apply_profile_settings() {
|
||||
local needs_ttl_change=0
|
||||
local changes_needed=0
|
||||
local requires_reboot=0
|
||||
local change_for_reboot=""
|
||||
|
||||
# Use normalized comparison
|
||||
compare_values "$current_apn" "$apn" "apn" && needs_apn_change=1 && changes_needed=1
|
||||
@@ -804,6 +834,7 @@ apply_profile_settings() {
|
||||
if [ $? -eq 0 ]; then
|
||||
changes_made=1
|
||||
requires_reboot=1
|
||||
change_for_reboot="IMEI"
|
||||
log_message "IMEI changed successfully to $imei (device will reboot)" "info"
|
||||
update_track "rebooting" "IMEI changed, device will reboot" "$profile_name" "95"
|
||||
else
|
||||
@@ -813,9 +844,56 @@ apply_profile_settings() {
|
||||
fi
|
||||
fi
|
||||
|
||||
# Apply unique rule setup for Verizon, but also handle "Other" Mobile Providers because of MPDN_rule shenanigans
|
||||
# Probably requires reboot
|
||||
output_check=$(execute_at_command "AT+QMAP=\"mpdn_rule\"")
|
||||
sleep 1 # Short delay to ensure command is processed
|
||||
qmap_rule0=$(echo "$output_check" | grep '+QMAP: "MPDN_rule",0,')
|
||||
qmap_ippt_rule0=$(echo "$qmap_rule0" | cut -d',' -f5)
|
||||
if [ $apply_success -eq 1 ] && [ -n "$mobile_provider" ]; then
|
||||
if [ "$mobile_provider" = "Verizon" ]; then
|
||||
# If Verizon, data call should be set to rule 3, AT+QMAP="mpdn_rule",0,3,0,0,1
|
||||
if echo "$qmap_rule0" | awk -F',' '{exit !($2==0 && $3==3 && $6==1)}'; then
|
||||
log_message "Verizon rule already set correctly, no changes needed" "info"
|
||||
else
|
||||
log_message "Setting Verizon data call mpdn_rule to 3" "info"
|
||||
update_track "applying" "Setting Verizon data call rule to 3" "$profile_name" "100"
|
||||
verizon_cmd="AT+QMAP=\"mpdn_rule\",0,3,0,$qmap_ippt_rule0,1"
|
||||
execute_at_command "$verizon_cmd" 10 "$token_id" >/dev/null
|
||||
sleep 1 # Short delay to ensure command is processed
|
||||
fi
|
||||
elif [ "$mobile_provider" = "Other" ]; then
|
||||
# Check if MPDN_rule 0 is already set to all zeros
|
||||
if echo "$qmap_rule0" | awk -F',' '{exit !($2==0 && $3==0 && $6==0)}'; then
|
||||
log_message "Default rule already set correctly, no changes needed" "info"
|
||||
else
|
||||
log_message "Setting to default mpdn_rule and releasing" "info"
|
||||
update_track "applying" "Setting Default data call mpdn_rule to 0" "$profile_name" "100"
|
||||
def_cmd1="AT+QMAP=\"mpdn_rule\",0"
|
||||
execute_at_command "$def_cmd1" 10 "$token_id"
|
||||
sleep 1 # Short delay to ensure command is processed
|
||||
def_cmd2="AT+QMAP=\"mpdn_rule\",0,1,0,$qmap_ippt_rule0,1"
|
||||
execute_at_command "$def_cmd2" 10 "$token_id"
|
||||
sleep 1 # Short delay to ensure command is processed
|
||||
if [ "$qmap_ippt_rule0" = "0" ]; then
|
||||
log_message "IPPT is disabled for rule, release the MPDN_rule" "info"
|
||||
def_cmd3="AT+QMAP=\"mpdn_rule\",0"
|
||||
execute_at_command "$def_cmd3" 10 "$token_id"
|
||||
sleep 1 # Short delay to ensure command is processed
|
||||
if [ "$(cat /sys/devices/soc0/machine)" = "SDXPINN" ]; then
|
||||
requires_reboot=1
|
||||
change_for_reboot="MPDN_rule"
|
||||
update_track "rebooting" "MPDN_rule released, device will reboot" "$profile_name" "105"
|
||||
fi
|
||||
else
|
||||
log_message "IPPT is enabled for rule0 not releasing MPDN_rule, no reboot needed: IPPT Value $qmap_ippt_rule0" "info"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
# Mark profile as applied if changes were made
|
||||
if [ $changes_made -eq 1 ]; then
|
||||
mark_profile_applied "$iccid" "$profile_name"
|
||||
@@ -824,7 +902,7 @@ apply_profile_settings() {
|
||||
# If IMEI was changed, need to reboot
|
||||
if [ $requires_reboot -eq 1 ]; then
|
||||
log_message "IMEI change requires reboot, scheduling reboot..." "info"
|
||||
update_track "rebooting" "Device is rebooting to apply IMEI change" "$profile_name" "100"
|
||||
update_track "rebooting" "Device is rebooting to apply $change_for_reboot change" "$profile_name" "100"
|
||||
sleep 2
|
||||
reboot &
|
||||
return 0
|
||||
@@ -913,11 +991,12 @@ check_profile() {
|
||||
local pdp_type=$(uci -q get quecprofiles.$profile_index.pdp_type)
|
||||
local imei=$(uci -q get quecprofiles.$profile_index.imei)
|
||||
local ttl=$(uci -q get quecprofiles.$profile_index.ttl)
|
||||
|
||||
local mobile_provider=$(uci -q get quecprofiles.$profile_index.mobile_provider)
|
||||
|
||||
# Check if profile is paused
|
||||
local paused=$(uci -q get quecprofiles.$profile_index.paused)
|
||||
paused="${paused:-0}" # Default to not paused if not set
|
||||
|
||||
|
||||
# Skip applying paused profiles
|
||||
if [ "$paused" = "1" ]; then
|
||||
log_message "Profile '$profile_name' is paused, skipping application" "info"
|
||||
@@ -982,7 +1061,7 @@ check_profile() {
|
||||
# Apply profile settings with the new parameters
|
||||
apply_profile_settings "$profile_name" "$network_type" "$lte_bands" "$sa_nr5g_bands" "$nsa_nr5g_bands" \
|
||||
"$apn" "$pdp_type" "$imei" "$ttl" "$current_apn" "$current_mode" "$current_lte_bands" \
|
||||
"$current_sa_nr5g_bands" "$current_nsa_nr5g_bands" "$current_imei" "$current_iccid"
|
||||
"$current_sa_nr5g_bands" "$current_nsa_nr5g_bands" "$current_imei" "$current_iccid" "$mobile_provider"
|
||||
return $?
|
||||
else
|
||||
log_message "Automatic profile switching is disabled, not applying profile" "info"
|
||||
@@ -1038,7 +1117,7 @@ main() {
|
||||
while [ $sleep_counter -lt $check_interval ]; do
|
||||
sleep 5
|
||||
sleep_counter=$((sleep_counter + 5))
|
||||
|
||||
|
||||
# Check for manual trigger during sleep
|
||||
if [ -f "$CHECK_TRIGGER" ]; then
|
||||
log_message "Manual check triggered during sleep" "info"
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
# QuecWatch Daemon
|
||||
# Monitors cellular connectivity and performs recovery actions
|
||||
|
||||
# Load centralized logging
|
||||
. /www/cgi-bin/services/quecmanager_logger.sh
|
||||
|
||||
# Load UCI configuration functions
|
||||
. /lib/functions.sh
|
||||
|
||||
@@ -17,6 +20,7 @@ RETRY_COUNT_FILE="/tmp/quecwatch_retry_count"
|
||||
UCI_CONFIG="quecmanager"
|
||||
MAX_TOKEN_WAIT=10 # Maximum seconds to wait for token acquisition
|
||||
TOKEN_PRIORITY=15 # Medium priority (between profiles and metrics)
|
||||
SCRIPT_NAME_LOG="quecwatch"
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
@@ -25,17 +29,33 @@ mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE"
|
||||
|
||||
# Function to log messages
|
||||
# Function to log messages - now uses centralized logging
|
||||
log_message() {
|
||||
local level="${2:-info}"
|
||||
local message="$1"
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# Log to file
|
||||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||||
# Use centralized logging
|
||||
case "$level" in
|
||||
"error")
|
||||
qm_log_error "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
"warn")
|
||||
qm_log_warn "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
"debug")
|
||||
qm_log_debug "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
*)
|
||||
qm_log_info "service" "$SCRIPT_NAME_LOG" "$message"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Log to system log
|
||||
# Also maintain system logging for compatibility
|
||||
logger -t quecwatch -p "daemon.$level" "$message"
|
||||
|
||||
# Log to file (maintain existing behavior)
|
||||
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
|
||||
}
|
||||
|
||||
# Function to update status
|
||||
|
||||
Reference in New Issue
Block a user