Merging Beta 2.0.0 Release Candidate
This commit is contained in:
@@ -0,0 +1,672 @@
|
||||
#!/bin/sh
|
||||
# AT Queue Manager for OpenWRT with Preemption Support and Token System
|
||||
# Located in /www/cgi-bin/services/at_queue_manager
|
||||
|
||||
# Constants
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
QUEUE_FILE="$QUEUE_DIR/queue"
|
||||
ACTIVE_FILE="$QUEUE_DIR/active"
|
||||
RESULTS_DIR="$QUEUE_DIR/results"
|
||||
LOCK_DIR="$QUEUE_DIR/lock"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
MAX_TIMEOUT=240
|
||||
CLEANUP_INTERVAL=300 # 5 minutes in seconds
|
||||
RESULTS_MAX_AGE=3600 # 1 hour in seconds
|
||||
POLL_INTERVAL=0.01
|
||||
PREEMPTION_THRESHOLD=2 # 3 seconds threshold for preemption
|
||||
TOKEN_TIMEOUT=30 # seconds before token expires
|
||||
|
||||
# Utility function for JSON escaping
|
||||
escape_json() {
|
||||
printf '%s' "$1" | awk '
|
||||
BEGIN { RS="\n"; ORS="\\n" }
|
||||
{
|
||||
gsub(/\\/, "\\\\")
|
||||
gsub(/"/, "\\\"")
|
||||
gsub(/\r/, "")
|
||||
gsub(/\t/, "\\t")
|
||||
gsub(/\f/, "\\f")
|
||||
gsub(/\b/, "\\b")
|
||||
print
|
||||
}
|
||||
' | sed 's/\\n$//'
|
||||
}
|
||||
|
||||
# Exclusive lock functions
|
||||
acquire_lock() {
|
||||
local timeout=10
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $timeout ]; do
|
||||
if mkdir "$LOCK_DIR" 2>/dev/null; then
|
||||
logger -t at_queue -p daemon.debug "Lock acquired"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.1
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock after $timeout attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
release_lock() {
|
||||
if [ -d "$LOCK_DIR" ]; then
|
||||
rmdir "$LOCK_DIR" 2>/dev/null
|
||||
logger -t at_queue -p daemon.debug "Lock released"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.error "Lock directory doesn't exist"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Ensure required directories exist
|
||||
init_queue_system() {
|
||||
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR"
|
||||
touch "$QUEUE_FILE"
|
||||
chmod 755 "$QUEUE_DIR"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
chmod 755 "$RESULTS_DIR"
|
||||
logger -t at_queue -p daemon.info "Queue system initialized"
|
||||
}
|
||||
|
||||
# Cleanup old results and tracking files
|
||||
cleanup_old_results() {
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Clean up old execution tracking files
|
||||
find "$QUEUE_DIR" -name "pid.*" -type f -mmin +60 -delete 2>/dev/null
|
||||
find "$QUEUE_DIR" -name "*.exit" -type f -mmin +60 -delete 2>/dev/null
|
||||
find "$QUEUE_DIR" -name "start_time.*" -type f -mmin +60 -delete 2>/dev/null
|
||||
logger -t at_queue -p daemon.debug "Cleaned up old tracking files"
|
||||
|
||||
# Use find with -delete and basic timestamp check for OpenWRT
|
||||
find "$RESULTS_DIR" -name "*.json" -type f -mmin +60 -delete 2>/dev/null || {
|
||||
# Fallback method if find fails
|
||||
for file in "$RESULTS_DIR"/*.json; do
|
||||
[ -f "$file" ] || continue
|
||||
local file_time=$(stat -c %Y "$file")
|
||||
if [ $((current_time - file_time)) -gt $RESULTS_MAX_AGE ]; then
|
||||
rm -f "$file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Check for expired token
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local token_time=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
if [ $((current_time - token_time)) -gt $TOKEN_TIMEOUT ]; then
|
||||
local token_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
logger -t at_queue -p daemon.warn "Removing expired token from $token_holder"
|
||||
rm -f "$TOKEN_FILE"
|
||||
fi
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Cleanup: Removed files older than 1 hour"
|
||||
}
|
||||
|
||||
# Generate unique command ID
|
||||
generate_command_id() {
|
||||
echo "$(date +%s)_$(head -c 8 /dev/urandom | hexdump -v -e '1/1 "%02x"')"
|
||||
}
|
||||
|
||||
# Start tracking command execution time
|
||||
start_execution_tracking() {
|
||||
local cmd_id="$1"
|
||||
local pid="$2"
|
||||
local start_time=$(date +%s)
|
||||
|
||||
echo "$start_time" > "$QUEUE_DIR/start_time.$cmd_id"
|
||||
echo "$pid" > "$QUEUE_DIR/pid.$cmd_id"
|
||||
chmod 644 "$QUEUE_DIR/start_time.$cmd_id"
|
||||
chmod 644 "$QUEUE_DIR/pid.$cmd_id"
|
||||
logger -t at_queue -p daemon.debug "Started tracking command $cmd_id (PID: $pid)"
|
||||
}
|
||||
|
||||
# Check if running command should be preempted
|
||||
should_preempt() {
|
||||
local current_cmd_id="$1"
|
||||
local new_priority="$2"
|
||||
|
||||
if [ ! -f "$QUEUE_DIR/start_time.$current_cmd_id" ]; then
|
||||
logger -t at_queue -p daemon.debug "No start time found for $current_cmd_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local start_time=$(cat "$QUEUE_DIR/start_time.$current_cmd_id")
|
||||
local current_time=$(date +%s)
|
||||
local execution_time=$((current_time - start_time))
|
||||
|
||||
# Get current command's priority
|
||||
local current_priority
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
current_priority=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.priority')
|
||||
else
|
||||
logger -t at_queue -p daemon.debug "No active command found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ $execution_time -gt $PREEMPTION_THRESHOLD ] && [ $new_priority -lt $current_priority ]; then
|
||||
logger -t at_queue -p daemon.info "Command $current_cmd_id (priority $current_priority) running for ${execution_time}s is eligible for preemption by priority $new_priority"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.debug "Command $current_cmd_id not eligible for preemption (time: ${execution_time}s, current priority: $current_priority, new priority: $new_priority)"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Handle command preemption
|
||||
preempt_command() {
|
||||
local cmd_id="$1"
|
||||
local pid_file="$QUEUE_DIR/pid.$cmd_id"
|
||||
|
||||
if [ -f "$pid_file" ]; then
|
||||
local pid=$(cat "$pid_file")
|
||||
logger -t at_queue -p daemon.info "Preempting command $cmd_id (PID: $pid)"
|
||||
|
||||
# Send SIGTERM first
|
||||
kill -TERM $pid 2>/dev/null
|
||||
|
||||
# Brief wait for graceful termination
|
||||
sleep 0.1
|
||||
|
||||
# Force kill if still running
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
kill -KILL $pid 2>/dev/null
|
||||
logger -t at_queue -p daemon.warn "Forced termination of command $cmd_id"
|
||||
fi
|
||||
|
||||
# Record preemption result
|
||||
write_preemption_result "$cmd_id"
|
||||
|
||||
# Cleanup command files
|
||||
rm -f "$pid_file" "$QUEUE_DIR/start_time.$cmd_id" "$QUEUE_DIR/$cmd_id.exit"
|
||||
[ -f "$ACTIVE_FILE" ] && rm -f "$ACTIVE_FILE"
|
||||
|
||||
logger -t at_queue -p daemon.info "Command $cmd_id preemption complete"
|
||||
return 0
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.warn "No PID file found for command $cmd_id"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Record result for preempted command
|
||||
write_preemption_result() {
|
||||
local cmd_id="$1"
|
||||
local end_time=$(date +%s%3N)
|
||||
local start_time
|
||||
|
||||
if [ -f "$QUEUE_DIR/start_time.$cmd_id" ]; then
|
||||
start_time=$(cat "$QUEUE_DIR/start_time.$cmd_id")000
|
||||
else
|
||||
start_time=$end_time
|
||||
fi
|
||||
|
||||
local duration=$((end_time - start_time))
|
||||
local command_text=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.command')
|
||||
|
||||
local response=$(cat << EOF
|
||||
{
|
||||
"command": {
|
||||
"id": "$cmd_id",
|
||||
"text": "$(escape_json "$command_text")",
|
||||
"timestamp": "$(date -Iseconds)"
|
||||
},
|
||||
"response": {
|
||||
"status": "preempted",
|
||||
"raw_output": "Command preempted by higher priority task",
|
||||
"completion_time": "$end_time",
|
||||
"duration_ms": $duration
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
|
||||
chmod 644 "$RESULTS_DIR/$cmd_id.json"
|
||||
logger -t at_queue -p daemon.info "Recorded preemption result for command $cmd_id (duration: ${duration}ms)"
|
||||
}
|
||||
|
||||
# Request a token for direct sms_tool execution
|
||||
request_token() {
|
||||
local requestor_id="$1"
|
||||
local priority="${2:-10}"
|
||||
local timeout="${3:-10}"
|
||||
|
||||
# Acquire lock first
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for token request"
|
||||
echo "{\"error\":\"Could not acquire lock\",\"status\":\"denied\"}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if token file exists (someone else has the token)
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority')
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> TOKEN_TIMEOUT seconds old)
|
||||
if [ $((current_time - timestamp)) -gt $TOKEN_TIMEOUT ]; then
|
||||
logger -t at_queue -p daemon.warn "Found expired token from $current_holder, releasing"
|
||||
rm -f "$TOKEN_FILE"
|
||||
# Check for priority preemption
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
logger -t at_queue -p daemon.info "Preempting token from $current_holder (priority: $current_priority) for $requestor_id (priority: $priority)"
|
||||
rm -f "$TOKEN_FILE"
|
||||
else
|
||||
# Token in use and cannot be preempted
|
||||
release_lock
|
||||
echo "{\"status\":\"denied\",\"holder\":\"$current_holder\",\"priority\":$current_priority}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Also check if there's an active command from the queue
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
local active_id=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.id')
|
||||
local active_priority=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.priority')
|
||||
|
||||
# Only preempt if priority is higher
|
||||
if [ $priority -ge $active_priority ]; then
|
||||
release_lock
|
||||
echo "{\"status\":\"denied\",\"holder\":\"$active_id\",\"priority\":$active_priority}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Direct execution with higher priority than active queue command"
|
||||
fi
|
||||
|
||||
# Grant token
|
||||
local token_data="{\"id\":\"$requestor_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}"
|
||||
echo "$token_data" > "$TOKEN_FILE"
|
||||
chmod 644 "$TOKEN_FILE"
|
||||
|
||||
release_lock
|
||||
echo "{\"status\":\"granted\",\"id\":\"$requestor_id\",\"timeout\":$timeout}"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Release a previously acquired token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for token release"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE"
|
||||
logger -t at_queue -p daemon.debug "Token released by $requestor_id"
|
||||
release_lock
|
||||
echo "{\"status\":\"released\"}"
|
||||
return 0
|
||||
else
|
||||
logger -t at_queue -p daemon.warn "Token release attempted by $requestor_id but held by $current_holder"
|
||||
fi
|
||||
else
|
||||
logger -t at_queue -p daemon.warn "Token release attempted but no token exists"
|
||||
fi
|
||||
|
||||
release_lock
|
||||
echo "{\"status\":\"not_found\"}"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Add command to queue with preemption support
|
||||
enqueue_command() {
|
||||
local cmd="$1"
|
||||
local priority="${2:-10}"
|
||||
local cmd_id=$(generate_command_id)
|
||||
local timestamp=$(date -Iseconds)
|
||||
|
||||
# Ensure queue directory exists
|
||||
[ ! -d "$QUEUE_DIR" ] && init_queue_system
|
||||
|
||||
logger -t at_queue -p daemon.info "Enqueuing command: $cmd (priority: $priority, id: $cmd_id)"
|
||||
|
||||
# Acquire lock for queue modification
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for enqueuing command"
|
||||
echo "{\"error\":\"Queue lock acquisition failed\",\"command\":\"$cmd\"}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check for active command that can be preempted
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
local active_cmd_id=$(cat "$ACTIVE_FILE" | jsonfilter -e '@.id')
|
||||
if should_preempt "$active_cmd_id" "$priority"; then
|
||||
preempt_command "$active_cmd_id"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create command entry
|
||||
local entry="{\"id\":\"$cmd_id\",\"command\":\"$(escape_json "$cmd")\",\"priority\":$priority,\"timestamp\":\"$timestamp\"}"
|
||||
|
||||
if [ "$priority" = "1" ]; then
|
||||
# High priority - prepend to queue
|
||||
local temp_file=$(mktemp)
|
||||
echo "$entry" > "$temp_file"
|
||||
cat "$QUEUE_FILE" >> "$temp_file"
|
||||
mv "$temp_file" "$QUEUE_FILE"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
logger -t at_queue -p daemon.info "Added high priority command to front of queue"
|
||||
else
|
||||
# Normal priority - append to queue
|
||||
echo "$entry" >> "$QUEUE_FILE"
|
||||
logger -t at_queue -p daemon.info "Added normal priority command to end of queue"
|
||||
fi
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
|
||||
echo "{\"command_id\":\"$cmd_id\",\"status\":\"queued\"}"
|
||||
}
|
||||
|
||||
# Get next command from queue
|
||||
dequeue_command() {
|
||||
if [ ! -s "$QUEUE_FILE" ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Acquire lock
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for dequeuing command"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local cmd_entry=$(head -n 1 "$QUEUE_FILE")
|
||||
local temp_file=$(mktemp)
|
||||
tail -n +2 "$QUEUE_FILE" > "$temp_file"
|
||||
mv "$temp_file" "$QUEUE_FILE"
|
||||
chmod 644 "$QUEUE_FILE"
|
||||
|
||||
echo "$cmd_entry" > "$ACTIVE_FILE"
|
||||
chmod 644 "$ACTIVE_FILE"
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
|
||||
logger -t at_queue -p daemon.debug "Dequeued command: $(echo "$cmd_entry" | jsonfilter -e '@.command')"
|
||||
echo "$cmd_entry"
|
||||
}
|
||||
|
||||
# Clean and format AT command output
|
||||
clean_output() {
|
||||
local output="$1"
|
||||
|
||||
# First format AT command responses for readability
|
||||
output=$(echo "$output" | sed -E '
|
||||
# Add newline after AT commands
|
||||
s/(AT\+[A-Z0-9]+[^ ]*) +/\1\n/g
|
||||
# Add newline before +RESPONSE lines
|
||||
s/ +(\+[A-Z0-9]+:)/\n\1/g
|
||||
# Add newline before OK/ERROR
|
||||
s/ +(OK|ERROR)$/\n\1/g
|
||||
')
|
||||
|
||||
# Then escape the formatted output for JSON
|
||||
output=$(escape_json "$output")
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
# Execute AT command with optimized timeout handling
|
||||
execute_with_timeout() {
|
||||
local command="$1"
|
||||
local timeout="$2"
|
||||
local cmd_id="$3"
|
||||
local output_file=$(mktemp)
|
||||
|
||||
# Start command in background with immediate output
|
||||
(sms_tool -D at "$command" > "$output_file" 2>&1; echo $? > "$QUEUE_DIR/$cmd_id.exit") &
|
||||
local pid=$!
|
||||
|
||||
# Start execution tracking
|
||||
start_execution_tracking "$cmd_id" "$pid"
|
||||
|
||||
logger -t at_queue -p daemon.debug "Started command execution: $command (PID: $pid)"
|
||||
|
||||
# Wait for completion with shorter polling interval
|
||||
local start_time=$(date +%s)
|
||||
local elapsed=0
|
||||
|
||||
while [ $elapsed -lt "$timeout" ]; do
|
||||
if [ -f "$QUEUE_DIR/$cmd_id.exit" ]; then
|
||||
local exit_code=$(cat "$QUEUE_DIR/$cmd_id.exit")
|
||||
local output=$(cat "$output_file")
|
||||
|
||||
# Cleanup
|
||||
rm -f "$QUEUE_DIR/pid.$cmd_id" "$QUEUE_DIR/$cmd_id.exit" "$output_file" "$QUEUE_DIR/start_time.$cmd_id"
|
||||
|
||||
logger -t at_queue -p daemon.debug "Command completed with exit code $exit_code"
|
||||
echo "$output"
|
||||
return $exit_code
|
||||
fi
|
||||
|
||||
elapsed=$(($(date +%s) - start_time))
|
||||
sleep $POLL_INTERVAL
|
||||
done
|
||||
|
||||
# Handle timeout
|
||||
if [ -f "$QUEUE_DIR/pid.$cmd_id" ]; then
|
||||
local pid=$(cat "$QUEUE_DIR/pid.$cmd_id")
|
||||
kill $pid 2>/dev/null
|
||||
sleep 0.1
|
||||
# Force kill if still running
|
||||
if kill -0 $pid 2>/dev/null; then
|
||||
kill -KILL $pid 2>/dev/null
|
||||
fi
|
||||
|
||||
local partial_output=$(cat "$output_file" 2>/dev/null || echo "")
|
||||
|
||||
# Cleanup
|
||||
rm -f "$QUEUE_DIR/pid.$cmd_id" "$QUEUE_DIR/$cmd_id.exit" "$output_file" "$QUEUE_DIR/start_time.$cmd_id"
|
||||
|
||||
logger -t at_queue -p daemon.warn "Command timed out after $timeout seconds"
|
||||
echo "${partial_output:-Command timed out after $timeout seconds}"
|
||||
fi
|
||||
|
||||
return 124
|
||||
}
|
||||
|
||||
# Execute AT command and handle response
|
||||
execute_command() {
|
||||
local cmd_entry="$1"
|
||||
local cmd_id=$(echo "$cmd_entry" | jsonfilter -e '@.id')
|
||||
local cmd_text=$(echo "$cmd_entry" | jsonfilter -e '@.command')
|
||||
local priority=$(echo "$cmd_entry" | jsonfilter -e '@.priority')
|
||||
|
||||
local start_time=$(date +%s%3N)
|
||||
|
||||
logger -t at_queue -p daemon.info "Executing command $cmd_id: $cmd_text (priority: $priority)"
|
||||
|
||||
# Execute command with timeout
|
||||
local result=$(execute_with_timeout "$cmd_text" $MAX_TIMEOUT "$cmd_id")
|
||||
local exit_code=$?
|
||||
local end_time=$(date +%s%3N)
|
||||
local duration=$((end_time - start_time))
|
||||
|
||||
# Determine status and log level
|
||||
local status="error"
|
||||
local log_level="error"
|
||||
|
||||
if [ $exit_code -eq 124 ]; then
|
||||
status="timeout"
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id timed out after ${duration}ms"
|
||||
elif echo "$result" | grep -q "OK"; then
|
||||
status="success"
|
||||
log_level="info"
|
||||
logger -t at_queue -p daemon.info "Command $cmd_id completed successfully in ${duration}ms"
|
||||
elif echo "$result" | grep -q "CME ERROR"; then
|
||||
status="cme_error"
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id failed with CME ERROR in ${duration}ms"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Command $cmd_id failed with general error in ${duration}ms"
|
||||
fi
|
||||
|
||||
# Clean and escape the output
|
||||
local clean_result=$(clean_output "$result")
|
||||
|
||||
# Create JSON response
|
||||
local response=$(cat << EOF
|
||||
{
|
||||
"command": {
|
||||
"id": "$cmd_id",
|
||||
"text": "$(escape_json "$cmd_text")",
|
||||
"timestamp": "$(date -Iseconds)"
|
||||
},
|
||||
"response": {
|
||||
"status": "$status",
|
||||
"raw_output": "$clean_result",
|
||||
"completion_time": "$end_time",
|
||||
"duration_ms": $duration
|
||||
}
|
||||
}
|
||||
EOF
|
||||
)
|
||||
|
||||
# Acquire lock for writing result
|
||||
if ! acquire_lock; then
|
||||
logger -t at_queue -p daemon.error "Failed to acquire lock for writing result"
|
||||
else
|
||||
# Save response
|
||||
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
|
||||
chmod 644 "$RESULTS_DIR/$cmd_id.json"
|
||||
|
||||
# Clean up active file
|
||||
rm -f "$ACTIVE_FILE"
|
||||
|
||||
# Release lock
|
||||
release_lock
|
||||
fi
|
||||
|
||||
echo "$response"
|
||||
}
|
||||
|
||||
# Main queue processing function
|
||||
process_queue() {
|
||||
init_queue_system
|
||||
local last_cleanup=$(date +%s)
|
||||
local last_log=$(date +%s) # Add a timestamp for less frequent logging
|
||||
|
||||
# Make sure the lock directory doesn't exist at startup
|
||||
[ -d "$LOCK_DIR" ] && rmdir "$LOCK_DIR" 2>/dev/null
|
||||
|
||||
logger -t at_queue -p daemon.info "Started queue processing daemon"
|
||||
|
||||
while true; do
|
||||
# Quick cleanup check
|
||||
local current_time=$(date +%s)
|
||||
if [ $((current_time - last_cleanup)) -ge $CLEANUP_INTERVAL ]; then
|
||||
cleanup_old_results
|
||||
last_cleanup=$current_time
|
||||
fi
|
||||
|
||||
# Skip processing if token is granted to someone
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local token_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id')
|
||||
local token_time=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp')
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token
|
||||
if [ $((current_time - token_time)) -gt $TOKEN_TIMEOUT ]; then
|
||||
logger -t at_queue -p daemon.warn "Removing expired token from $token_holder"
|
||||
rm -f "$TOKEN_FILE"
|
||||
else
|
||||
# Log pause status only every 5 seconds to reduce log spam
|
||||
if [ $((current_time - last_log)) -ge 5 ]; then
|
||||
logger -t at_queue -p daemon.debug "Queue processing paused, token held by $token_holder"
|
||||
last_log=$current_time
|
||||
fi
|
||||
sleep $POLL_INTERVAL
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Process queue if not empty and no active command
|
||||
if [ -s "$QUEUE_FILE" ] && [ ! -f "$ACTIVE_FILE" ]; then
|
||||
local cmd_entry=$(dequeue_command)
|
||||
if [ -n "$cmd_entry" ]; then
|
||||
execute_command "$cmd_entry"
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep $POLL_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# CGI command handling
|
||||
if [ "${SCRIPT_NAME}" != "" ]; then
|
||||
# Output headers
|
||||
if [ "$HTTP_HEADERS" != "0" ]; then
|
||||
echo "Content-Type: application/json"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Parse query string for CGI mode
|
||||
eval $(echo "$QUERY_STRING" | sed 's/&/;/g')
|
||||
|
||||
case "$action" in
|
||||
"enqueue")
|
||||
if [ -n "$command" ]; then
|
||||
logger -t at_queue -p daemon.info "CGI: Received enqueue request for command: $command"
|
||||
enqueue_command "$command" "$priority"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "CGI: Empty command received"
|
||||
echo "{\"error\":\"No command specified\"}"
|
||||
fi
|
||||
;;
|
||||
"status")
|
||||
if [ -f "$ACTIVE_FILE" ]; then
|
||||
logger -t at_queue -p daemon.debug "CGI: Status request - queue active"
|
||||
cat "$ACTIVE_FILE"
|
||||
else
|
||||
logger -t at_queue -p daemon.debug "CGI: Status request - queue idle"
|
||||
echo "{\"status\":\"idle\"}"
|
||||
fi
|
||||
;;
|
||||
"request_token")
|
||||
if [ -n "$id" ]; then
|
||||
logger -t at_queue -p daemon.info "Token request from $id (priority: ${priority:-10})"
|
||||
request_token "$id" "${priority:-10}" "${timeout:-10}"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Token request missing ID"
|
||||
echo "{\"error\":\"No requestor ID specified\",\"status\":\"denied\"}"
|
||||
fi
|
||||
;;
|
||||
"release_token")
|
||||
if [ -n "$id" ]; then
|
||||
logger -t at_queue -p daemon.info "Token release from $id"
|
||||
release_token "$id"
|
||||
else
|
||||
logger -t at_queue -p daemon.error "Token release missing ID"
|
||||
echo "{\"error\":\"No requestor ID specified\",\"status\":\"denied\"}"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
logger -t at_queue -p daemon.error "CGI: Invalid action received: $action"
|
||||
echo "{\"error\":\"Invalid action\"}"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# CLI command handling
|
||||
if [ "$1" = "enqueue" ] && [ -n "$2" ]; then
|
||||
enqueue_command "$2" "${3:-10}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# If not run as CGI, start queue processing
|
||||
if [ "${SCRIPT_NAME}" = "" ] && [ -z "$1" ]; then
|
||||
process_queue
|
||||
fi
|
||||
@@ -1,169 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
RESULT_FILE="/tmp/at_results.json"
|
||||
LOG_FILE="/var/log/at_commands.log"
|
||||
# Define all lock keywords
|
||||
FETCH_LOCK_KEYWORD="FETCH_DATA_LOCK"
|
||||
SIGNAL_LOCK_KEYWORD="SIGNAL_METRICS_LOCK"
|
||||
# Combine keywords for pattern matching
|
||||
ALL_LOCK_KEYWORDS="${FETCH_LOCK_KEYWORD}\\|${SIGNAL_LOCK_KEYWORD}"
|
||||
|
||||
# Create or clear necessary files
|
||||
touch "${QUEUE_FILE}"
|
||||
[ ! -f "${RESULT_FILE}" ] && echo '[]' > "${RESULT_FILE}"
|
||||
|
||||
# Log messages to the log file
|
||||
log_message() {
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
|
||||
}
|
||||
|
||||
# Escape special characters for JSON
|
||||
escape_json() {
|
||||
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g'
|
||||
}
|
||||
|
||||
# Function to check if any lock is present
|
||||
is_system_locked() {
|
||||
grep -q "\"command\":\"\\(${ALL_LOCK_KEYWORDS}\\)\"" "${QUEUE_FILE}"
|
||||
return $?
|
||||
}
|
||||
|
||||
# Process a single command
|
||||
process_command() {
|
||||
local command="$1"
|
||||
local timestamp="$2"
|
||||
local cmd_id="$3"
|
||||
|
||||
log_message "Processing command: ${command} (ID: ${cmd_id})"
|
||||
|
||||
# Check if sms_tool exists and is executable
|
||||
if ! which sms_tool >/dev/null 2>&1; then
|
||||
log_message "Error: sms_tool not found in PATH"
|
||||
result="sms_tool not found"
|
||||
exit_code=1
|
||||
else
|
||||
# Execute the AT command using sms_tool
|
||||
result=$(sms_tool at "${command}" 2>&1)
|
||||
exit_code=$?
|
||||
log_message "Command output: ${result}"
|
||||
log_message "Exit code: ${exit_code}"
|
||||
fi
|
||||
|
||||
# Escape the command and result for JSON
|
||||
escaped_command=$(escape_json "${command}")
|
||||
escaped_result=$(echo "${result}" | sed 's/"/\\"/g' | sed ':a;N;$!ba;s/\n/\\n/g' | tr -d '\r')
|
||||
|
||||
# Generate the result JSON
|
||||
if [ ${exit_code} -eq 0 ]; then
|
||||
log_message "Command successful: ${command}"
|
||||
RESULT_JSON=$(printf '{"id":"%s","status":"success","command":"%s","response":"%s","queued_at":"%s","executed_at":"%s"}' \
|
||||
"${cmd_id}" "${escaped_command}" "${escaped_result}" "${timestamp}" "$(date '+%H:%M:%S')")
|
||||
else
|
||||
log_message "Command failed: ${command}"
|
||||
RESULT_JSON=$(printf '{"id":"%s","status":"error","command":"%s","error":"%s","queued_at":"%s","executed_at":"%s"}' \
|
||||
"${cmd_id}" "${escaped_command}" "${escaped_result}" "${timestamp}" "$(date '+%H:%M:%S')")
|
||||
fi
|
||||
|
||||
# Update the results file safely
|
||||
if ! current_results=$(cat "${RESULT_FILE}" 2>/dev/null); then
|
||||
log_message "Error reading results file, initializing new one"
|
||||
echo '[]' > "${RESULT_FILE}"
|
||||
current_results='[]'
|
||||
fi
|
||||
|
||||
# Append the result JSON to the results file
|
||||
if ! echo "${current_results}" | jq --argjson new "${RESULT_JSON}" '. + [$new]' > "${RESULT_FILE}.tmp"; then
|
||||
log_message "Error updating results file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
mv "${RESULT_FILE}.tmp" "${RESULT_FILE}"
|
||||
log_message "Successfully updated results file"
|
||||
return ${exit_code}
|
||||
}
|
||||
|
||||
# Check if an entry is a lock entry
|
||||
is_lock_entry() {
|
||||
local line="$1"
|
||||
echo "${line}" | grep -q "\"command\":\"\\(${ALL_LOCK_KEYWORDS}\\)\""
|
||||
return $?
|
||||
}
|
||||
|
||||
# Process pending commands in the queue
|
||||
process_pending_commands() {
|
||||
while true; do
|
||||
# Check if any lock is present
|
||||
if is_system_locked; then
|
||||
local lock_type=$(grep -o "\"command\":\"[^\"]*\"" "${QUEUE_FILE}" | grep "${ALL_LOCK_KEYWORDS}")
|
||||
log_message "System is locked: ${lock_type}, waiting..."
|
||||
sleep 0.5
|
||||
continue
|
||||
fi
|
||||
|
||||
# Read the first line from the queue
|
||||
line=$(head -n 1 "${QUEUE_FILE}" 2>/dev/null)
|
||||
|
||||
if [ -n "${line}" ]; then
|
||||
log_message "Processing queue entry: ${line}"
|
||||
|
||||
# Skip processing if it's a lock entry
|
||||
if is_lock_entry "${line}"; then
|
||||
log_message "Found lock entry, skipping"
|
||||
sed -i '1d' "${QUEUE_FILE}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Validate JSON before processing
|
||||
if ! echo "${line}" | jq empty 2>/dev/null; then
|
||||
log_message "Invalid JSON in queue, skipping line"
|
||||
sed -i '1d' "${QUEUE_FILE}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Parse the command, timestamp, and ID from the JSON entry
|
||||
command=$(echo "${line}" | jq -r '.command // empty')
|
||||
timestamp=$(echo "${line}" | jq -r '.timestamp // empty')
|
||||
cmd_id=$(echo "${line}" | jq -r '.id // empty')
|
||||
|
||||
if [ -z "${command}" ] || [ -z "${timestamp}" ] || [ -z "${cmd_id}" ]; then
|
||||
log_message "Missing required fields in JSON, skipping"
|
||||
sed -i '1d' "${QUEUE_FILE}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Process the command
|
||||
process_command "${command}" "${timestamp}" "${cmd_id}"
|
||||
|
||||
# Remove the processed line from the queue
|
||||
sed -i '1d' "${QUEUE_FILE}"
|
||||
|
||||
# Add a small delay between commands
|
||||
sleep 0.1
|
||||
else
|
||||
# No commands in queue, wait briefly before checking again
|
||||
sleep 0.5
|
||||
break
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Main queue monitoring loop
|
||||
process_queue() {
|
||||
log_message "Starting queue processor with multiple lock support"
|
||||
|
||||
while true; do
|
||||
# Process any pending commands
|
||||
process_pending_commands
|
||||
|
||||
# Wait for changes to the queue file
|
||||
inotifywait -q -e modify,create "${QUEUE_FILE}" >/dev/null 2>&1
|
||||
|
||||
# Small delay to allow file to stabilize
|
||||
sleep 0.1
|
||||
done
|
||||
}
|
||||
|
||||
# Start processing the queue
|
||||
log_message "Queue processor started with file monitoring and multiple lock support"
|
||||
process_queue
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Script path
|
||||
SCRIPT_PATH=$(readlink -f "$0")
|
||||
|
||||
# Check if files exist and are writable
|
||||
missing_files=0
|
||||
|
||||
# Check apn_profiles.log
|
||||
if [ ! -f "/tmp/apn_profiles.log" ]; then
|
||||
logger -t log_cleanup "File not found: /tmp/apn_profiles.log"
|
||||
missing_files=1
|
||||
elif [ ! -w "/tmp/apn_profiles.log" ]; then
|
||||
logger -t log_cleanup "No write permission for file: /tmp/apn_profiles.log"
|
||||
missing_files=1
|
||||
fi
|
||||
|
||||
# Check imei_profiles.log
|
||||
if [ ! -f "/tmp/imei_profiles.log" ]; then
|
||||
logger -t log_cleanup "File not found: /tmp/imei_profiles.log"
|
||||
missing_files=1
|
||||
elif [ ! -w "/tmp/imei_profiles.log" ]; then
|
||||
logger -t log_cleanup "No write permission for file: /tmp/imei_profiles.log"
|
||||
missing_files=1
|
||||
fi
|
||||
|
||||
# Check at_commands.log
|
||||
if [ ! -f "/var/log/at_commands.log" ]; then
|
||||
logger -t log_cleanup "File not found: /var/log/at_commands.log"
|
||||
missing_files=1
|
||||
elif [ ! -w "/var/log/at_commands.log" ]; then
|
||||
logger -t log_cleanup "No write permission for file: /var/log/at_commands.log"
|
||||
missing_files=1
|
||||
fi
|
||||
|
||||
# Exit if any files are missing or not writable
|
||||
if [ $missing_files -eq 1 ]; then
|
||||
logger -t log_cleanup "Exiting due to missing or unwritable files"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fix the spacing in the cron line to ensure exactly 5 fields
|
||||
CRON_LINE="0 0 * * * $SCRIPT_PATH"
|
||||
|
||||
# Install crontab while preserving other entries
|
||||
if ! crontab -l | grep -Fq "$SCRIPT_PATH"; then
|
||||
# Create temporary file
|
||||
TEMP_CRON=$(mktemp)
|
||||
|
||||
# Get existing crontab
|
||||
crontab -l 2>/dev/null > "$TEMP_CRON" || true
|
||||
|
||||
# Remove any old instances of this script
|
||||
if [ -s "$TEMP_CRON" ]; then
|
||||
sed -i "\#$SCRIPT_PATH#d" "$TEMP_CRON"
|
||||
fi
|
||||
|
||||
# Add new cron line
|
||||
echo "$CRON_LINE" >> "$TEMP_CRON"
|
||||
|
||||
# Install new crontab
|
||||
if crontab "$TEMP_CRON"; then
|
||||
logger -t log_cleanup "Successfully installed crontab job"
|
||||
else
|
||||
logger -t log_cleanup "Failed to install crontab job"
|
||||
rm -f "$TEMP_CRON"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Clean up
|
||||
rm -f "$TEMP_CRON"
|
||||
fi
|
||||
|
||||
# Clean log files
|
||||
if ! echo "" > "/tmp/apn_profiles.log"; then
|
||||
logger -t log_cleanup "Failed to clean file: /tmp/apn_profiles.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! echo "" > "/tmp/imei_profiles.log"; then
|
||||
logger -t log_cleanup "Failed to clean file: /tmp/imei_profiles.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! echo "" > "/var/log/at_commands.log"; then
|
||||
logger -t log_cleanup "Failed to clean file: /var/log/at_commands.log"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
logger -t log_cleanup "Successfully cleaned log files"
|
||||
@@ -3,177 +3,193 @@
|
||||
LOGDIR="/www/signal_graphs"
|
||||
MAX_ENTRIES=10
|
||||
INTERVAL=60
|
||||
QUEUE_FILE="/tmp/at_pipe.txt"
|
||||
AT_COMMAND_KEYWORD="AT_COMMAND_LOCK"
|
||||
CELL_SCAN_KEYWORD="CELL_SCAN" # Added to check for cell scan
|
||||
PAUSE_FILE="/tmp/signal_logging.pause"
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOCK_FILE="/tmp/signal_metrics.lock"
|
||||
METRICS_PID_FILE="/tmp/signal_metrics.pid"
|
||||
MAX_TOKEN_WAIT=5 # seconds to wait for token acquisition
|
||||
|
||||
# Ensure the directory exists
|
||||
mkdir -p "$LOGDIR"
|
||||
# Ensure required directories exist
|
||||
mkdir -p "$LOGDIR" "$QUEUE_DIR"
|
||||
|
||||
# Wait for high-priority operations
|
||||
wait_for_high_priority() {
|
||||
while grep -q "\"priority\":\"high\"" "$QUEUE_FILE"; do
|
||||
logger -t signal_metrics "Waiting for high-priority operation to complete"
|
||||
sleep 1
|
||||
done
|
||||
}
|
||||
|
||||
# Enhanced lock handling with better priority awareness
|
||||
handle_lock() {
|
||||
# Check for any CGI script operations (high priority)
|
||||
while grep -q "\"priority\":\"high\"" "$QUEUE_FILE" ||
|
||||
grep -q "\"command\":\"$AT_COMMAND_KEYWORD\"" "$QUEUE_FILE"; do
|
||||
logger -t signal_metrics "Waiting for high-priority CGI operation to complete"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
# Check and clean any stale FETCH_LOCK entries
|
||||
check_and_clean_stale "FETCH_LOCK"
|
||||
|
||||
# Check for cell scan operations
|
||||
while grep -q "\"command\":\"$CELL_SCAN_KEYWORD\"" "$QUEUE_FILE"; do
|
||||
logger -t signal_metrics "Waiting for cell scan to complete"
|
||||
sleep 1
|
||||
done
|
||||
|
||||
# Add our low-priority entry
|
||||
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s","priority":"low"}\n' \
|
||||
"$$" \
|
||||
"$(date '+%H:%M:%S')" >>"$QUEUE_FILE"
|
||||
|
||||
# Then check and clean our own entry if it gets stuck
|
||||
check_and_clean_stale "AT_COMMAND"
|
||||
}
|
||||
|
||||
# Increase the wait time for stale entry checking
|
||||
check_and_clean_stale() {
|
||||
local command_type="$1"
|
||||
local wait_count=0
|
||||
|
||||
while [ $wait_count -lt 10 ]; do # Increased from 6 to 10
|
||||
# Check if our type of entry exists
|
||||
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
|
||||
sleep 2 # Increased from 1 to 2
|
||||
wait_count=$((wait_count + 1))
|
||||
else
|
||||
# Entry is gone, we can proceed
|
||||
# Check if another instance is running
|
||||
check_running() {
|
||||
if [ -f "$METRICS_PID_FILE" ]; then
|
||||
pid=$(cat "$METRICS_PID_FILE")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# Only clean low-priority entries
|
||||
if ! grep -q "\"priority\":\"high\".*\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
|
||||
logger -t signal_metrics "Removing stale ${command_type} entry after ${wait_count}s"
|
||||
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
|
||||
rm -f "$METRICS_PID_FILE" 2>/dev/null
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Acquire token directly (minimized version)
|
||||
acquire_token() {
|
||||
local metrics_id="METRICS_$(date +%s)_$$"
|
||||
local priority=20 # Lowest priority for metrics
|
||||
local max_attempts=20
|
||||
local attempt=0
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
# Check current token
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Wait and try again
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token
|
||||
echo "{\"id\":\"$metrics_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got it
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$metrics_id" ]; then
|
||||
echo "$metrics_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Release token directly
|
||||
release_token() {
|
||||
local metrics_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$metrics_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Execute AT command directly
|
||||
execute_at_command() {
|
||||
local CMD="$1"
|
||||
sms_tool at "$CMD" -t 3 2>/dev/null
|
||||
}
|
||||
|
||||
# Process all metrics commands with a single token
|
||||
process_all_metrics() {
|
||||
# Try to get token
|
||||
local metrics_id=$(acquire_token)
|
||||
if [ -z "$metrics_id" ]; then
|
||||
logger -t at_queue -p daemon.warn "Could not acquire token for metrics - will try again later"
|
||||
return 1
|
||||
fi
|
||||
|
||||
logger -t at_queue -p daemon.info "Processing all metrics with token $metrics_id"
|
||||
|
||||
# Execute all metrics commands with the single token
|
||||
local timestamp=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
# RSRP
|
||||
local rsrp_output=$(execute_at_command "AT+QRSRP")
|
||||
if [ -n "$rsrp_output" ] && echo "$rsrp_output" | grep -q "QRSRP"; then
|
||||
local logfile="$LOGDIR/rsrp.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$rsrp_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# RSRQ
|
||||
local rsrq_output=$(execute_at_command "AT+QRSRQ")
|
||||
if [ -n "$rsrq_output" ] && echo "$rsrq_output" | grep -q "QRSRQ"; then
|
||||
local logfile="$LOGDIR/rsrq.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$rsrq_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# SINR
|
||||
local sinr_output=$(execute_at_command "AT+QSINR")
|
||||
if [ -n "$sinr_output" ] && echo "$sinr_output" | grep -q "QSINR"; then
|
||||
local logfile="$LOGDIR/sinr.json"
|
||||
[ ! -s "$logfile" ] && echo "[]" > "$logfile"
|
||||
|
||||
local temp_file="${logfile}.tmp.$$"
|
||||
jq --arg dt "$timestamp" \
|
||||
--arg out "$sinr_output" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$logfile" > "$temp_file" 2>/dev/null && mv "$temp_file" "$logfile"
|
||||
chmod 644 "$logfile"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
|
||||
# Data usage
|
||||
local usage_output=$(execute_at_command "AT+QGDCNT?;+QGDNRCNT?")
|
||||
if [ -n "$usage_output" ] && echo "$usage_output" | grep -q "QGDCNT\|QGDNRCNT"; then
|
||||
local logfile="$LOGDIR/data_usage.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"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Clean output function
|
||||
clean_output() {
|
||||
local output=""
|
||||
read -r line
|
||||
|
||||
while read -r line; do
|
||||
case "$line" in
|
||||
"OK" | "")
|
||||
continue
|
||||
;;
|
||||
*)
|
||||
if [ -n "$output" ]; then
|
||||
output="$output\\n$line"
|
||||
else
|
||||
output="$line"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "$output"
|
||||
}
|
||||
|
||||
# Execute AT command
|
||||
execute_at_command() {
|
||||
local COMMAND="$1"
|
||||
handle_lock
|
||||
local OUTPUT=$(sms_tool at "$COMMAND" -t 4 2>/dev/null | clean_output)
|
||||
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE" # Remove our entry
|
||||
echo "$OUTPUT"
|
||||
}
|
||||
|
||||
# Log signal metric with response validation
|
||||
log_signal_metric() {
|
||||
[ -f "$PAUSE_FILE" ] && return
|
||||
|
||||
local COMMAND="$1"
|
||||
local FILENAME="$2"
|
||||
local EXPECTED_RESPONSE="$3" # New parameter for expected response content
|
||||
local LOGFILE="$LOGDIR/$FILENAME"
|
||||
|
||||
mkdir -p "$(dirname "$LOGFILE")"
|
||||
|
||||
local TIMESTAMP=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
local SIGNAL_OUTPUT=$(execute_at_command "$COMMAND")
|
||||
|
||||
# Validate response based on command type
|
||||
case "$COMMAND" in
|
||||
"AT+QRSRP")
|
||||
if ! echo "$SIGNAL_OUTPUT" | grep -q "QRSRP"; then
|
||||
logger -t signal_metrics "Invalid RSRP response: $SIGNAL_OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
"AT+QRSRQ")
|
||||
if ! echo "$SIGNAL_OUTPUT" | grep -q "QRSRQ"; then
|
||||
logger -t signal_metrics "Invalid RSRQ response: $SIGNAL_OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
"AT+QSINR")
|
||||
if ! echo "$SIGNAL_OUTPUT" | grep -q "QSINR"; then
|
||||
logger -t signal_metrics "Invalid SINR response: $SIGNAL_OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
"AT+QGDCNT?;+QGDNRCNT?")
|
||||
if ! echo "$SIGNAL_OUTPUT" | grep -q "QGDCNT\|QGDNRCNT"; then
|
||||
logger -t signal_metrics "Invalid data usage response: $SIGNAL_OUTPUT"
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
[ ! -s "$LOGFILE" ] && echo "[]" >"$LOGFILE"
|
||||
|
||||
if [ -n "$SIGNAL_OUTPUT" ]; then
|
||||
local TEMP_FILE="${LOGFILE}.tmp.$$"
|
||||
if jq --arg dt "$TIMESTAMP" \
|
||||
--arg out "$SIGNAL_OUTPUT" \
|
||||
'. + [{"datetime": $dt, "output": $out}] | .[-'"$MAX_ENTRIES"':]' \
|
||||
"$LOGFILE" >"$TEMP_FILE"; then
|
||||
mv "$TEMP_FILE" "$LOGFILE"
|
||||
else
|
||||
rm -f "$TEMP_FILE"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Main continuous logging function
|
||||
# Main continuous logging function with proper locking
|
||||
start_continuous_logging() {
|
||||
sleep 20
|
||||
logger -t signal_metrics "Starting continuous signal metrics logging (PID: $$)"
|
||||
# Check if already running
|
||||
if check_running; then
|
||||
logger -t at_queue -p daemon.error "Signal metrics logging already running"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$METRICS_PID_FILE"
|
||||
chmod 644 "$METRICS_PID_FILE"
|
||||
|
||||
sleep 20 # Initial delay to allow system startup
|
||||
logger -t at_queue -p daemon.info "Starting continuous signal metrics logging (PID: $$)"
|
||||
|
||||
trap 'logger -t signal_metrics "Stopping signal metrics logging"; exit 0' INT TERM
|
||||
trap 'logger -t at_queue -p daemon.info "Stopping signal metrics logging"; rm -f "$METRICS_PID_FILE"; exit 0' INT TERM
|
||||
|
||||
while true; do
|
||||
if [ ! -f "$PAUSE_FILE" ]; then
|
||||
log_signal_metric "AT+QRSRP" "rsrp.json"
|
||||
log_signal_metric "AT+QRSRQ" "rsrq.json"
|
||||
log_signal_metric "AT+QSINR" "sinr.json"
|
||||
log_signal_metric "AT+QGDCNT?;+QGDNRCNT?" "data_usage.json"
|
||||
fi
|
||||
process_all_metrics
|
||||
sleep "$INTERVAL"
|
||||
done
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,544 @@
|
||||
#!/bin/sh
|
||||
|
||||
# QuecWatch Daemon
|
||||
# Monitors cellular connectivity and performs recovery actions
|
||||
|
||||
# Load UCI configuration functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOG_DIR="/tmp/log/quecwatch"
|
||||
LOG_FILE="$LOG_DIR/quecwatch.log"
|
||||
PID_FILE="/var/run/quecwatch.pid"
|
||||
STATUS_FILE="/tmp/quecwatch_status.json"
|
||||
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)
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE"
|
||||
|
||||
# Function to log messages
|
||||
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"
|
||||
|
||||
# Log to system log
|
||||
logger -t quecwatch -p "daemon.$level" "$message"
|
||||
}
|
||||
|
||||
# Function to update status
|
||||
update_status() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local retry="${3:-$CURRENT_RETRIES}"
|
||||
local max="${4:-$MAX_RETRIES}"
|
||||
|
||||
# Create JSON status
|
||||
cat > "$STATUS_FILE" <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"retry": $retry,
|
||||
"maxRetries": $max,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
chmod 644 "$STATUS_FILE"
|
||||
|
||||
log_message "Status updated: $status - $message" "debug"
|
||||
}
|
||||
|
||||
# Function to acquire token for AT commands
|
||||
acquire_token() {
|
||||
local requestor_id="QUECWATCH_$(date +%s)_$$"
|
||||
local priority="$TOKEN_PRIORITY"
|
||||
local max_attempts=$MAX_TOKEN_WAIT
|
||||
local attempt=0
|
||||
|
||||
log_message "Attempting to acquire token with priority $priority" "debug"
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token file exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> 30 seconds old)
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
# Remove expired token
|
||||
log_message "Found expired token from $current_holder, removing" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
# Preempt lower priority token
|
||||
log_message "Preempting token from $current_holder (priority: $current_priority)" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Check if the token is held by a QuecProfile or cell scan
|
||||
if echo "$current_holder" | grep -q "CELL_SCAN"; then
|
||||
log_message "Token held by cell scan (priority: $current_priority), waiting..." "debug"
|
||||
elif echo "$current_holder" | grep -q "QUECPROFILES"; then
|
||||
log_message "Token held by profile application (priority: $current_priority), waiting..." "debug"
|
||||
else
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$requestor_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got the token
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$requestor_id" ]; then
|
||||
log_message "Successfully acquired token with ID $requestor_id" "debug"
|
||||
echo "$requestor_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to release token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token $requestor_id" "debug"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($requestor_id)" "warn"
|
||||
else
|
||||
log_message "Token file doesn't exist, nothing to release" "debug"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to execute AT command with token
|
||||
execute_at_command() {
|
||||
local cmd="$1"
|
||||
local timeout="${2:-5}"
|
||||
local token_id="$3"
|
||||
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "No valid token provided for command: $cmd" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Executing AT command: $cmd (timeout: ${timeout}s)" "debug"
|
||||
|
||||
# Execute the command with proper timeout
|
||||
local output
|
||||
local status=1
|
||||
|
||||
output=$(sms_tool at "$cmd" -t "$timeout" 2>&1)
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
log_message "AT command failed: $cmd (exit code: $status)" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check internet connectivity
|
||||
check_internet() {
|
||||
local ping_target
|
||||
local ping_count=3
|
||||
|
||||
# Get ping target from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
config_get ping_target quecwatch ping_target
|
||||
|
||||
if [ -z "$ping_target" ]; then
|
||||
log_message "No ping target configured" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Checking internet connectivity to $ping_target" "debug"
|
||||
|
||||
if ping -c $ping_count "$ping_target" > /dev/null 2>&1; then
|
||||
log_message "Internet connectivity check successful" "debug"
|
||||
return 0
|
||||
else
|
||||
log_message "Internet connectivity check failed" "warn"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get current SIM slot
|
||||
get_current_sim() {
|
||||
local token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for SIM slot check" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Checking current SIM slot" "debug"
|
||||
|
||||
local result=$(execute_at_command "AT+QUIMSLOT?" 5 "$token_id")
|
||||
local status=$?
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
if [ $status -eq 0 ] && [ -n "$result" ]; then
|
||||
# Extract SIM slot number from response
|
||||
local current_sim=$(echo "$result" | grep -o '+QUIMSLOT: [0-9]' | cut -d' ' -f2)
|
||||
|
||||
if [ -n "$current_sim" ]; then
|
||||
log_message "Current SIM slot: $current_sim" "debug"
|
||||
echo "$current_sim"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "Failed to get current SIM slot" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to switch SIM card
|
||||
switch_sim_card() {
|
||||
local current_sim
|
||||
local target_sim
|
||||
local token_id
|
||||
|
||||
log_message "Starting SIM card switch operation" "info"
|
||||
|
||||
# Get current SIM slot
|
||||
current_sim=$(get_current_sim)
|
||||
if [ $? -ne 0 ]; then
|
||||
log_message "Failed to get current SIM slot, cannot switch" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Determine target SIM
|
||||
if [ "$current_sim" = "1" ]; then
|
||||
target_sim=2
|
||||
else
|
||||
target_sim=1
|
||||
fi
|
||||
|
||||
log_message "Attempting to switch from SIM $current_sim to SIM $target_sim" "info"
|
||||
|
||||
# Get token for AT commands
|
||||
token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for SIM switch" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detach from network
|
||||
log_message "Detaching from network" "debug"
|
||||
execute_at_command "AT+COPS=2" 10 "$token_id"
|
||||
sleep 2
|
||||
|
||||
# Switch SIM slot
|
||||
log_message "Switching to SIM slot $target_sim" "debug"
|
||||
local switch_result=$(execute_at_command "AT+QUIMSLOT=$target_sim" 10 "$token_id")
|
||||
local switch_status=$?
|
||||
|
||||
# If switch failed, return error
|
||||
if [ $switch_status -ne 0 ]; then
|
||||
log_message "Failed to switch to SIM $target_sim" "error"
|
||||
release_token "$token_id"
|
||||
return 1
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
|
||||
# Reattach to network
|
||||
log_message "Reattaching to network" "debug"
|
||||
execute_at_command "AT+COPS=0" 10 "$token_id"
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
# Verify switch
|
||||
sleep 10
|
||||
local new_sim=$(get_current_sim)
|
||||
if [ "$new_sim" = "$target_sim" ]; then
|
||||
log_message "Successfully switched to SIM $target_sim" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Failed to verify SIM switch, current SIM is $new_sim" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to perform connection recovery
|
||||
perform_connection_recovery() {
|
||||
local token_id
|
||||
|
||||
log_message "Starting connection recovery" "info"
|
||||
|
||||
# Get token for AT commands
|
||||
token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for connection recovery" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Detach from network
|
||||
log_message "Detaching from network" "debug"
|
||||
execute_at_command "AT+COPS=2" 10 "$token_id"
|
||||
sleep 2
|
||||
|
||||
# Reattach to network
|
||||
log_message "Reattaching to network" "debug"
|
||||
execute_at_command "AT+COPS=0" 15 "$token_id"
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
# Verify recovery
|
||||
sleep 10
|
||||
if check_internet; then
|
||||
log_message "Connection recovery successful" "info"
|
||||
return 0
|
||||
else
|
||||
log_message "Connection recovery failed" "error"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Load configuration
|
||||
load_config() {
|
||||
# Initialize variables
|
||||
PING_TARGET=""
|
||||
PING_INTERVAL=60
|
||||
PING_FAILURES=3
|
||||
MAX_RETRIES=5
|
||||
CURRENT_RETRIES=0
|
||||
CONNECTION_REFRESH=0
|
||||
REFRESH_COUNT=3
|
||||
AUTO_SIM_FAILOVER=0
|
||||
SIM_FAILOVER_SCHEDULE=0
|
||||
|
||||
# Load from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
|
||||
# Get settings with defaults
|
||||
config_get PING_TARGET quecwatch ping_target
|
||||
config_get PING_INTERVAL quecwatch ping_interval 60
|
||||
config_get PING_FAILURES quecwatch ping_failures 3
|
||||
config_get MAX_RETRIES quecwatch max_retries 5
|
||||
config_get CURRENT_RETRIES quecwatch current_retries 0
|
||||
config_get_bool CONNECTION_REFRESH quecwatch connection_refresh 0
|
||||
config_get REFRESH_COUNT quecwatch refresh_count 3
|
||||
config_get_bool AUTO_SIM_FAILOVER quecwatch auto_sim_failover 0
|
||||
config_get SIM_FAILOVER_SCHEDULE quecwatch sim_failover_schedule 0
|
||||
|
||||
# Validate required settings
|
||||
if [ -z "$PING_TARGET" ]; then
|
||||
log_message "No ping target configured, using default (8.8.8.8)" "warn"
|
||||
PING_TARGET="8.8.8.8"
|
||||
uci set "$UCI_CONFIG.quecwatch.ping_target=$PING_TARGET"
|
||||
uci commit "$UCI_CONFIG"
|
||||
fi
|
||||
|
||||
# Load persisted retry count if available
|
||||
if [ -f "$RETRY_COUNT_FILE" ]; then
|
||||
CURRENT_RETRIES=$(cat "$RETRY_COUNT_FILE")
|
||||
fi
|
||||
|
||||
log_message "Configuration loaded: ping_target=$PING_TARGET, interval=$PING_INTERVAL, failures=$PING_FAILURES, max_retries=$MAX_RETRIES, current_retries=$CURRENT_RETRIES" "info"
|
||||
}
|
||||
|
||||
# Save retry count to both UCI and file
|
||||
save_retry_count() {
|
||||
local count=$1
|
||||
|
||||
# Update UCI
|
||||
uci set "$UCI_CONFIG.quecwatch.current_retries=$count"
|
||||
uci commit "$UCI_CONFIG"
|
||||
|
||||
# Update file for crash recovery
|
||||
echo "$count" > "$RETRY_COUNT_FILE"
|
||||
chmod 644 "$RETRY_COUNT_FILE"
|
||||
|
||||
log_message "Updated retry count to $count" "debug"
|
||||
}
|
||||
|
||||
# Main monitoring function
|
||||
main() {
|
||||
log_message "QuecWatch daemon starting (PID: $$)" "info"
|
||||
|
||||
# Load configuration
|
||||
load_config
|
||||
|
||||
# Initial status update
|
||||
update_status "active" "Monitoring started"
|
||||
|
||||
# Track consecutive failures
|
||||
local failure_count=0
|
||||
|
||||
# For scheduled SIM failover
|
||||
local sim_failover_interval=0
|
||||
local initial_sim=""
|
||||
|
||||
# If auto SIM failover is enabled, store initial SIM slot
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ]; then
|
||||
initial_sim=$(get_current_sim)
|
||||
if [ -n "$initial_sim" ]; then
|
||||
log_message "Auto SIM failover enabled, initial SIM slot: $initial_sim" "info"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
log_message "Starting monitoring cycle" "debug"
|
||||
|
||||
# Check internet connectivity
|
||||
if ! check_internet; then
|
||||
failure_count=$((failure_count + 1))
|
||||
log_message "Connectivity check failed ($failure_count/$PING_FAILURES)" "warn"
|
||||
|
||||
# Update status
|
||||
update_status "warning" "Connection check failed: $failure_count/$PING_FAILURES failures"
|
||||
|
||||
# Check if failure threshold is reached
|
||||
if [ $failure_count -ge $PING_FAILURES ]; then
|
||||
# Reset failure counter
|
||||
failure_count=0
|
||||
|
||||
# Increment retry counter
|
||||
CURRENT_RETRIES=$((CURRENT_RETRIES + 1))
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
|
||||
log_message "Failure threshold reached. Current retry: $CURRENT_RETRIES/$MAX_RETRIES" "warn"
|
||||
update_status "error" "Connection lost, attempt $CURRENT_RETRIES/$MAX_RETRIES to recover"
|
||||
|
||||
# Check if max retries reached
|
||||
if [ $CURRENT_RETRIES -ge $MAX_RETRIES ]; then
|
||||
log_message "Maximum retries reached" "error"
|
||||
|
||||
# Try SIM failover if enabled
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ]; then
|
||||
log_message "Attempting SIM failover" "info"
|
||||
update_status "failover" "Maximum retries reached, attempting SIM failover"
|
||||
|
||||
if switch_sim_card && check_internet; then
|
||||
log_message "SIM failover successful, connection restored" "info"
|
||||
update_status "recovered" "Connection restored via SIM failover"
|
||||
|
||||
# Reset retry counter
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
else
|
||||
log_message "SIM failover failed, system will reboot" "error"
|
||||
update_status "rebooting" "SIM failover failed, system will reboot"
|
||||
|
||||
# Wait briefly and reboot
|
||||
sleep 5
|
||||
reboot
|
||||
fi
|
||||
else
|
||||
log_message "Auto SIM failover disabled, system will reboot" "error"
|
||||
update_status "rebooting" "Maximum retries reached, system will reboot"
|
||||
|
||||
# Wait briefly and reboot
|
||||
sleep 5
|
||||
reboot
|
||||
fi
|
||||
else
|
||||
# Try connection recovery
|
||||
log_message "Attempting connection recovery" "info"
|
||||
update_status "recovering" "Attempting to restore connection"
|
||||
|
||||
if perform_connection_recovery; then
|
||||
log_message "Connection recovery successful" "info"
|
||||
update_status "recovered" "Connection restored"
|
||||
|
||||
# Reset retry counter
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Connection is good
|
||||
if [ $failure_count -gt 0 ] || [ $CURRENT_RETRIES -gt 0 ]; then
|
||||
log_message "Connection restored" "info"
|
||||
update_status "stable" "Connection restored"
|
||||
|
||||
# Reset counters
|
||||
failure_count=0
|
||||
CURRENT_RETRIES=0
|
||||
save_retry_count $CURRENT_RETRIES
|
||||
fi
|
||||
|
||||
# Scheduled SIM failover check
|
||||
if [ "$AUTO_SIM_FAILOVER" -eq 1 ] && [ "$SIM_FAILOVER_SCHEDULE" -gt 0 ] && [ -n "$initial_sim" ]; then
|
||||
# Get current SIM to check if we're on the backup
|
||||
local current_sim=$(get_current_sim)
|
||||
|
||||
# If we're on backup SIM, check if it's time to try primary again
|
||||
if [ -n "$current_sim" ] && [ "$current_sim" != "$initial_sim" ]; then
|
||||
sim_failover_interval=$((sim_failover_interval + 1))
|
||||
|
||||
# Check if we've reached the scheduled time
|
||||
if [ $((sim_failover_interval * PING_INTERVAL)) -ge $((SIM_FAILOVER_SCHEDULE * 60)) ]; then
|
||||
log_message "Scheduled check: attempting to switch back to primary SIM $initial_sim" "info"
|
||||
update_status "switchback" "Attempting to switch back to primary SIM"
|
||||
|
||||
# Try switching back
|
||||
if switch_sim_card && check_internet; then
|
||||
log_message "Successfully switched back to primary SIM" "info"
|
||||
update_status "stable" "Successfully switched back to primary SIM"
|
||||
else
|
||||
log_message "Failed to switch back to primary SIM, staying on backup" "warn"
|
||||
update_status "stable" "Staying on backup SIM - primary SIM check failed"
|
||||
|
||||
# Switch back to backup SIM
|
||||
current_sim=$(get_current_sim)
|
||||
if [ -n "$current_sim" ] && [ "$current_sim" = "$initial_sim" ]; then
|
||||
switch_sim_card
|
||||
fi
|
||||
fi
|
||||
|
||||
# Reset failover interval
|
||||
sim_failover_interval=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Sleep for the configured interval
|
||||
sleep $PING_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Set up trap for clean shutdown
|
||||
trap 'log_message "Received signal, exiting" "info"; update_status "stopped" "Daemon stopped"; rm -f "$PID_FILE"; exit 0' INT TERM
|
||||
|
||||
# Start the main function
|
||||
main
|
||||
@@ -0,0 +1,429 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Cell Lock Scheduler Daemon
|
||||
# Monitors schedule and applies/restores cell locks as needed
|
||||
|
||||
# Load UCI configuration functions
|
||||
. /lib/functions.sh
|
||||
|
||||
# Configuration
|
||||
QUEUE_DIR="/tmp/at_queue"
|
||||
TOKEN_FILE="$QUEUE_DIR/token"
|
||||
LOG_DIR="/tmp/log/cell_lock"
|
||||
LOG_FILE="$LOG_DIR/cell_lock.log"
|
||||
PID_FILE="/var/run/cell_lock_scheduler.pid"
|
||||
STATUS_FILE="/tmp/cell_lock_status.json"
|
||||
UCI_CONFIG="quecmanager"
|
||||
CHECK_INTERVAL=60 # Check schedule every minute
|
||||
MAX_TOKEN_WAIT=15 # Maximum seconds to wait for token acquisition
|
||||
TOKEN_PRIORITY=5 # Higher priority than QuecWatch (which is 15)
|
||||
|
||||
# Ensure directories exist
|
||||
mkdir -p "$LOG_DIR" "$QUEUE_DIR"
|
||||
|
||||
# Store PID
|
||||
echo "$$" > "$PID_FILE"
|
||||
chmod 644 "$PID_FILE"
|
||||
|
||||
# Function to log messages
|
||||
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"
|
||||
|
||||
# Log to system log
|
||||
logger -t cell_lock -p "daemon.$level" "$message"
|
||||
}
|
||||
|
||||
# Function to update status
|
||||
update_status() {
|
||||
local status="$1"
|
||||
local message="$2"
|
||||
local active="${3:-0}"
|
||||
local locked="${4:-0}"
|
||||
|
||||
# Create JSON status
|
||||
cat > "$STATUS_FILE" <<EOF
|
||||
{
|
||||
"status": "$status",
|
||||
"message": "$message",
|
||||
"active": $active,
|
||||
"locked": $locked,
|
||||
"timestamp": $(date +%s)
|
||||
}
|
||||
EOF
|
||||
chmod 644 "$STATUS_FILE"
|
||||
|
||||
log_message "Status updated: $status - $message" "debug"
|
||||
}
|
||||
|
||||
# Function to acquire token for AT commands
|
||||
acquire_token() {
|
||||
local requestor_id="CELLLOCK_$(date +%s)_$$"
|
||||
local priority="$TOKEN_PRIORITY"
|
||||
local max_attempts=$MAX_TOKEN_WAIT
|
||||
local attempt=0
|
||||
|
||||
log_message "Attempting to acquire token with priority $priority" "debug"
|
||||
|
||||
while [ $attempt -lt $max_attempts ]; do
|
||||
# Check if token file exists
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
local current_priority=$(cat "$TOKEN_FILE" | jsonfilter -e '@.priority' 2>/dev/null)
|
||||
local timestamp=$(cat "$TOKEN_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
|
||||
local current_time=$(date +%s)
|
||||
|
||||
# Check for expired token (> 30 seconds old)
|
||||
if [ $((current_time - timestamp)) -gt 30 ] || [ -z "$current_holder" ]; then
|
||||
# Remove expired token
|
||||
log_message "Found expired token from $current_holder, removing" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
elif [ $priority -lt $current_priority ]; then
|
||||
# Preempt lower priority token
|
||||
log_message "Preempting token from $current_holder (priority: $current_priority)" "debug"
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
else
|
||||
# Check if the token is held by a cell scan
|
||||
if echo "$current_holder" | grep -q "CELL_SCAN"; then
|
||||
log_message "Token held by cell scan (priority: $current_priority), waiting..." "debug"
|
||||
else
|
||||
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Try to create token file
|
||||
echo "{\"id\":\"$requestor_id\",\"priority\":$priority,\"timestamp\":$(date +%s)}" > "$TOKEN_FILE" 2>/dev/null
|
||||
chmod 644 "$TOKEN_FILE" 2>/dev/null
|
||||
|
||||
# Verify we got the token
|
||||
local holder=$(cat "$TOKEN_FILE" 2>/dev/null | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$holder" = "$requestor_id" ]; then
|
||||
log_message "Successfully acquired token with ID $requestor_id" "debug"
|
||||
echo "$requestor_id"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 0.5
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
log_message "Failed to acquire token after $max_attempts attempts" "error"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to release token
|
||||
release_token() {
|
||||
local requestor_id="$1"
|
||||
|
||||
if [ -f "$TOKEN_FILE" ]; then
|
||||
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
|
||||
if [ "$current_holder" = "$requestor_id" ]; then
|
||||
rm -f "$TOKEN_FILE" 2>/dev/null
|
||||
log_message "Released token $requestor_id" "debug"
|
||||
return 0
|
||||
fi
|
||||
log_message "Token held by $current_holder, not by us ($requestor_id)" "warn"
|
||||
else
|
||||
log_message "Token file doesn't exist, nothing to release" "debug"
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to execute AT command with token
|
||||
execute_at_command() {
|
||||
local cmd="$1"
|
||||
local timeout="${2:-10}"
|
||||
local token_id="$3"
|
||||
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "No valid token provided for command: $cmd" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_message "Executing AT command: $cmd (timeout: ${timeout}s)" "debug"
|
||||
|
||||
# Execute the command with proper timeout
|
||||
local output
|
||||
local status=1
|
||||
|
||||
output=$(sms_tool at "$cmd" -t "$timeout" 2>&1)
|
||||
status=$?
|
||||
|
||||
if [ $status -ne 0 ]; then
|
||||
log_message "AT command failed: $cmd (exit code: $status)" "error"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$output"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check current lock status
|
||||
check_lock_status() {
|
||||
local token_id="$1"
|
||||
|
||||
log_message "Checking current cell lock status" "debug"
|
||||
|
||||
# Check LTE lock status
|
||||
local lte_status=$(execute_at_command 'AT+QNWLOCK="common/4g"' 5 "$token_id")
|
||||
local nr5g_status=$(execute_at_command 'AT+QNWLOCK="common/5g"' 5 "$token_id")
|
||||
|
||||
# Check if any lock is active
|
||||
if echo "$lte_status" | grep -q '"common/4g",0'; then
|
||||
if echo "$nr5g_status" | grep -q '"common/5g",0'; then
|
||||
log_message "No active cell locks detected" "debug"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
log_message "Active cell locks detected" "debug"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to get current lock parameters and save to UCI
|
||||
store_current_lock_params() {
|
||||
local token_id="$1"
|
||||
|
||||
log_message "Storing current lock parameters" "debug"
|
||||
|
||||
# Get LTE lock status
|
||||
local lte_status=$(execute_at_command 'AT+QNWLOCK="common/4g"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters
|
||||
local lte_params=$(echo "$lte_status" | grep -o '"common/4g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.lte_params='$lte_params'"
|
||||
log_message "Stored LTE parameters: $lte_params" "debug"
|
||||
fi
|
||||
|
||||
# Get NR5G lock status
|
||||
local nr5g_status=$(execute_at_command 'AT+QNWLOCK="common/5g"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters
|
||||
local nr5g_params=$(echo "$nr5g_status" | grep -o '"common/5g",[^[:space:]]*' | cut -d',' -f2-)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.nr5g_params='$nr5g_params'"
|
||||
log_message "Stored NR5G parameters: $nr5g_params" "debug"
|
||||
fi
|
||||
|
||||
# Get persist settings
|
||||
local persist_status=$(execute_at_command 'AT+QNWLOCK="save_ctrl"' 5 "$token_id")
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract parameters (LTE persist is at index 1, NR5G persist is at index 2)
|
||||
local persist_params=$(echo "$persist_status" | grep -o '"save_ctrl",[^[:space:]]*' | cut -d',' -f2-)
|
||||
local lte_persist=$(echo "$persist_params" | cut -d',' -f1)
|
||||
local nr5g_persist=$(echo "$persist_params" | cut -d',' -f2)
|
||||
|
||||
# Save to UCI
|
||||
uci set "$UCI_CONFIG.cell_lock.lte_persist='$lte_persist'"
|
||||
uci set "$UCI_CONFIG.cell_lock.nr5g_persist='$nr5g_persist'"
|
||||
log_message "Stored persist settings: LTE=$lte_persist, NR5G=$nr5g_persist" "debug"
|
||||
fi
|
||||
|
||||
# Commit changes
|
||||
uci commit "$UCI_CONFIG"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Function to check if time is in range
|
||||
is_time_in_range() {
|
||||
local current_time_minutes=$1
|
||||
local start_time_minutes=$2
|
||||
local end_time_minutes=$3
|
||||
|
||||
# Handle case where end time is on the next day
|
||||
if [ $end_time_minutes -lt $start_time_minutes ]; then
|
||||
if [ $current_time_minutes -ge $start_time_minutes ] || [ $current_time_minutes -lt $end_time_minutes ]; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
if [ $current_time_minutes -ge $start_time_minutes ] && [ $current_time_minutes -lt $end_time_minutes ]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to convert HH:MM to minutes
|
||||
time_to_minutes() {
|
||||
local time="$1"
|
||||
local hours=$(echo "$time" | cut -d':' -f1)
|
||||
local minutes=$(echo "$time" | cut -d':' -f2)
|
||||
|
||||
echo $((hours * 60 + minutes))
|
||||
}
|
||||
|
||||
# Function to check schedule and manage cell locks
|
||||
check_schedule() {
|
||||
local enabled
|
||||
local start_time
|
||||
local end_time
|
||||
local current_active
|
||||
|
||||
# Get current scheduler state from UCI
|
||||
config_load "$UCI_CONFIG"
|
||||
config_get_bool enabled cell_lock enabled 0
|
||||
|
||||
if [ "$enabled" -ne 1 ]; then
|
||||
log_message "Cell lock scheduler is disabled" "debug"
|
||||
update_status "disabled" "Scheduler is disabled" 0 0
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Get schedule from UCI
|
||||
config_get start_time cell_lock start_time
|
||||
config_get end_time cell_lock end_time
|
||||
config_get current_active cell_lock active 0
|
||||
|
||||
if [ -z "$start_time" ] || [ -z "$end_time" ]; then
|
||||
log_message "Missing start or end time in configuration" "error"
|
||||
update_status "error" "Missing schedule configuration" 0 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Get current time
|
||||
local current_time=$(date "+%H:%M")
|
||||
|
||||
# Convert times to minutes for comparison
|
||||
local current_minutes=$(time_to_minutes "$current_time")
|
||||
local start_minutes=$(time_to_minutes "$start_time")
|
||||
local end_minutes=$(time_to_minutes "$end_time")
|
||||
|
||||
# Get token for AT commands
|
||||
local token_id=$(acquire_token)
|
||||
if [ -z "$token_id" ]; then
|
||||
log_message "Failed to acquire token for checking schedule" "error"
|
||||
update_status "error" "Failed to acquire token for checking schedule" 0 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if any cell lock is currently active
|
||||
local lock_active=0
|
||||
check_lock_status "$token_id" && lock_active=1
|
||||
|
||||
# Check if current time is in the scheduled range
|
||||
if is_time_in_range "$current_minutes" "$start_minutes" "$end_minutes"; then
|
||||
# We're in the active window
|
||||
if [ "$current_active" -ne 1 ]; then
|
||||
# We just entered the window, need to save current state
|
||||
log_message "Entering scheduled window" "info"
|
||||
|
||||
# Store current lock parameters if a lock is active
|
||||
if [ $lock_active -eq 1 ]; then
|
||||
log_message "Storing current cell lock parameters" "info"
|
||||
store_current_lock_params "$token_id"
|
||||
else
|
||||
log_message "No active cell locks to store" "info"
|
||||
update_status "inactive" "Schedule active but no cell locks configured" 1 0
|
||||
release_token "$token_id"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Update status
|
||||
uci set "$UCI_CONFIG.cell_lock.active=1"
|
||||
uci commit "$UCI_CONFIG"
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
else
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
}
|
||||
else
|
||||
# We're outside the active window
|
||||
if [ "$current_active" -eq 1 ]; then
|
||||
# We just exited the window
|
||||
log_message "Exiting scheduled window" "info"
|
||||
|
||||
# Update status
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
update_status "inactive" "Outside scheduled hours" 0 $lock_active
|
||||
} else {
|
||||
update_status "inactive" "Outside scheduled hours" 0 $lock_active
|
||||
}
|
||||
fi
|
||||
|
||||
# Release token
|
||||
release_token "$token_id"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log_message "Cell lock scheduler daemon starting (PID: $$)" "info"
|
||||
|
||||
# Ensure UCI section exists
|
||||
if ! uci -q get "$UCI_CONFIG.cell_lock" >/dev/null; then
|
||||
uci set "$UCI_CONFIG.cell_lock=scheduler"
|
||||
uci set "$UCI_CONFIG.cell_lock.enabled=0"
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
log_message "Created cell lock UCI configuration" "info"
|
||||
fi
|
||||
|
||||
# Initialize status
|
||||
update_status "starting" "Cell lock scheduler daemon starting" 0 0
|
||||
|
||||
# Get token and check if any locks are active
|
||||
local token_id=$(acquire_token)
|
||||
if [ -n "$token_id" ]; then
|
||||
local lock_active=0
|
||||
check_lock_status "$token_id" && lock_active=1
|
||||
release_token "$token_id"
|
||||
|
||||
# Update status based on current state
|
||||
local enabled=$(uci -q get "$UCI_CONFIG.cell_lock.enabled")
|
||||
if [ "$enabled" = "1" ]; then
|
||||
# Get schedule from UCI
|
||||
local start_time=$(uci -q get "$UCI_CONFIG.cell_lock.start_time")
|
||||
local end_time=$(uci -q get "$UCI_CONFIG.cell_lock.end_time")
|
||||
|
||||
if [ -n "$start_time" ] && [ -n "$end_time" ]; then
|
||||
# Check if we're currently in the schedule window
|
||||
local current_time=$(date "+%H:%M")
|
||||
local current_minutes=$(time_to_minutes "$current_time")
|
||||
local start_minutes=$(time_to_minutes "$start_time")
|
||||
local end_minutes=$(time_to_minutes "$end_time")
|
||||
|
||||
if is_time_in_range "$current_minutes" "$start_minutes" "$end_minutes"; then
|
||||
update_status "active" "Cell lock scheduler is active" 1 $lock_active
|
||||
uci set "$UCI_CONFIG.cell_lock.active=1"
|
||||
uci commit "$UCI_CONFIG"
|
||||
} else {
|
||||
update_status "inactive" "Cell lock scheduler is enabled but outside scheduled hours" 0 $lock_active
|
||||
uci set "$UCI_CONFIG.cell_lock.active=0"
|
||||
uci commit "$UCI_CONFIG"
|
||||
}
|
||||
} else {
|
||||
update_status "error" "Missing schedule configuration" 0 $lock_active
|
||||
}
|
||||
} else {
|
||||
update_status "disabled" "Cell lock scheduler is disabled" 0 $lock_active
|
||||
}
|
||||
} else {
|
||||
log_message "Failed to acquire token for initial status check" "error"
|
||||
}
|
||||
|
||||
# Main monitoring loop
|
||||
while true; do
|
||||
check_schedule
|
||||
sleep $CHECK_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Set up trap for clean shutdown
|
||||
trap 'log_message "Received signal, exiting" "info"; update_status "stopped" "Daemon stopped" 0 0; rm -f "$PID_FILE"; exit 0' INT TERM
|
||||
|
||||
# Start the main function
|
||||
main
|
||||
Reference in New Issue
Block a user