Merging Beta 2.0.0 Release Candidate

This commit is contained in:
Russel Yasol
2025-03-11 15:21:04 +08:00
parent 0ce398b6e5
commit 36874b12f0
169 changed files with 8794 additions and 3057 deletions

View File

@@ -1,5 +1,5 @@
Package: sdxpinn-quecmanager-beta
Version: 1.1.1-4
Version: 2.0.0
Architecture: aarch64_cortex-a53
Maintainer: Russel Yasol dr-dolomite@github.com Cameron Thompson iamromulan@github.com
Source: github.com/iamromulan

View File

@@ -0,0 +1,22 @@
#! /bin/sh /etc/rc.common
START=90
USE_PROCD=1
start_service() {
if [ ! -f /etc/config/system ]; then
touch /etc/config/system
sh /etc/init.d/ntp.config.h
procd_open_instance
procd_set_param command user ntp
procd_set_param command group ntp
procd_close_instance
fi
echo "Starting ntp config service..."
}
stop_service(){
echo "Stoping ntp config service..."
}

View File

@@ -0,0 +1,49 @@
#!/bin/sh /etc/rc.common
START=95
STOP=10
USE_PROCD=1
DAEMON="/www/cgi-bin/services/scheduled_cell_locking.sh"
UCI_CONFIG="quecmanager"
PID_FILE="/var/run/cell_lock_scheduler.pid"
LOG_DIR="/tmp/log/cell_lock"
start_service() {
# Check if the daemon script exists
if [ ! -x "$DAEMON" ]; then
logger -t cell_lock -p daemon.error "Daemon script not found or not executable: $DAEMON"
return 1
fi
# Check if service is enabled in UCI
local enabled
config_load "$UCI_CONFIG"
config_get_bool enabled cell_lock enabled 0
if [ "$enabled" -ne 1 ]; then
logger -t cell_lock -p daemon.info "Cell lock scheduler is disabled in config"
return 0
fi
# Create log directory
mkdir -p "$LOG_DIR"
# Start the service via procd
logger -t cell_lock -p daemon.info "Starting cell lock scheduler daemon"
procd_open_instance "cell_lock_scheduler"
procd_set_param command "$DAEMON"
procd_set_param respawn 3600 5 5 # Retry every hour, 5 times max
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile "$PID_FILE"
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "$UCI_CONFIG"
}
reload_service() {
restart
}

View File

@@ -3,25 +3,27 @@ START=49
STOP=10
USE_PROCD=1
start_service() {
# Run clear_logs.sh once without procd management, with a timeout
echo "Clearing QuecManager Logs"
timeout 5 /www/cgi-bin/services/clear_logs.sh
if [ $? -eq 124 ]; then
echo "clear_logs.sh timed out after 5 seconds"
else
echo "Log Cleaner complete"
fi
# Configuration paths
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
LOG_DIR="/www/signal_graphs"
# Start the continuously running services
echo "Starting AT Command Queue Processor..."
start_service() {
# Ensure required directories exist
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR" "$LOG_DIR"
chmod 755 "$QUEUE_DIR" "$RESULTS_DIR" "$LOG_DIR"
# Start the AT Command Queue Manager
echo "Starting AT Command Queue Manager..."
procd_open_instance
procd_set_param command /www/cgi-bin/services/at_queue_processor.sh
procd_set_param command /www/cgi-bin/services/at_queue_manager.sh
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
echo "AT Queue Processor Started"
echo "AT Queue Manager Started"
# Start the Signal Metrics Logger
echo "Starting Signal Metrics Logger..."
procd_open_instance
procd_set_param command /www/cgi-bin/services/log_signal_metrics.sh
@@ -37,4 +39,4 @@ start_service() {
stop_service() {
# procd will handle stopping all instances automatically
echo "Stopping QuecManager services."
}
}

View File

@@ -0,0 +1,84 @@
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
# Configuration paths
PROG="/www/cgi-bin/services/quecprofile.sh"
CONF="/etc/config/quecprofiles"
TRACK_FILE="/tmp/quecprofiles_active"
CHECK_TRIGGER="/tmp/quecprofiles_check"
STATUS_FILE="/tmp/quecprofiles_status.json"
DEBUG_LOG="/tmp/quecprofiles_debug.log"
start_service() {
# Ensure configuration exists
if [ ! -f "$CONF" ]; then
# Create default configuration
cat > "$CONF" <<-EOF
config quecprofiles 'settings'
option check_interval '60'
option enable_autoswitch '1'
option apply_priority '20'
EOF
fi
# Ensure script is executable
if [ -f "$PROG" ]; then
chmod 755 "$PROG"
else
logger -t quecprofiles -p daemon.error "Profile daemon script not found at $PROG"
return 1
fi
# Clear any existing logs
echo "$(date) - Init script starting service" > "$DEBUG_LOG"
# Check if service is enabled
local enabled
config_load quecprofiles
config_get_bool enabled settings enable_autoswitch 1
if [ "$enabled" -eq 0 ]; then
logger -t quecprofiles -p daemon.info "QuecProfiles service is disabled in config"
echo "$(date) - Service is disabled in config" >> "$DEBUG_LOG"
return 0
fi
# Log before starting daemon
logger -t quecprofiles -p daemon.info "Starting QuecProfiles Daemon with script: $PROG"
echo "$(date) - Starting daemon using script: $PROG" >> "$DEBUG_LOG"
# Start the profile daemon
echo "Starting QuecProfiles Daemon..."
procd_open_instance "quecprofiles"
procd_set_param command "$PROG"
procd_set_param respawn
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
echo "QuecProfiles Daemon Started"
echo "$(date) - Daemon started via procd" >> "$DEBUG_LOG"
}
stop_service() {
# Clean up state files
rm -f "$TRACK_FILE"
rm -f "$CHECK_TRIGGER"
# Log stop action
logger -t quecprofiles -p daemon.info "Stopping QuecProfiles service"
echo "$(date) - Stopping service" >> "$DEBUG_LOG"
# procd will handle stopping the instance automatically
echo "Stopping QuecProfiles service."
}
service_triggers() {
procd_add_reload_trigger "quecprofiles"
}
reload_service() {
touch "$CHECK_TRIGGER"
restart
}

View File

@@ -0,0 +1,49 @@
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
DAEMON="/www/cgi-bin/services/quecwatch.sh"
UCI_CONFIG="quecmanager"
PID_FILE="/var/run/quecwatch.pid"
LOG_DIR="/tmp/log/quecwatch"
start_service() {
# Check if the daemon script exists
if [ ! -x "$DAEMON" ]; then
logger -t quecwatch -p daemon.error "Daemon script not found or not executable: $DAEMON"
return 1
fi
# Check if service is enabled in UCI
local enabled
config_load "$UCI_CONFIG"
config_get_bool enabled quecwatch enabled 0
if [ "$enabled" -ne 1 ]; then
logger -t quecwatch -p daemon.info "QuecWatch service is disabled in config"
return 0
fi
# Create log directory
mkdir -p "$LOG_DIR"
# Start the service via procd
logger -t quecwatch -p daemon.info "Starting QuecWatch daemon"
procd_open_instance "quecwatch"
procd_set_param command "$DAEMON"
procd_set_param respawn 3600 5 5 # Retry every hour, 5 times max
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param pidfile "$PID_FILE"
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "$UCI_CONFIG"
}
reload_service() {
restart
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
self.__BUILD_MANIFEST=function(r,e,t){return{__rewrites:{afterFiles:[],beforeFiles:[],fallback:[]},__routerFilterStatic:{numItems:21,errorRate:1e-4,numBits:403,numHashes:14,bitArray:[0,1,1,0,1,e,0,r,r,e,e,e,e,e,e,r,e,e,r,e,r,r,e,e,r,r,e,r,r,r,e,e,r,r,e,e,e,r,r,r,r,e,r,r,r,e,e,e,e,e,r,r,r,e,e,r,r,r,e,r,r,e,e,e,e,r,r,r,e,r,r,r,e,e,e,e,r,e,r,e,r,e,r,e,e,e,e,r,r,r,e,r,e,e,r,r,e,r,e,e,e,r,r,r,r,e,e,e,r,r,e,r,e,e,e,r,r,e,e,r,r,r,r,e,r,e,e,e,e,e,e,r,r,e,r,r,e,r,r,r,r,r,e,r,e,e,r,e,e,r,r,r,r,e,r,r,r,e,e,e,e,r,e,e,e,r,e,e,e,e,r,r,e,e,e,e,r,e,r,r,e,r,r,e,r,e,r,r,e,e,r,e,e,e,r,r,e,r,r,e,e,e,e,r,r,e,r,e,e,e,r,e,r,r,e,r,e,r,r,r,e,e,r,r,r,e,e,e,r,r,e,r,r,r,e,r,e,e,r,e,e,r,r,e,e,r,r,r,e,r,e,r,r,r,e,e,e,e,e,r,r,e,e,e,e,r,e,r,r,r,e,e,r,e,r,e,e,r,r,r,r,r,e,e,r,e,e,e,r,r,r,r,r,e,e,e,e,r,e,r,r,r,e,r,e,e,e,e,r,r,r,e,r,e,e,r,e,r,r,r,e,r,r,e,r,e,r,r,e,r,r,r,r,e,r,r,e,e,r,e,e,r,r,r,r,e,r,r,e,r,r,e,r,r,e,r,r,e,r,e,r,r,e,e,r,e,r,e,e,r,e,e,e,e,r,r,e,r,r,r,r,e,r,e,e,r,r,r,e,e,e,e,e,r,e,e,e,r,e,r,r,r,e]},__routerFilterDynamic:{numItems:r,errorRate:1e-4,numBits:r,numHashes:null,bitArray:[]},"/_error":["static/chunks/pages/_error-f347b70a71a8047b.js"],sortedPages:["/_app","/_error"]}}(0,1,0),self.__BUILD_MANIFEST_CB&&self.__BUILD_MANIFEST_CB();

View File

@@ -0,0 +1 @@
self.__SSG_MANIFEST=new Set([]);self.__SSG_MANIFEST_CB&&self.__SSG_MANIFEST_CB()

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[3075],{43946:(e,a,r)=>{Promise.resolve().then(r.bind(r,31753))},31753:(e,a,r)=>{"use strict";r.r(a),r.d(a,{default:()=>c});var s=r(20475);r(20107);var t=r(16118),l=r(9477),n=r.n(l);let c=e=>{let{children:a}=e,r=(0,t.usePathname)();return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("div",{className:"mx-auto grid w-full max-w-6xl gap-2",children:(0,s.jsx)("h1",{className:"text-3xl font-semibold",children:"Experimental"})}),(0,s.jsxs)("div",{className:"mx-auto grid w-full max-w-6xl items-start gap-6 md:grid-cols-[180px_1fr] lg:grid-cols-[250px_1fr]",children:[(0,s.jsxs)("nav",{className:"grid gap-4 text-sm text-muted-foreground","x-chunk":"dashboard-04-chunk-0",children:[(0,s.jsx)(n(),{href:"/dashboard/experimental/quecwatch",className:"".concat("/dashboard/experimental/quecwatch/"===r?"font-semibold text-primary":"text-sm"),children:"QuecWatch"}),(0,s.jsx)(n(),{href:"/dashboard/experimental/quecprofiles",className:"".concat("/dashboard/experimental/quecprofiles/"===r?"font-semibold text-primary":"text-sm"),children:"QuecProfiles"}),(0,s.jsx)(n(),{href:"/dashboard/experimental/keep-alive",className:"".concat("/dashboard/experimental/keep-alive/"===r?"font-semibold text-primary":"text-sm"),children:"Keep Alive"}),(0,s.jsx)(n(),{href:"/dashboard/experimental/cell-scanner",className:"".concat("/dashboard/experimental/cell-scanner/"===r?"font-semibold text-primary":"text-sm"),children:"Cell Scanner"})]}),a]})]})}},16118:(e,a,r)=>{"use strict";var s=r(65834);r.o(s,"usePathname")&&r.d(a,{usePathname:function(){return s.usePathname}}),r.o(s,"useRouter")&&r.d(a,{useRouter:function(){return s.useRouter}})}},e=>{var a=a=>e(e.s=a);e.O(0,[9477,191,6035,7358],()=>a(43946)),_N_E=e.O()}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={id:o,loaded:!1,exports:{}},i=!0;try{e[o].call(a.exports,a,a.exports,r),i=!1}finally{i&&delete t[o]}return a.loaded=!0,a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(o){a=a||0;for(var i=e.length;i>0&&e[i-1][2]>a;i--)e[i]=e[i-1];e[i]=[o,n,a];return}for(var l=1/0,i=0;i<e.length;i++){for(var[o,n,a]=e[i],u=!0,d=0;d<o.length;d++)(!1&a||l>=a)&&Object.keys(r.O).every(e=>r.O[e](o[d]))?o.splice(d--,1):(u=!1,a<l&&(l=a));if(u){e.splice(i--,1);var c=n();void 0!==c&&(t=c)}}return t}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n||"object"==typeof o&&o&&(4&n&&o.__esModule||16&n&&"function"==typeof o.then))return o;var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var l=2&n&&o;"object"==typeof l&&!~e.indexOf(l);l=t(l))Object.getOwnPropertyNames(l).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>"static/chunks/"+e+"."+({3993:"84dc2c07c5289739",4840:"58ad85f7ae0b4d74"})[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="_N_E:";r.l=(o,n,a,i)=>{if(e[o]){e[o].push(n);return}if(void 0!==a)for(var l,u,d=document.getElementsByTagName("script"),c=0;c<d.length;c++){var s=d[c];if(s.getAttribute("src")==o||s.getAttribute("data-webpack")==t+a){l=s;break}}l||(u=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,r.nc&&l.setAttribute("nonce",r.nc),l.setAttribute("data-webpack",t+a),l.src=r.tu(o)),e[o]=[n];var f=(t,r)=>{l.onerror=l.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],l.parentNode&&l.parentNode.removeChild(l),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(f.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=f.bind(null,l.onerror),l.onload=f.bind(null,l.onload),u&&document.head.appendChild(l)}})(),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),(()=>{var e;r.tt=()=>(void 0===e&&(e={createScriptURL:e=>e},"undefined"!=typeof trustedTypes&&trustedTypes.createPolicy&&(e=trustedTypes.createPolicy("nextjs#bundler",e))),e)})(),r.tu=e=>r.tt().createScriptURL(e),r.p="/_next/",(()=>{var e={8068:0,3752:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n){if(n)o.push(n[2]);else if(/^(3752|8068)$/.test(t))e[t]=0;else{var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),l=Error();r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;l.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",l.name="ChunkLoadError",l.type=a,l.request=i,n[1](l)}},"chunk-"+t,t)}}},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,[i,l,u]=o,d=0;if(i.some(t=>0!==e[t])){for(n in l)r.o(l,n)&&(r.m[n]=l[n]);if(u)var c=u(r)}for(t&&t(o);d<i.length;d++)a=i[d],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(c)},o=self.webpackChunk_N_E=self.webpackChunk_N_E||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})(),r.nc=void 0})();

File diff suppressed because one or more lines are too long

View File

@@ -1,180 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define file paths and configuration
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/var/log/at_commands.log"
LOCK_KEYWORD="AT_COMMAND_LOCK"
CELL_SCAN_KEYWORD="CELL_SCAN"
MAX_WAIT=6 # Maximum seconds to wait for lock
COMMAND_TIMEOUT=4 # Timeout for individual AT commands
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
logger -t at_commands "$1"
}
# Function to output error in JSON format
output_error() {
printf '{"status":"error","message":"%s","timestamp":"%s"}\n' "$1" "$(date '+%H:%M:%S')"
exit 1
}
# Function to wait for high-priority operations
wait_for_high_priority() {
while grep -q "\"command\":\"$CELL_SCAN_KEYWORD\"" "$QUEUE_FILE" || \
grep -q "\"priority\":\"high\"" "$QUEUE_FILE"; do
log_message "Waiting for high-priority operation to complete"
sleep 1
done
}
# Function to clean and add lock with simplified timeout logic
add_clean_lock() {
local TIMESTAMP=$(date +%s)
local WAIT_START=$(date +%s)
# First, wait for any high-priority operations
wait_for_high_priority
while true; do
local CURRENT_TIME=$(date +%s)
# After MAX_WAIT seconds, forcibly remove any existing lock
if [ $((CURRENT_TIME - WAIT_START)) -ge $MAX_WAIT ]; then
sed -i "/${LOCK_KEYWORD}/d" "$QUEUE_FILE"
log_message "Removed existing lock after $MAX_WAIT seconds timeout"
fi
# Add our lock entry with high priority
printf '{"id":"%s","timestamp":"%s","command":"%s","status":"lock","pid":"%s","start_time":"%s","priority":"high"}\n' \
"${LOCK_KEYWORD}" \
"$(date '+%H:%M:%S')" \
"${LOCK_KEYWORD}" \
"$$" \
"$TIMESTAMP" >> "$QUEUE_FILE"
# Verify our lock was written
if grep -q "\"pid\":\"$$\".*\"start_time\":\"$TIMESTAMP\"" "$QUEUE_FILE"; then
log_message "Lock created by PID $$ at $TIMESTAMP"
trap 'remove_lock; exit' INT TERM EXIT
return 0
fi
if [ $((CURRENT_TIME - WAIT_START)) -lt $MAX_WAIT ]; then
sleep 1
else
log_message "Failed to acquire lock after $MAX_WAIT seconds"
return 1
fi
done
}
# Function to remove lock
remove_lock() {
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
log_message "Lock removed by PID $$"
}
# Function to escape JSON
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$//'
}
# Simplified AT command execution with basic response validation
execute_at_command() {
local CMD="$1"
local RETRY_COUNT=0
local MAX_RETRIES=3
local OUTPUT=""
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
# Execute command with -D parameter to include OK/ERROR responses
OUTPUT=$(timeout $COMMAND_TIMEOUT sms_tool at "$CMD" -D 2>&1)
local EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
# Check if response contains "CME" for execution failure
if echo "$OUTPUT" | grep -q "CME"; then
echo "$OUTPUT"
return 2 # Command execution failed
# Check if response contains OK (simple grep)
elif echo "$OUTPUT" | grep -q "OK"; then
echo "$OUTPUT"
return 0
else
# Any other response is considered unsupported
echo "$OUTPUT"
return 1
fi
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
[ $RETRY_COUNT -lt $MAX_RETRIES ] && sleep 1
done
log_message "Command failed after $MAX_RETRIES attempts: $CMD"
return 1
}
# Get command from query string
QUERY_STRING="${QUERY_STRING:-}"
RAW_COMMAND=$(echo "${QUERY_STRING}" | sed 's/^command=//')
if [ -n "${RAW_COMMAND}" ]; then
# Decode URL-encoded command
AT_COMMAND=$(printf '%b' "${RAW_COMMAND}" | sed -e 's/%\([0-9A-Fa-f][0-9A-Fa-f]\)/\\x\1/g' | xargs -0 echo -e)
# Set timeout for the entire script
( sleep 60; kill -TERM $$ 2>/dev/null ) &
TIMEOUT_PID=$!
if ! add_clean_lock; then
kill $TIMEOUT_PID 2>/dev/null
output_error "Failed to acquire lock for command processing"
fi
# Execute command and capture result
RESULT=$(execute_at_command "${AT_COMMAND}")
EXIT_CODE=$?
# Clean up
remove_lock
kill $TIMEOUT_PID 2>/dev/null
# Escape command and result for JSON
ESCAPED_COMMAND=$(escape_json "${AT_COMMAND}")
ESCAPED_RESULT=$(escape_json "${RESULT}")
# Return response based on simplified exit codes
if [ $EXIT_CODE -eq 0 ]; then
# Command succeeded with OK response
printf '{"status":"success","command":"%s","response":"%s","timestamp":"%s"}\n' \
"${ESCAPED_COMMAND}" "${ESCAPED_RESULT}" "$(date '+%H:%M:%S')"
elif [ $EXIT_CODE -eq 2 ]; then
# Command contains CME - execution failed
printf '{"status":"error","command":"%s","message":"Command execution failed","response":"%s","timestamp":"%s"}\n' \
"${ESCAPED_COMMAND}" "${ESCAPED_RESULT}" "$(date '+%H:%M:%S')"
else
# Any other response is considered unsupported
printf '{"status":"error","command":"%s","message":"Unsupported command","response":"%s","timestamp":"%s"}\n' \
"${ESCAPED_COMMAND}" "${ESCAPED_RESULT}" "$(date '+%H:%M:%S')"
fi
else
output_error "No command provided"
fi

View File

@@ -1,66 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/apn_profile/" ]; then
rm -rf /etc/quecmanager/apn_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the apnProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/apnProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/apn_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputAPN.txt
rm -f /tmp/outputAPN.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"APN profiles and configuration successfully removed\"}"
fi

View File

@@ -1,45 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/apn_profile/apn_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile1=$(grep "^apnProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType1=$(grep "^pdpType1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
apnProfile2=$(grep "^apnProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
pdpType2=$(grep "^pdpType2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"apn\": \"$apnProfile1\","
echo " \"pdpType\": \"$pdpType1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"apn\": \"$apnProfile2\","
echo " \"pdpType\": \"$pdpType2\""
echo " }"
fi
echo "}"

View File

@@ -1,292 +0,0 @@
#!/bin/sh
# Parse POST data (using busybox compatible method)
read -r QUERY_STRING
# Function to urldecode (busybox compatible version)
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile1=\([^&]*\).*/\1/p' | tr -d "'")
pdpType1=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile2=\([^&]*\).*/\1/p' | tr -d "'")
pdpType2=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
apnProfile1=$(urldecode "$apnProfile1")
pdpType1=$(urldecode "$pdpType1")
iccidProfile2=$(urldecode "$iccidProfile2")
apnProfile2=$(urldecode "$apnProfile2")
pdpType2=$(urldecode "$pdpType2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create directory with proper permissions
mkdir -p /etc/quecmanager/apn_profile
chmod 755 /etc/quecmanager/apn_profile
# Create a configuration file to store APN profiles (with proper permissions)
cat > /etc/quecmanager/apn_profile/apn_config.txt <<EOF
iccidProfile1=${iccidProfile1}
apnProfile1=${apnProfile1}
pdpType1=${pdpType1}
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/apn_profile/apn_config.txt <<EOF
iccidProfile2=${iccidProfile2}
apnProfile2=${apnProfile2}
pdpType2=${pdpType2}
EOF
fi
chmod 644 /etc/quecmanager/apn_profile/apn_config.txt
# Create the apnProfiles.sh script with proper locking mechanism and logging
cat > /etc/quecmanager/apn_profile/apnProfiles.sh <<'EOF'
#!/bin/sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/apn_profiles.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t apn_profiles "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Simplified lock handling with debug
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command without timeout dependency
execute_at_command() {
local command="$1"
local result=""
log_message "DEBUG" "Executing AT command: ${command}"
handle_lock
# Execute command and capture all output
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -ne 0 ]; then
log_message "ERROR" "Command failed with status $status: $command"
log_message "ERROR" "Command output: $result"
return 1
fi
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
}
# Get current ICCID with enhanced debug
get_current_iccid() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current ICCID"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "ICCID attempt ${retry_count}"
result=$(execute_at_command "AT+ICCID")
local cmd_status=$?
log_message "DEBUG" "AT+ICCID command returned status: ${cmd_status}"
log_message "DEBUG" "AT+ICCID raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
local iccid=$(echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]')
log_message "INFO" "Retrieved current ICCID: ${iccid}"
echo "${iccid}"
return 0
else
log_message "WARN" "Attempt ${retry_count} failed to get valid ICCID"
log_message "WARN" "Result: ${result}"
fi
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
log_message "INFO" "Waiting 2 seconds before retry"
sleep 2
fi
done
log_message "ERROR" "Failed to get ICCID after $max_retries attempts"
return 1
}
# Set APN with modified error handling - removed strict OK check
set_apn() {
local pdp_type="$1"
local apn="$2"
local result
local retry_count=0
local max_retries=3
if [ -z "$pdp_type" ] || [ -z "$apn" ]; then
log_message "ERROR" "Invalid PDP type or APN"
return 1
fi
while [ $retry_count -lt $max_retries ]; do
result=$(execute_at_command "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0")
if [ $? -eq 0 ]; then
log_message "INFO" "Successfully set APN: $apn with PDP type: $pdp_type"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to set APN: $apn after $max_retries attempts"
return 1
}
# Load configuration
if [ -f /etc/quecmanager/apn_profile/apn_config.txt ]; then
. /etc/quecmanager/apn_profile/apn_config.txt
log_message "INFO" "Loaded configuration - Profile1 ICCID: ${iccidProfile1}, Profile2 ICCID: ${iccidProfile2:-none}"
else
log_message "ERROR" "Configuration file not found"
echo "Configuration file not found" > /tmp/apn_result.txt
exit 1
fi
# Get current ICCID and trim any whitespace
current_iccid=$(get_current_iccid | tr -d '[:space:]')
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current ICCID"
echo "Failed to get current ICCID" > /tmp/apn_result.txt
exit 1
fi
# Trim any whitespace from profile ICCIDs
iccidProfile1=$(echo "${iccidProfile1}" | tr -d '[:space:]')
[ -n "$iccidProfile2" ] && iccidProfile2=$(echo "${iccidProfile2}" | tr -d '[:space:]')
# Log the comparison values
log_message "INFO" "Comparing ICCIDs:"
log_message "INFO" "Current ICCID: ${current_iccid}"
log_message "INFO" "Profile1 ICCID: ${iccidProfile1}"
[ -n "$iccidProfile2" ] && log_message "INFO" "Profile2 ICCID: ${iccidProfile2}"
# Match ICCID and apply corresponding profile
if [ "${current_iccid}" = "${iccidProfile1}" ]; then
log_message "INFO" "Matched with Profile1, applying settings..."
if set_apn "$pdpType1" "$apnProfile1"; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
elif [ -n "$iccidProfile2" ] && [ "${current_iccid}" = "${iccidProfile2}" ]; then
log_message "INFO" "Matched with Profile2, applying settings..."
if set_apn "$pdpType2" "$apnProfile2"; then
echo "APN set successfully" > /tmp/apn_result.txt
else
echo "Failed to set APN" > /tmp/apn_result.txt
fi
else
log_message "WARN" "No matching ICCID profile found"
echo "No matching ICCID profile found" > /tmp/apn_result.txt
fi
EOF
# Make the script executable
chmod 755 /etc/quecmanager/apn_profile/apnProfiles.sh
# Add to rc.local if not already present
if ! grep -q "^[^#]*\/etc\/quecmanager\/apn_profile\/apnProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/apn_profile/apnProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/apn_profile/apnProfiles.sh
# Check the result
if [ -f /tmp/apn_result.txt ]; then
result=$(cat /tmp/apn_result.txt)
rm -f /tmp/apn_result.txt
case "$result" in
"APN set successfully")
echo '{"status": "success", "message": "APN profiles saved and applied successfully"}'
;;
"No matching ICCID profile found")
echo '{"status": "warning", "message": "APN profiles saved but no matching ICCID found"}'
;;
"Configuration file not found")
echo '{"status": "error", "message": "Configuration file not found"}'
;;
"Failed to get current ICCID")
echo '{"status": "error", "message": "Failed to get current ICCID"}'
;;
*)
echo '{"status": "error", "message": "APN profiles saved but failed to apply"}'
;;
esac
else
echo '{"status": "error", "message": "Something went wrong while processing APN profiles"}'
fi

View File

@@ -1,66 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error flag
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Remove the entire quecmanager directory
if [ -d "/etc/quecmanager/imei_profile/" ]; then
rm -rf /etc/quecmanager/imei_profile/
if [ $? -ne 0 ]; then
append_error "Failed to remove quecmanager directory"
fi
else
append_error "quecmanager directory not found"
fi
# Remove the line from rc.local
if [ -f "/etc/rc.local" ]; then
# Create a temporary file
temp_file=$(mktemp)
# Remove the imeiProfiles.sh line and copy to temp file
sed '/\/etc\/quecmanager\/imeiProfiles.sh/d' /etc/rc.local > "$temp_file"
# Check if sed command was successful
if [ $? -eq 0 ]; then
# Replace original file with modified version
mv "$temp_file" /etc/rc.local
if [ $? -ne 0 ]; then
append_error "Failed to update rc.local"
fi
else
append_error "Failed to modify rc.local"
rm -f "$temp_file"
fi
else
append_error "rc.local file not found"
fi
# Remove temporary files that might have been created
rm -f /tmp/imei_result.txt
rm -f /tmp/debug.log
rm -f /tmp/inputICCID.txt
rm -f /tmp/outputICCID.txt
rm -f /tmp/inputIMEI.txt
rm -f /tmp/outputIMEI.txt
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"IMEI profiles and configuration successfully removed\"}"
fi

View File

@@ -1,39 +0,0 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
CONFIG_FILE="/etc/quecmanager/imei_profile/imei_config.txt"
if [ ! -f "$CONFIG_FILE" ]; then
echo "{}"
exit 0
fi
# Read the configuration file
iccidProfile1=$(grep "^iccidProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile1=$(grep "^imeiProfile1=" "$CONFIG_FILE" | cut -d'=' -f2)
iccidProfile2=$(grep "^iccidProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
imeiProfile2=$(grep "^imeiProfile2=" "$CONFIG_FILE" | cut -d'=' -f2)
# Build the JSON response
echo "{"
# Add Profile 1 if it exists
if [ -n "$iccidProfile1" ]; then
echo " \"profile1\": {"
echo " \"iccid\": \"$iccidProfile1\","
echo " \"imei\": \"$imeiProfile1\""
echo " }"
# Add comma if Profile 2 exists
[ -n "$iccidProfile2" ] && echo " ,"
fi
# Add Profile 2 if it exists
if [ -n "$iccidProfile2" ]; then
echo " \"profile2\": {"
echo " \"iccid\": \"$iccidProfile2\","
echo " \"imei\": \"$imeiProfile2\""
echo " }"
fi
echo "}"

View File

@@ -1,333 +0,0 @@
#!/bin/sh
# Parse POST data (using busybox compatible method)
read -r QUERY_STRING
# Function to urldecode (busybox compatible version)
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
imeiProfile1=$(urldecode "$imeiProfile1")
iccidProfile2=$(urldecode "$iccidProfile2")
imeiProfile2=$(urldecode "$imeiProfile2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$imeiProfile1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Create directory with proper permissions
mkdir -p /etc/quecmanager/imei_profile
chmod 755 /etc/quecmanager/imei_profile
# Create a configuration file to store IMEI profiles
cat > /etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile1=${iccidProfile1}
imeiProfile1=${imeiProfile1}
EOF
# Add second profile only if ICCID is provided
if [ -n "$iccidProfile2" ]; then
cat >> /etc/quecmanager/imei_profile/imei_config.txt <<EOF
iccidProfile2=${iccidProfile2}
imeiProfile2=${imeiProfile2}
EOF
fi
chmod 644 /etc/quecmanager/imei_profile/imei_config.txt
# Create the imeiProfiles.sh script with proper locking mechanism and logging
cat > /etc/quecmanager/imei_profile/imeiProfiles.sh <<'EOF'
#!/bin/sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/imei_profiles.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t imei_profiles "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Simplified lock handling with debug
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command without timeout dependency
execute_at_command() {
local command="$1"
local result=""
log_message "DEBUG" "Executing AT command: ${command}"
handle_lock
# Execute command and capture all output
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -ne 0 ]; then
log_message "ERROR" "Command failed with status $status: $command"
log_message "ERROR" "Command output: $result"
return 1
fi
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
}
# Get current ICCID with enhanced debug
get_current_iccid() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current ICCID"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "ICCID attempt ${retry_count}"
result=$(execute_at_command "AT+ICCID")
local cmd_status=$?
log_message "DEBUG" "AT+ICCID command returned status: ${cmd_status}"
log_message "DEBUG" "AT+ICCID raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
local iccid=$(echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]')
log_message "INFO" "Retrieved current ICCID: ${iccid}"
echo "${iccid}"
return 0
else
log_message "WARN" "Attempt ${retry_count} failed to get valid ICCID"
log_message "WARN" "Result: ${result}"
fi
retry_count=$((retry_count + 1))
if [ $retry_count -lt $max_retries ]; then
log_message "INFO" "Waiting 2 seconds before retry"
sleep 2
fi
done
log_message "ERROR" "Failed to get ICCID after $max_retries attempts"
return 1
}
# Get current IMEI with enhanced debug
get_current_imei() {
local result
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to get current IMEI"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "IMEI attempt ${retry_count}"
result=$(execute_at_command "AT+CGSN")
local cmd_status=$?
log_message "DEBUG" "AT+CGSN command returned status: ${cmd_status}"
log_message "DEBUG" "AT+CGSN raw output: ${result}"
if [ $cmd_status -eq 0 ]; then
local imei=$(echo "$result" | grep -v "AT+CGSN" | grep -v "OK" | tr -d '\r\n[:space:]')
if [ -n "$imei" ]; then
log_message "INFO" "Retrieved current IMEI: ${imei}"
echo "${imei}"
return 0
fi
fi
log_message "WARN" "Attempt ${retry_count} failed to get valid IMEI"
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to get IMEI after $max_retries attempts"
return 1
}
# Set IMEI with enhanced debug
set_imei() {
local imei="$1"
local retry_count=0
local max_retries=3
log_message "INFO" "Attempting to set IMEI: ${imei}"
while [ $retry_count -lt $max_retries ]; do
log_message "DEBUG" "IMEI set attempt ${retry_count}"
result=$(execute_at_command "AT+EGMR=1,7,\"$imei\";+QPOWD=1")
local cmd_status=$?
log_message "DEBUG" "AT+EGMR command returned status: ${cmd_status}"
log_message "DEBUG" "AT+EGMR raw output: ${result}"
if [ $cmd_status -eq 0 ] && echo "$result" | grep -q "OK"; then
log_message "INFO" "Successfully set IMEI: ${imei}"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to set IMEI after $max_retries attempts"
return 1
}
# Load configuration
if [ -f /etc/quecmanager/imei_profile/imei_config.txt ]; then
. /etc/quecmanager/imei_profile/imei_config.txt
log_message "INFO" "Loaded configuration - Profile1 ICCID: ${iccidProfile1}, IMEI: ${imeiProfile1}"
[ -n "$iccidProfile2" ] && log_message "INFO" "Profile2 ICCID: ${iccidProfile2}, IMEI: ${imeiProfile2}"
else
log_message "ERROR" "Configuration file not found"
echo "Configuration file not found" > /tmp/imei_result.txt
exit 1
fi
# Get current ICCID and IMEI
current_iccid=$(get_current_iccid)
current_imei=$(get_current_imei)
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current ICCID or IMEI"
echo "Failed to get current ICCID or IMEI" > /tmp/imei_result.txt
exit 1
fi
log_message "INFO" "Current ICCID: ${current_iccid}"
log_message "INFO" "Current IMEI: ${current_imei}"
# Match ICCID and apply corresponding profile
if [ "${current_iccid}" = "${iccidProfile1}" ]; then
log_message "INFO" "Matched with Profile1"
if [ "${current_imei}" != "${imeiProfile1}" ]; then
log_message "INFO" "IMEI needs updating for Profile1"
if set_imei "${imeiProfile1}"; then
echo "IMEI set successfully" > /tmp/imei_result.txt
else
echo "Failed to set IMEI" > /tmp/imei_result.txt
fi
else
log_message "INFO" "IMEI already matches Profile1"
echo "IMEI already correct" > /tmp/imei_result.txt
fi
elif [ -n "${iccidProfile2}" ] && [ "${current_iccid}" = "${iccidProfile2}" ]; then
log_message "INFO" "Matched with Profile2"
if [ "${current_imei}" != "${imeiProfile2}" ]; then
log_message "INFO" "IMEI needs updating for Profile2"
if set_imei "${imeiProfile2}"; then
echo "IMEI set successfully" > /tmp/imei_result.txt
else
echo "Failed to set IMEI" > /tmp/imei_result.txt
fi
else
log_message "INFO" "IMEI already matches Profile2"
echo "IMEI already correct" > /tmp/imei_result.txt
fi
else
log_message "WARN" "No matching ICCID profile found"
echo "No matching ICCID profile found" > /tmp/imei_result.txt
fi
EOF
# Make the script executable
chmod 755 /etc/quecmanager/imei_profile/imeiProfiles.sh
# Add to rc.local if not already present
if ! grep -q "^[^#]*\/etc\/quecmanager\/imei_profile\/imeiProfiles.sh" /etc/rc.local; then
sed -i '/^exit 0/i /etc/quecmanager/imei_profile/imeiProfiles.sh' /etc/rc.local
fi
# Run the script immediately
/etc/quecmanager/imei_profile/imeiProfiles.sh
# Check the result
if [ -f /tmp/imei_result.txt ]; then
result=$(cat /tmp/imei_result.txt)
rm -f /tmp/imei_result.txt
case "$result" in
"IMEI set successfully")
echo '{"status": "success", "message": "IMEI profiles saved and applied successfully"}'
;;
"IMEI already correct")
echo '{"status": "success", "message": "IMEI profiles saved, no changes needed"}'
;;
"No matching ICCID profile found")
echo '{"status": "warning", "message": "IMEI profiles saved but no matching ICCID found"}'
;;
"Configuration file not found")
echo '{"status": "error", "message": "Configuration file not found"}'
;;
"Failed to get current ICCID or IMEI")
echo '{"status": "error", "message": "Failed to get current ICCID or IMEI"}'
;;
*)
echo '{"status": "error", "message": "IMEI profiles saved but failed to apply"}'
;;
esac
else
echo '{"status": "error", "message": "Something went wrong while processing IMEI profiles"}'
fi

View File

@@ -1,111 +0,0 @@
#!/bin/sh
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
QUEUE_FILE="/tmp/at_pipe.txt"
RESULT_FILE="/tmp/qscan_result.json"
WORKER_SCRIPT="/www/cgi-bin/experimental/cell_scanner/cell_scan_worker.sh"
PID_FILE="/tmp/cell_scan.pid"
CELL_SCAN_KEYWORD="CELL_SCAN"
# Function to log messages
log_message() {
logger -t cell_scan "$1"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
log_message "Sending response: status=$status, message=$message"
printf '{"status":"%s","message":"%s"}\n' "$status" "$message"
exit 0
}
# Function to check if worker is running
check_worker_running() {
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
log_message "Worker process $pid is running"
return 0
fi
log_message "Removing stale PID file for process $pid"
rm -f "$PID_FILE"
fi
return 1
}
# Function to wait for queue to be ready
wait_for_queue() {
local retries=0
while [ ! -f "$QUEUE_FILE" ] && [ $retries -lt 10 ]; do
touch "$QUEUE_FILE" 2>/dev/null || {
log_message "Waiting for queue file to be available (attempt $retries)"
sleep 1
retries=$((retries + 1))
continue
}
chmod 666 "$QUEUE_FILE" 2>/dev/null
log_message "Queue file created and permissions set"
break
done
}
# Function to add scan entry to queue
add_scan_entry() {
# Wait for queue file to exist
wait_for_queue
local entry
entry=$(printf '{"command":"%s","id":"%s","pid":"%s","timestamp":"%s","priority":"high","status":"queued"}\n' \
"$CELL_SCAN_KEYWORD" \
"cell_scan_$$" \
"$$" \
"$(date '+%H:%M:%S')")
echo "$entry" >> "$QUEUE_FILE"
log_message "Added scan entry to queue: $entry"
# Verify entry was added
if ! grep -q "\"pid\":\"$$\"" "$QUEUE_FILE"; then
log_message "Failed to verify scan entry in queue"
return 1
fi
sync
return 0
}
# Ensure worker script is executable
chmod +x "$WORKER_SCRIPT" 2>/dev/null
log_message "Ensured worker script is executable"
# Main execution
{
# If scan is running, return running status
if check_worker_running; then
output_json "running" "Cell scan is in progress"
fi
# Start new scan
rm -f "$RESULT_FILE"
log_message "Starting new worker script: $WORKER_SCRIPT"
# Add scan entry to queue before starting worker
if ! add_scan_entry; then
log_message "Failed to add scan entry to queue"
output_json "error" "Failed to acquire queue lock"
fi
sh "$WORKER_SCRIPT" >/tmp/cell_scan_worker.log 2>&1 &
log_message "Worker script started with PID $!"
output_json "running" "Started new cell scan"
} || {
# Error handler
log_message "Script failed with error"
output_json "error" "Internal error occurred"
}

View File

@@ -1,104 +0,0 @@
# Modified cell_scan_worker.sh
#!/bin/sh
# Configuration
QUEUE_FILE="/tmp/at_pipe.txt"
RESULT_FILE="/tmp/qscan_result.json"
PID_FILE="/tmp/cell_scan.pid"
CELL_SCAN_KEYWORD="CELL_SCAN"
SCAN_COMMAND="AT+QSCAN=3,1"
SCAN_TIMEOUT=200
# Function to log messages
log_message() {
logger -t cell_scan_worker "$1"
}
# Function to clean AT command output
clean_output() {
while IFS= read -r line; do
case "$line" in
"OK" | "" | *"ERROR"*)
continue
;;
*)
printf '%s\n' "$line"
;;
esac
done | sed 's/\r//g' | tr '\n' '\r' | sed 's/\r$//' | tr '\r' '\n'
}
# Function to check if scan is already running
check_running() {
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
return 0
fi
rm -f "$PID_FILE"
fi
return 1
}
# Function to remove scan entry
remove_scan_entry() {
if [ -f "$QUEUE_FILE" ]; then
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
sync
fi
if [ -f "$PID_FILE" ]; then
rm -f "$PID_FILE"
fi
log_message "Scan entry and PID file removed"
}
# Main execution
main() {
# Start logging
log_message "Worker script started"
# Check if already running
if check_running; then
log_message "Cell scan already running"
exit 1
fi
# Create PID file
echo "$$" >"$PID_FILE"
chmod 666 "$PID_FILE" 2>/dev/null
log_message "Created PID file: $$"
# Execute scan with timeout and process output
log_message "Executing scan command: $SCAN_COMMAND"
SCAN_OUTPUT=$(timeout $SCAN_TIMEOUT sms_tool at "$SCAN_COMMAND" -t $SCAN_TIMEOUT 2>&1 | clean_output)
SCAN_STATUS=$?
# Process and store result
if [ $SCAN_STATUS -eq 0 ] && [ -n "$SCAN_OUTPUT" ]; then
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
printf '{"status":"success","timestamp":"%s","output":"%s"}\n' \
"$TIMESTAMP" \
"$(printf '%s' "$SCAN_OUTPUT" | jq -R -s '.')" >"$RESULT_FILE"
chmod 666 "$RESULT_FILE" 2>/dev/null
log_message "Scan completed successfully"
remove_scan_entry
exit 0
else
log_message "Scan failed with status: $SCAN_STATUS"
printf '{"status":"error","timestamp":"%s","message":"Scan failed"}\n' \
"$(date '+%Y-%m-%d %H:%M:%S')" >"$RESULT_FILE"
chmod 666 "$RESULT_FILE" 2>/dev/null
remove_scan_entry
exit 1
fi
}
# Execute main function with proper error handling
{
main
} || {
log_message "Script failed with error"
remove_scan_entry
exit 1
}

View File

@@ -1,60 +0,0 @@
#!/bin/sh
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
RESULT_FILE="/tmp/qscan_result.json"
PID_FILE="/tmp/cell_scan.pid"
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
if [ "$status" = "success" ] && [ -f "$RESULT_FILE" ]; then
# Remove trailing quotes from output field and clean up formatting
sed 's/"output":""/"output":"/; s/""}/"}/' "$RESULT_FILE"
else
printf '{"status":"%s","message":"%s","timestamp":"","output":""}\n' "$status" "$message"
fi
}
# Check if a scan is already in progress
check_scan_progress() {
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
output_json "running" "Scan in progress"
exit 0
else
rm -f "$PID_FILE"
fi
fi
}
# Check for existing results
check_results() {
if [ -f "$RESULT_FILE" ]; then
output_json "success" "Scan results available"
exit 0
fi
}
# Main execution
{
# First check if a scan is in progress
check_scan_progress
# Then check for existing results
check_results
# If no results and no running scan, indicate idle state
output_json "idle" "No active scan"
exit 0
} || {
# Error handler
output_json "error" "Failed to check scan status"
exit 1
}

View File

@@ -1,200 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define file paths and configuration
QUEUE_FILE="/tmp/at_pipe.txt"
TEMP_FILE="/tmp/network_info_output.txt"
LOG_FILE="/var/log/network_info.log"
LOCK_KEYWORD="AT_COMMAND_LOCK"
MAX_WAIT=6
COMMAND_TIMEOUT=4
# Function to log messages
log_message() {
echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "${LOG_FILE}"
logger -t network_info "$1"
}
# Function to output JSON error
output_error() {
printf '{"status":"error","message":"%s","timestamp":"%s"}\n' "$1" "$(date '+%H:%M:%S')"
exit 1
}
# Function to clean and add lock
add_clean_lock() {
local TIMESTAMP=$(date +%s)
local WAIT_START=$(date +%s)
while true; do
local CURRENT_TIME=$(date +%s)
if [ $((CURRENT_TIME - WAIT_START)) -ge $MAX_WAIT ]; then
sed -i "/${LOCK_KEYWORD}/d" "$QUEUE_FILE"
log_message "Removed existing lock after $MAX_WAIT seconds timeout"
fi
printf '{"id":"%s","timestamp":"%s","command":"%s","status":"lock","pid":"%s","start_time":"%s","priority":"high"}\n' \
"${LOCK_KEYWORD}" \
"$(date '+%H:%M:%S')" \
"${LOCK_KEYWORD}" \
"$$" \
"$TIMESTAMP" >> "$QUEUE_FILE"
if grep -q "\"pid\":\"$$\".*\"start_time\":\"$TIMESTAMP\"" "$QUEUE_FILE"; then
log_message "Lock created by PID $$ at $TIMESTAMP"
trap 'remove_lock; exit' INT TERM EXIT
return 0
fi
if [ $((CURRENT_TIME - WAIT_START)) -lt $MAX_WAIT ]; then
sleep 1
else
log_message "Failed to acquire lock after $MAX_WAIT seconds"
return 1
fi
done
}
# Function to remove lock
remove_lock() {
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
log_message "Lock removed by PID $$"
}
# Function to execute AT command with retries
execute_at_command() {
local CMD="$1"
local RETRY_COUNT=0
local MAX_RETRIES=3
local OUTPUT=""
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
OUTPUT=$(timeout $COMMAND_TIMEOUT sms_tool at "$CMD" -D 2>&1)
local EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
if echo "$OUTPUT" | grep -q "CME ERROR"; then
RETRY_COUNT=$((RETRY_COUNT + 1))
[ $RETRY_COUNT -lt $MAX_RETRIES ] && sleep 1
continue
fi
echo "$OUTPUT"
return 0
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
[ $RETRY_COUNT -lt $MAX_RETRIES ] && sleep 1
done
log_message "Command failed after $MAX_RETRIES attempts: $CMD"
return 1
}
# Function to check network mode
check_network_mode() {
local OUTPUT=$(execute_at_command "AT+QENG=\"servingcell\"")
echo "$OUTPUT" > "$TEMP_FILE"
# Check for both LTE and NR5G-NSA (NSA mode)
if echo "$OUTPUT" | grep -q "\"LTE\"" && echo "$OUTPUT" | grep -q "\"NR5G-NSA\""; then
echo "NRLTE"
# Check for LTE only
elif echo "$OUTPUT" | grep -q "\"LTE\""; then
echo "LTE"
# Check for NR5G-SA
elif echo "$OUTPUT" | grep -q "\"NR5G-SA\""; then
echo "NR5G"
else
echo "UNKNOWN"
fi
}
# Function to check NR5G measurement info setting
check_nr5g_meas_info() {
local OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
if echo "$OUTPUT" | grep -q "\"nr5g_meas_info\",1"; then
return 0
else
return 1
fi
}
# Function to escape JSON string
escape_json_string() {
echo "$1" | sed 's/\\/\\\\/g' | sed 's/"/\\"/g' | tr -d '\n' | sed 's/\r//g'
}
# Function to parse and format output as JSON
format_output_json() {
local MODE="$1"
local NEIGHBOR_OUTPUT="$2"
local MEAS_OUTPUT="$3"
# Basic JSON structure
printf '{"status":"success","timestamp":"%s","mode":"%s","data":{' "$(date '+%H:%M:%S')" "$MODE"
# Add neighbor cell info if available
if [ -n "$NEIGHBOR_OUTPUT" ]; then
printf '"neighborCells":"%s"' "$(escape_json_string "$NEIGHBOR_OUTPUT")"
fi
# Add measurement info if available
if [ -n "$MEAS_OUTPUT" ]; then
[ -n "$NEIGHBOR_OUTPUT" ] && printf ','
printf '"meas":"%s"' "$(escape_json_string "$MEAS_OUTPUT")"
fi
printf '}}\n'
}
# Main execution
{
if ! add_clean_lock; then
output_error "Failed to acquire lock for command processing"
fi
# Check network mode
NETWORK_MODE=$(check_network_mode)
log_message "Detected network mode: $NETWORK_MODE"
SERVING_OUTPUT=""
MEAS_OUTPUT=""
case "$NETWORK_MODE" in
"NRLTE")
SERVING_OUTPUT=$(execute_at_command "AT+QENG=\"neighbourcell\"")
if ! check_nr5g_meas_info; then
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\",1;+QNWCFG=\"nr5g_meas_info\"")
else
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
fi
;;
"LTE")
SERVING_OUTPUT=$(execute_at_command "AT+QENG=\"neighbourcell\"")
;;
"NR5G")
if ! check_nr5g_meas_info; then
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\",1;+QNWCFG=\"nr5g_meas_info\"")
else
MEAS_OUTPUT=$(execute_at_command "AT+QNWCFG=\"nr5g_meas_info\"")
fi
;;
*)
output_error "Unknown or unsupported network mode"
;;
esac
format_output_json "$NETWORK_MODE" "$SERVING_OUTPUT" "$MEAS_OUTPUT"
remove_lock
rm -f "$TEMP_FILE"
} || {
# Error handler
remove_lock
rm -f "$TEMP_FILE"
output_error "Internal error occurred"
}

View File

@@ -1,61 +0,0 @@
#!/bin/sh
# Configuration and log directories
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Log directory for cleaning process
CLEANUP_LOG_FILE="${LOG_DIR}/cleanup.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Function to log cleanup events
log_cleanup() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "${CLEANUP_LOG_FILE}"
}
# Default response headers
echo "Content-type: application/json"
echo ""
# Cleanup function
cleanup_quecwatch() {
# Start logging cleanup process
log_cleanup "Starting QuecWatch cleanup process"
# Stop any running QuecWatch processes
log_cleanup "Stopping QuecWatch processes"
pkill -f "${QUECWATCH_SCRIPT}" >> "${CLEANUP_LOG_FILE}" 2>&1
# Remove QuecWatch script from rc.local
if [ -f "${RCLOCAL}" ]; then
log_cleanup "Removing QuecWatch entries from rc.local"
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' "${RCLOCAL}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove configuration directory
if [ -d "${CONFIG_DIR}" ]; then
log_cleanup "Removing configuration directory: ${CONFIG_DIR}"
rm -rf "${CONFIG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
# Remove log directory
if [ -d "${LOG_DIR}" ]; then
log_cleanup "Removing log directory: ${LOG_DIR}"
rm -rf "${LOG_DIR}" >> "${CLEANUP_LOG_FILE}" 2>&1
fi
log_cleanup "QuecWatch cleanup completed successfully"
# Optional: Output JSON response
echo '{"status": "success", "message": "QuecWatch disabled and removed"}'
}
# Execute cleanup
cleanup_quecwatch
exit 0

View File

@@ -1,439 +0,0 @@
#!/bin/sh
# Read POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
echo -e "$(echo "$1" | sed 's/+/ /g;s/%\([0-9A-F][0-9A-F]\)/\\x\1/g')"
}
# Configuration directory
CONFIG_DIR="/etc/quecmanager/quecwatch"
QUECWATCH_CONFIG="${CONFIG_DIR}/quecwatch.conf"
QUECWATCH_SCRIPT="${CONFIG_DIR}/quecwatch.sh"
RCLOCAL="/etc/rc.local"
LOG_DIR="/tmp/log/quecwatch"
DEBUG_LOG_FILE="${LOG_DIR}/debug.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
# Extract values from POST data
action=$(echo "$QUERY_STRING" | grep -o 'action=[^&]*' | cut -d= -f2)
ping_target=$(echo "$QUERY_STRING" | grep -o 'ping_target=[^&]*' | cut -d= -f2)
ping_interval=$(echo "$QUERY_STRING" | grep -o 'ping_interval=[^&]*' | cut -d= -f2)
ping_failures=$(echo "$QUERY_STRING" | grep -o 'ping_failures=[^&]*' | cut -d= -f2)
max_retries=$(echo "$QUERY_STRING" | grep -o 'max_retries=[^&]*' | cut -d= -f2)
connection_refresh=$(echo "$QUERY_STRING" | grep -o 'connection_refresh=[^&]*' | cut -d= -f2)
auto_sim_failover=$(echo "$QUERY_STRING" | grep -o 'auto_sim_failover=[^&]*' | cut -d= -f2)
sim_failover_schedule=$(echo "$QUERY_STRING" | grep -o 'sim_failover_schedule=[^&]*' | cut -d= -f2)
# URL decode the values
action=$(urldecode "$action")
ping_target=$(urldecode "$ping_target")
ping_interval=$(urldecode "$ping_interval")
ping_failures=$(urldecode "$ping_failures")
max_retries=$(urldecode "$max_retries")
connection_refresh=$(urldecode "$connection_refresh")
auto_sim_failover=$(urldecode "$auto_sim_failover")
sim_failover_schedule=$(urldecode "$sim_failover_schedule")
# Default response headers
echo "Content-type: application/json"
echo ""
# Validate inputs
if [ -z "$ping_target" ]; then
echo '{"status": "error", "message": "Ping target is required"}'
exit 1
fi
# Initialize configuration function
initialize_config() {
# Create config directory if not exists
mkdir -p "${CONFIG_DIR}"
# Write configuration with defaults and user-provided values
cat >"${QUECWATCH_CONFIG}" <<EOL
# QuecWatch Configuration File
# Ping Target (IP or domain to ping)
PING_TARGET=${ping_target}
# Interval between ping checks (in seconds)
PING_INTERVAL=${ping_interval:-30}
# Number of consecutive ping failures before taking action
PING_FAILURES=${ping_failures:-3}
# Maximum number of retry attempts
MAX_RETRIES=${max_retries:-5}
# Current retry count (should start at 0)
CURRENT_RETRIES=0
# Enable/Disable Connection Refresh
CONNECTION_REFRESH=${connection_refresh:-false}
# Number of connection refresh attempts
REFRESH_COUNT=${connection_refresh:+3}
# Enable/Disable Auto SIM Failover
AUTO_SIM_FAILOVER=${auto_sim_failover:-false}
# Schedule for checking initial SIM (in minutes)
# 0 means no scheduled check
SIM_FAILOVER_SCHEDULE=${sim_failover_schedule:-0}
# Indicate that QuecWatch is enabled
ENABLED=true
EOL
chmod 644 "${QUECWATCH_CONFIG}"
}
# Generate monitoring script function
generate_monitoring_script() {
cat >"${QUECWATCH_SCRIPT}" <<'EOL'
#!/bin/sh
# Load configuration
. /etc/quecmanager/quecwatch/quecwatch.conf
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Function to persist retry count to a more permanent location
persist_retry_count() {
local count=$1
echo "$count" > /etc/quecmanager/quecwatch/retry_count
}
# Function to load persisted retry count
load_retry_count() {
if [ -f /etc/quecmanager/quecwatch/retry_count ]; then
cat /etc/quecmanager/quecwatch/retry_count
else
echo "0"
fi
}
# Enhanced logging function with debug level
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t quecwatch "${level}: ${message}"
}
# Check for stale entries and clean them
check_and_clean_stale() {
local command_type="$1"
local wait_count=0
while [ $wait_count -lt 6 ]; do
if grep -q "\"command\":\"${command_type}\"" "$QUEUE_FILE"; then
log_message "DEBUG" "Waiting for ${command_type} to clear (attempt ${wait_count})"
sleep 1
wait_count=$((wait_count + 1))
else
return 0
fi
done
log_message "WARN" "Removing stale ${command_type} entry after ${wait_count}s"
sed -i "/\"command\":\"${command_type}\"/d" "$QUEUE_FILE"
return 0
}
# Handle lock with debug logging
handle_lock() {
log_message "DEBUG" "Checking queue file status before lock"
if [ -f "$QUEUE_FILE" ]; then
log_message "DEBUG" "Current queue content: $(cat $QUEUE_FILE)"
else
log_message "DEBUG" "Queue file does not exist, creating it"
touch "$QUEUE_FILE"
fi
check_and_clean_stale "FETCH_LOCK"
log_message "DEBUG" "Adding AT_COMMAND entry to queue"
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' \
"$$" \
"$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
check_and_clean_stale "AT_COMMAND"
}
# Execute AT command with enhanced error handling
execute_at_command() {
local command="$1"
local result=""
local retry_count=0
local max_retries=3
log_message "DEBUG" "Executing AT command: ${command}"
while [ $retry_count -lt $max_retries ]; do
handle_lock
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
log_message "DEBUG" "Removing our entry from queue"
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -eq 0 ] && [ -n "$result" ]; then
log_message "DEBUG" "Command successful. Output: $result"
echo "$result"
return 0
fi
log_message "WARN" "Command failed (attempt $((retry_count + 1))): $result"
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Command failed after $max_retries attempts: $command"
return 1
}
# Function to update retry count in config and persistent storage
update_retry_count() {
local new_retry_count=$1
# Update the persistent count file
persist_retry_count "$new_retry_count"
# Update the config file
sed -i "s/CURRENT_RETRIES=[0-9]*/CURRENT_RETRIES=${new_retry_count}/" /etc/quecmanager/quecwatch/quecwatch.conf
# Reload config to ensure latest values
. /etc/quecmanager/quecwatch/quecwatch.conf
}
# Function to get current SIM slot with enhanced error handling
get_current_sim() {
local output
local retry_count=0
local max_retries=3
while [ $retry_count -lt $max_retries ]; do
output=$(execute_at_command "AT+QUIMSLOT?")
if [ $? -eq 0 ] && echo "$output" | grep -q "+QUIMSLOT:"; then
echo "$output" | grep "+QUIMSLOT:" | awk '{print $2}'
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
log_message "ERROR" "Failed to get current SIM slot after $max_retries attempts"
return 1
}
# Function to switch SIM card with enhanced error handling
switch_sim_card() {
log_message "INFO" "Attempting to switch SIM card"
# Get current SIM slot
current_sim_slot=$(get_current_sim)
if [ $? -ne 0 ]; then
log_message "ERROR" "Failed to get current SIM slot"
return 1
fi
# Toggle between SIM slots
new_sim_slot=$((current_sim_slot % 2 + 1))
log_message "INFO" "Switching from SIM slot ${current_sim_slot} to SIM slot ${new_sim_slot}"
if ! execute_at_command "AT+QUIMSLOT=${new_sim_slot}"; then
log_message "ERROR" "Failed to switch to SIM slot ${new_sim_slot}"
return 1
fi
sleep 10 # Allow time for SIM switch and network registration
return 0
}
# Function to check internet connectivity
check_internet() {
ping -c 3 ${PING_TARGET} > /dev/null 2>&1
return $?
}
# Function to perform connection recovery
perform_connection_recovery() {
local recovery_attempted=0
local recovery_successful=0
if [ "${CONNECTION_REFRESH}" = "true" ] && [ "${retry_trigger}" -eq 1 ] && [ "${REFRESH_COUNT}" -gt 0 ]; then
log_message "INFO" "Attempting connection refresh"
if ! execute_at_command "AT+COPS=2"; then
log_message "ERROR" "Failed to detach from network"
return 1
fi
sleep 2
if ! execute_at_command "AT+COPS=0"; then
log_message "ERROR" "Failed to reattach to network"
return 1
fi
sleep 5
if check_internet; then
log_message "INFO" "Connection refresh successful"
recovery_successful=1
return 0
fi
REFRESH_COUNT=$((REFRESH_COUNT - 1))
sed -i "s/REFRESH_COUNT=.*/REFRESH_COUNT=${REFRESH_COUNT}/" /etc/quecmanager/quecwatch/quecwatch.conf
recovery_attempted=1
fi
[ ${recovery_successful} -eq 1 ] && return 0 || return 1
}
# Store initial SIM slot
initial_sim_slot=""
if [ "${AUTO_SIM_FAILOVER}" = "true" ]; then
initial_sim_slot=$(get_current_sim)
if [ $? -eq 0 ]; then
log_message "INFO" "Auto SIM failover enabled. Initial SIM slot: ${initial_sim_slot}"
else
log_message "ERROR" "Failed to get initial SIM slot"
fi
fi
# Main monitoring loop
failure_count=0
retry_trigger=$(load_retry_count)
sim_failover_interval=0
while true; do
if ! check_internet; then
failure_count=$((failure_count + 1))
log_message "INFO" "Ping failed. Failure count: ${failure_count}"
if [ ${failure_count} -ge ${PING_FAILURES} ]; then
failure_count=0
retry_trigger=$((retry_trigger + 1))
update_retry_count ${retry_trigger}
log_message "INFO" "Failure threshold reached. Retry trigger: ${retry_trigger}"
if [ ${retry_trigger} -ge ${MAX_RETRIES} ]; then
if [ "${AUTO_SIM_FAILOVER}" = "true" ]; then
log_message "INFO" "Max retries exhausted. Attempting SIM failover."
if switch_sim_card && check_internet; then
log_message "INFO" "SIM failover successful"
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "ERROR" "SIM failover failed. Updating retry count before reboot."
retry_trigger=$((retry_trigger + 1))
update_retry_count ${retry_trigger}
log_message "INFO" "Updated retry count to ${retry_trigger}. Performing system reboot."
reboot
fi
else
log_message "INFO" "Max retries exhausted. Auto SIM failover disabled. Removing QuecWatch."
# Clean up the retry count file
rm -f /etc/quecmanager/quecwatch/retry_count
# Remove from rc.local and disable
sed -i '\|/etc/quecmanager/quecwatch/quecwatch.sh|d' /etc/rc.local
sed -i 's/ENABLED=true/ENABLED=false/' /etc/quecmanager/quecwatch/quecwatch.conf
reboot
exit 0
fi
else
if perform_connection_recovery; then
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "ERROR" "Recovery failed. Updating retry count before reboot."
retry_trigger=$((retry_trigger + 1))
update_retry_count ${retry_trigger}
log_message "INFO" "Updated retry count to ${retry_trigger}. Performing system reboot."
reboot
fi
fi
fi
else
failure_count=0
retry_trigger=0
update_retry_count 0
log_message "INFO" "Modem is connected to the internet"
if [ "${AUTO_SIM_FAILOVER}" = "true" ] && [ "${SIM_FAILOVER_SCHEDULE}" -gt 0 ]; then
current_sim_slot=$(get_current_sim)
if [ -n "${initial_sim_slot}" ] && [ "${current_sim_slot}" != "${initial_sim_slot}" ]; then
sim_failover_interval=$((sim_failover_interval + 1))
if [ $((sim_failover_interval * PING_INTERVAL)) -ge $((SIM_FAILOVER_SCHEDULE * 60)) ]; then
log_message "INFO" "Scheduled check: Attempting to switch back to initial SIM ${initial_sim_slot}"
if execute_at_command "AT+QUIMSLOT=${initial_sim_slot}"; then
sleep 10
if check_internet; then
log_message "INFO" "Initial SIM restored successfully"
retry_trigger=0
failure_count=0
update_retry_count 0
else
log_message "WARN" "Initial SIM still not working. Switching back to backup SIM."
execute_at_command "AT+QUIMSLOT=${current_sim_slot}"
sleep 10
fi
else
log_message "ERROR" "Failed to switch to initial SIM"
fi
sim_failover_interval=0
fi
fi
fi
fi
sleep ${PING_INTERVAL}
done
EOL
chmod +x "${QUECWATCH_SCRIPT}"
# Run the script
"${QUECWATCH_SCRIPT}" &
}
# Enable QuecWatch
enable_quecwatch() {
initialize_config
generate_monitoring_script
if ! grep -q "${QUECWATCH_SCRIPT}" "${RCLOCAL}"; then
[ -f "${RCLOCAL}" ] || touch "${RCLOCAL}"
chmod +x "${RCLOCAL}"
sed -i '$i'"${QUECWATCH_SCRIPT} &" "${RCLOCAL}"
fi
# Output success JSON
echo '{"status": "success", "message": "QuecWatch enabled", "config": "'${QUECWATCH_CONFIG}'"}'
}
# Log debug information
{
echo "Timestamp: $(date)"
echo "Script Path: $0"
echo "Ping Target: $ping_target"
echo "Ping Interval: $ping_interval"
echo "Ping Failures: $ping_failures"
echo "Max Retries: $max_retries"
echo "Connection Refresh: $connection_refresh"
echo "Auto SIM Failover: $auto_sim_failover"
echo "SIM Failover Schedule: $sim_failover_schedule"
} >>"$DEBUG_LOG_FILE" 2>&1
# Enable QuecWatch
enable_quecwatch
exit 0

View File

@@ -1,79 +0,0 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Configuration file path
CONFIG_FILE="/etc/quecmanager/quecwatch/quecwatch.conf"
# Check if configuration file exists
if [ ! -f "$CONFIG_FILE" ]; then
echo '{"status": "inactive", "message": "QuecWatch is not configured"}'
exit 0
fi
# Function to safely get config value
get_config_value() {
grep "^$1=" "$CONFIG_FILE" | cut -d'=' -f2
}
# Check if QuecWatch is enabled
enabled=$(get_config_value "ENABLED")
if [ "$enabled" != "true" ]; then
echo '{"status": "inactive", "message": "QuecWatch is disabled"}'
exit 0
fi
# Fetch configuration values
ping_target=$(get_config_value "PING_TARGET")
ping_interval=$(get_config_value "PING_INTERVAL")
ping_failures=$(get_config_value "PING_FAILURES")
max_retries=$(get_config_value "MAX_RETRIES")
current_retries=$(get_config_value "CURRENT_RETRIES")
connection_refresh=$(get_config_value "CONNECTION_REFRESH")
refresh_count=$(get_config_value "REFRESH_COUNT")
# New configuration options
mobile_data_reconnect=$(get_config_value "MOBILE_DATA_RECONNECT")
auto_sim_failover=$(get_config_value "AUTO_SIM_FAILOVER")
sim_failover_schedule=$(get_config_value "SIM_FAILOVER_SCHEDULE")
# Default values if not set
mobile_data_reconnect=${mobile_data_reconnect:-false}
auto_sim_failover=${auto_sim_failover:-false}
sim_failover_schedule=${sim_failover_schedule:-30}
# Check monitoring script existence
QUECWATCH_SCRIPT="/etc/quecmanager/quecwatch/quecwatch.sh"
if [ ! -f "$QUECWATCH_SCRIPT" ]; then
echo '{"status": "error", "message": "Monitoring script is missing"}'
exit 0
fi
# Check log file for recent activity
LOG_FILE="/tmp/log/quecwatch/quecwatch.log"
last_log=""
if [ -f "$LOG_FILE" ]; then
last_log=$(tail -n 1 "$LOG_FILE")
fi
# Prepare JSON response
cat <<EOF
{
"status": "active",
"config": {
"pingTarget": "${ping_target}",
"pingInterval": ${ping_interval},
"pingFailures": ${ping_failures},
"maxRetries": ${max_retries},
"currentRetries": ${current_retries},
"connectionRefresh": ${connection_refresh},
"refreshCount": ${refresh_count:-0},
"mobileDataReconnect": ${mobile_data_reconnect},
"autoSimFailover": ${auto_sim_failover},
"simFailoverSchedule": ${sim_failover_schedule}
},
"lastActivity": "${last_log}"
}
EOF

View File

@@ -1,212 +0,0 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define file paths and configuration
QUEUE_FILE="/tmp/at_pipe.txt"
LOCK_KEYWORD="FETCH_DATA_LOCK"
CELL_SCAN_KEYWORD="CELL_SCAN"
CELL_SCAN_WAIT=3 # Wait time for cell scan in seconds
MAX_WAIT=6 # Maximum seconds to wait for lock
# Function to output error in JSON format
output_error() {
printf '{"error": "%s"}\n' "$1"
exit 1
}
# Function to remove cell scan entries after timeout
remove_cell_scan() {
local start_time=$(date +%s)
local has_waited=0
# Wait for cell scan to complete naturally
while [ $has_waited -eq 0 ]; do
if ! grep -q "\"command\":\"$CELL_SCAN_KEYWORD\"" "$QUEUE_FILE"; then
return 0
fi
current_time=$(date +%s)
if [ $((current_time - start_time)) -ge $CELL_SCAN_WAIT ]; then
has_waited=1
else
sleep 1
fi
done
# After wait period, forcibly remove cell scan entries
if grep -q "\"command\":\"$CELL_SCAN_KEYWORD\"" "$QUEUE_FILE"; then
logger -t at_commands "Removing cell scan entry after $CELL_SCAN_WAIT seconds timeout"
sed -i "/${CELL_SCAN_KEYWORD}/d" "$QUEUE_FILE"
sync
fi
}
# Function to clean and add high-priority lock
add_clean_lock() {
local TIMESTAMP=$(date +%s)
local WAIT_START=$(date +%s)
# First, handle any cell scan operations
remove_cell_scan
while true; do
local CURRENT_TIME=$(date +%s)
# After MAX_WAIT seconds, forcibly remove any existing lock
if [ $((CURRENT_TIME - WAIT_START)) -ge $MAX_WAIT ]; then
sed -i "/${LOCK_KEYWORD}/d" "$QUEUE_FILE"
logger -t at_commands "Removed existing lock after $MAX_WAIT seconds timeout"
fi
# Add our lock entry with high priority
printf '{"id":"%s","timestamp":"%s","command":"%s","status":"lock","pid":"%s","start_time":"%s","priority":"high"}\n' \
"${LOCK_KEYWORD}" \
"$(date '+%H:%M:%S')" \
"${LOCK_KEYWORD}" \
"$$" \
"$TIMESTAMP" >> "$QUEUE_FILE"
# Verify our lock was written
if grep -q "\"pid\":\"$$\".*\"start_time\":\"$TIMESTAMP\"" "$QUEUE_FILE"; then
logger -t at_commands "High priority lock created by PID $$ at $TIMESTAMP"
trap 'remove_lock; exit' INT TERM EXIT
return 0
fi
if [ $((CURRENT_TIME - WAIT_START)) -lt $MAX_WAIT ]; then
sleep 1
else
logger -t at_commands "Failed to acquire lock after $MAX_WAIT seconds"
return 1
fi
done
}
# Simple remove lock function that only removes our entry
remove_lock() {
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
logger -t at_commands "Lock removed by PID $$"
}
# Improved JSON string escaping function
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$//'
}
# Enhanced AT command execution with retries
execute_at_command() {
local CMD="$1"
local RETRY_COUNT=0
local MAX_RETRIES=3
local OUTPUT=""
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
OUTPUT=$(sms_tool at "$CMD" -t 4 2>/dev/null)
if [ $? -eq 0 ] && [ -n "$OUTPUT" ]; then
echo "$OUTPUT"
return 0
fi
RETRY_COUNT=$((RETRY_COUNT + 1))
[ $RETRY_COUNT -lt $MAX_RETRIES ] && sleep 1
done
logger -t at_commands "Command failed after $MAX_RETRIES attempts: $CMD"
return 1
}
# Enhanced command processing function
process_commands() {
local commands="$1"
local first=1
printf '['
for cmd in $commands; do
[ $first -eq 0 ] && printf ','
first=0
OUTPUT=$(execute_at_command "$cmd")
local CMD_STATUS=$?
ESCAPED_CMD=$(escape_json "$cmd")
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
if [ $CMD_STATUS -eq 0 ]; then
printf '{"command":"%s","response":"%s","status":"success"}' \
"${ESCAPED_CMD}" \
"${ESCAPED_OUTPUT}"
else
printf '{"command":"%s","response":"Command failed","status":"error"}' \
"${ESCAPED_CMD}"
fi
done
printf ']\n'
}
# Main process wrapper with automatic lock handling
main_with_clean_lock() {
( sleep 60; kill -TERM $$ 2>/dev/null ) &
TIMEOUT_PID=$!
if ! add_clean_lock; then
output_error "Failed to acquire lock for command processing"
kill $TIMEOUT_PID 2>/dev/null
exit 1
fi
process_commands "$COMMANDS"
remove_lock
kill $TIMEOUT_PID 2>/dev/null
}
# Define command sets
define_command_sets() {
COMMAND_SET_1='AT+QUIMSLOT? AT+CNUM AT+COPS? AT+CIMI AT+ICCID AT+CGSN AT+CPIN? AT+CGDCONT? AT+CREG? AT+CFUN? AT+QENG="servingcell" AT+QTEMP AT+CGCONTRDP AT+QCAINFO AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
COMMAND_SET_2='AT+CGDCONT? AT+CGCONTRDP AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QUIMSLOT?'
COMMAND_SET_3='AT+CGMI AT+CGMM AT+QGMR AT+CNUM AT+CIMI AT+ICCID AT+CGSN AT+QMAP="LANIP" AT+QMAP="WWAN" AT+QGETCAPABILITY'
COMMAND_SET_4='AT+QMAP="MPDN_RULE" AT+QMAP="DHCPV4DNS" AT+QCFG="usbnet"'
COMMAND_SET_5='AT+QRSRP AT+QRSRQ AT+QSINR AT+QCAINFO AT+QSPN'
COMMAND_SET_6='AT+CEREG=2;+CEREG? AT+C5GREG=2;+C5GREG? AT+CPIN? AT+CGDCONT? AT+CGCONTRDP AT+QMAP="WWAN" AT+QRSRP AT+QTEMP AT+QNETRC?'
COMMAND_SET_7='AT+QNWPREFCFG="policy_band" AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band"'
COMMAND_SET_8='AT+QNWLOCK="common/4g" AT+QNWLOCK="common/5g" AT+QNWLOCK="save_ctrl"'
}
# Main execution
define_command_sets
# Get command set from query string with validation
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[1-8]' | cut -d'=' -f2 | tr -cd '0-9')
if [ -z "$COMMAND_SET" ] || [ "$COMMAND_SET" -lt 1 ] || [ "$COMMAND_SET" -gt 8 ]; then
COMMAND_SET=1
fi
# Select the appropriate command set
case "$COMMAND_SET" in
1) COMMANDS="$COMMAND_SET_1";;
2) COMMANDS="$COMMAND_SET_2";;
3) COMMANDS="$COMMAND_SET_3";;
4) COMMANDS="$COMMAND_SET_4";;
5) COMMANDS="$COMMAND_SET_5";;
6) COMMANDS="$COMMAND_SET_6";;
7) COMMANDS="$COMMAND_SET_7";;
8) COMMANDS="$COMMAND_SET_8";;
esac
# Execute main process with clean lock handling
main_with_clean_lock

View File

@@ -1,20 +0,0 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Run ethtool on eth0 and capture the output
ethtool_output=$(ethtool eth0)
# Extract Link Speed
speed=$(echo "$ethtool_output" | grep "Speed:" | awk '{print $2}')
# Extract Link Status
link_status=$(echo "$ethtool_output" | grep "Link detected:" | awk '{print $3}')
# Extract Auto-negotiation status
auto_negotiation=$(echo "$ethtool_output" | grep "Auto-negotiation:" | awk '{print $2}')
# Create JSON output
echo "{\"link_speed\": \"$speed\", \"link_status\": \"$link_status\", \"auto_negotiation\": \"$auto_negotiation\"}"

View File

@@ -1,15 +0,0 @@
#!/bin/sh
# Set the content type to JSON
echo "Content-Type: application/json"
echo ""
# Run free command and capture the output, using -b for bytes
free_output=$(free -b)
# Extract memory information using awk
# Skip the header, take the Mem: line, and extract total, used, and available
memory_info=$(echo "$free_output" | awk '/Mem:/ {print "{\"total\": " $2 ", \"used\": " $3 ", \"available\": " $7 "}"}')
# Output the JSON
echo "$memory_info"

View File

@@ -1,11 +0,0 @@
#!/bin/sh
export HOME=/tmp/home
# Create named pipe for speedtest output if it doesn't exist
[ ! -p /tmp/realtime_spd.json ] && mkfifo /tmp/realtime_spd.json
# Run speedtest in background
/usr/bin/speedtest --accept-license -f json -p yes --progress-update-interval=100 > /tmp/realtime_spd.json
# Remove named pipe
rm /tmp/realtime_spd.json

View File

@@ -1,13 +0,0 @@
#!/bin/sh
echo "Content-Type: text/event-stream"
echo "Cache-Control: no-cache"
echo "Connection: keep-alive"
echo ""
# Use cat to read from the FIFO
cat /tmp/realtime_spd.json | while read line; do
echo "data: $line"
echo
sleep 0.1
done

View File

@@ -1,10 +0,0 @@
#!/bin/sh
# /www/cgi-bin/start_speedtest.sh
echo "Content-Type: application/json"
echo ""
# Run speedtest in background
/www/cgi-bin/home/speedtest/speedtest.sh
# Immediately return a success response
echo '{"status":"started"}'

View File

@@ -0,0 +1,266 @@
#!/bin/sh
# AT Queue Client for OpenWRT
# Located in /www/cgi-bin/services/at_queue_client
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager.sh"
POLL_INTERVAL=0.01
usage() {
echo "Usage: $0 [options] <AT command>"
echo "Options:"
echo " -w Wait for command completion"
echo " -t Timeout in seconds (default: 240)"
echo " -h Show this help message"
exit 1
}
# Output JSON response
output_json() {
local content="$1"
local headers="${2:-1}" # Default to showing headers
echo "$content"
}
# URL decode function
urldecode() {
local encoded="$1"
logger -t at_queue -p daemon.debug "urldecode: input='$encoded'"
# Handle %2B -> + and %22 -> " conversions
local decoded="${encoded//%2B/+}"
decoded="${decoded//%22/\"}"
# Then handle other encoded characters
decoded=$(printf '%b' "${decoded//%/\\x}")
logger -t at_queue -p daemon.debug "urldecode: output='$decoded'"
echo "$decoded"
}
# Extract command ID from response with improved error handling
get_command_id() {
local response="$1"
echo "DEBUG: Raw response: '$response'" >&2
# Strip any headers from response
local json_response=$(echo "$response" | sed -n '/^{/,$p')
echo "DEBUG: JSON portion: '$json_response'" >&2
# Try to extract command_id using grep and sed instead of jsonfilter
local cmd_id=$(echo "$json_response" | grep -o '"command_id":"[^"]*"' | sed 's/"command_id":"//;s/"$//')
if [ -n "$cmd_id" ]; then
echo "$cmd_id"
return 0
fi
# Fallback to jsonfilter if available
echo "DEBUG: Trying jsonfilter as fallback" >&2
local cmd_id_jsonfilter=$(echo "$json_response" | jsonfilter -e '@.command_id' 2>/dev/null)
if [ -n "$cmd_id_jsonfilter" ]; then
echo "$cmd_id_jsonfilter"
return 0
fi
echo "ERROR: Failed to extract command ID from response" >&2
return 1
}
# Normalize AT command
normalize_at_command() {
local cmd="$1"
logger -t at_queue -p daemon.debug "normalize: input='$cmd'"
# URL decode the command
cmd=$(urldecode "$cmd")
logger -t at_queue -p daemon.debug "normalize: after urldecode='$cmd'"
# Remove any carriage returns or newlines
cmd=$(echo "$cmd" | tr -d '\r\n')
logger -t at_queue -p daemon.debug "normalize: after cleanup='$cmd'"
# Trim leading/trailing whitespace while preserving quotes
cmd=$(echo "$cmd" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
logger -t at_queue -p daemon.debug "normalize: final output='$cmd'"
echo "$cmd"
}
# Submit command with priority handling
submit_command() {
local cmd="$1"
local priority=10
# Set high priority for QSCAN commands for faster processing
if echo "$cmd" | grep -qi "AT+QSCAN"; then
priority=1
fi
# Submit using appropriate method
if [ "${SCRIPT_NAME}" != "" ]; then
# CGI mode - direct execution
local escaped_cmd=$(echo "$cmd" | sed 's/"/\\"/g')
QUERY_STRING="action=enqueue&command=${escaped_cmd}&priority=$priority" "$QUEUE_MANAGER"
else
# CLI mode
"$QUEUE_MANAGER" enqueue "$cmd" "$priority"
fi
}
# Check if result exists with proper error handling
check_result() {
local cmd_id="$1"
local show_headers="${2:-1}" # Add parameter for header control
if [ -f "$RESULTS_DIR/$cmd_id.json" ]; then
local result_content=$(cat "$RESULTS_DIR/$cmd_id.json")
if [ -z "$result_content" ]; then
logger -t at_queue -p daemon.error "Empty result file for command ID: $cmd_id"
local error_json="{\"error\":\"Empty result file\",\"command_id\":\"$cmd_id\"}"
output_json "$error_json" "$show_headers"
return 1
fi
output_json "$result_content" "$show_headers"
return 0
fi
local error_json="{\"error\":\"Result not found\",\"command_id\":\"$cmd_id\"}"
output_json "$error_json" "$show_headers"
return 1
}
# Wait for command completion with optimized polling and better error handling
wait_for_completion() {
local cmd_id="$1"
local timeout="$2"
local show_headers="${3:-1}"
local result_file="$RESULTS_DIR/$cmd_id.json"
if [ -z "$cmd_id" ]; then
local error_json="{\"error\":\"Invalid command ID\"}"
output_json "$error_json" "$show_headers"
return 1
fi
# First quick check
if [ -f "$result_file" ]; then
output_json "$(cat "$result_file")" "$show_headers"
return 0
fi
# Wait with shorter polling interval
local start_time=$(date +%s)
local current_time
while true; do
if [ -f "$result_file" ]; then
output_json "$(cat "$result_file")" "$show_headers"
return 0
fi
current_time=$(date +%s)
if [ $((current_time - start_time)) -ge "$timeout" ]; then
break
fi
sleep $POLL_INTERVAL
done
local error_json=$(cat << EOF
{
"error": "Timeout waiting for completion",
"command_id": "$cmd_id",
"timeout": $timeout
}
EOF
)
output_json "$error_json" "$show_headers"
return 1
}
# CGI request handling
if [ "${SCRIPT_NAME}" != "" ]; then
# Output headers only once at the beginning
echo "Content-Type: application/json"
echo ""
# Parse query string
eval $(echo "$QUERY_STRING" | sed 's/&/;/g')
# Handle different actions
if [ -n "$command_id" ]; then
# Get result for specific command ID
check_result "$command_id" "0" # Don't show headers
elif [ -n "$command" ]; then
# URL decode and normalize the command
command=$(urldecode "$command")
command=$(normalize_at_command "$command")
# Check if it's a valid AT command
if echo "$command" | grep -qi "^AT"; then
# Submit command and get response
response=$(submit_command "$command")
cmd_id=$(get_command_id "$response")
if [ "$wait" = "1" ]; then
if [ -n "$cmd_id" ]; then
wait_for_completion "$cmd_id" "${timeout:-180}" "0" # Don't show headers
else
output_json "{\"error\":\"Failed to get command ID from response\",\"response\":\"$response\"}" "0"
fi
else
output_json "$response" "0" # Don't show headers
fi
else
output_json "{\"error\":\"Invalid AT command format\"}" "0"
fi
else
output_json "{\"error\":\"No command or command_id specified\"}" "0"
fi
exit 0
fi
# CLI processing
wait_mode=0
timeout=180
while getopts "wt:h" opt; do
case $opt in
w) wait_mode=1 ;;
t) timeout="$OPTARG" ;;
h) usage ;;
?) usage ;;
esac
done
shift $((OPTIND-1))
if [ $# -eq 0 ]; then
usage
fi
# Combine remaining arguments into AT command
command="$*"
# Validate AT command format
if ! echo "$command" | grep -qi "^AT"; then
echo "Error: Command must start with 'AT'"
exit 1
fi
# Submit command and get response
response=$(submit_command "$command")
cmd_id=$(get_command_id "$response")
if [ -z "$cmd_id" ]; then
echo "Error: Failed to get command ID"
echo "Response: $response"
exit 1
fi
if [ $wait_mode -eq 1 ]; then
wait_for_completion "$cmd_id" "$timeout"
else
echo "$response"
fi

View File

@@ -0,0 +1,195 @@
#!/bin/sh
# Set content-type for JSON response
echo "Content-type: application/json"
echo ""
# Define paths and constants to match queue system
QUEUE_DIR="/tmp/at_queue"
QUEUE_MANAGER="/www/cgi-bin/services/at_queue_manager"
LOCK_ID="FETCH_DATA_$(date +%s)_$$"
TOKEN_FILE="$QUEUE_DIR/token"
# Logging function (minimized)
log_message() {
# Only log errors and critical info
if [ "$1" = "error" ] || [ "$1" = "crit" ]; then
logger -t at_queue -p "daemon.$1" "$2"
fi
}
# Enhanced JSON string escaping function
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$//'
}
# Acquire token directly (avoid CGI overhead)
acquire_token() {
local priority="${1:-10}"
local max_attempts=10
local attempt=0
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
rm -f "$TOKEN_FILE" 2>/dev/null
elif [ $priority -lt $current_priority ]; then
# Preempt lower priority token
rm -f "$TOKEN_FILE" 2>/dev/null
else
# Try again
sleep 0.1
attempt=$((attempt + 1))
continue
fi
fi
# Try to create token file
echo "{\"id\":\"$LOCK_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" = "$LOCK_ID" ]; then
return 0
fi
sleep 0.1
attempt=$((attempt + 1))
done
return 1
}
# Release token directly
release_token() {
# Only remove if it's our token
if [ -f "$TOKEN_FILE" ]; then
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
if [ "$current_holder" = "$LOCK_ID" ]; then
rm -f "$TOKEN_FILE" 2>/dev/null
fi
fi
}
# Direct AT command execution with minimal overhead
execute_at_command() {
local CMD="$1"
sms_tool at "$CMD" -t 3 2>/dev/null
}
# Batch process all commands with a single token
process_all_commands() {
local commands="$1"
local priority="${2:-10}"
local first=1
# Acquire a single token for all commands
if ! acquire_token "$priority"; then
log_message "error" "Failed to acquire token for batch processing"
# Return all failed responses
printf '['
first=1
for cmd in $commands; do
[ $first -eq 0 ] && printf ','
first=0
ESCAPED_CMD=$(escape_json "$cmd")
printf '{"command":"%s","response":"Failed to acquire token","status":"error"}' "${ESCAPED_CMD}"
done
printf ']\n'
return 1
fi
# Process all commands with the single token
printf '['
for cmd in $commands; do
[ $first -eq 0 ] && printf ','
first=0
OUTPUT=$(execute_at_command "$cmd")
local CMD_STATUS=$?
ESCAPED_CMD=$(escape_json "$cmd")
ESCAPED_OUTPUT=$(escape_json "$OUTPUT")
if [ $CMD_STATUS -eq 0 ] && [ -n "$OUTPUT" ]; then
printf '{"command":"%s","response":"%s","status":"success"}' \
"${ESCAPED_CMD}" \
"${ESCAPED_OUTPUT}"
else
printf '{"command":"%s","response":"Command failed","status":"error"}' \
"${ESCAPED_CMD}"
fi
done
printf ']\n'
# Release token after all commands are done
release_token
return 0
}
# Main execution with timeout and proper cleanup
trap 'release_token; exit 1' INT TERM
# Command sets
COMMAND_SET_1='AT+QUIMSLOT? AT+CNUM AT+COPS? AT+CIMI AT+ICCID AT+CGSN AT+CPIN? AT+CGDCONT? AT+CREG? AT+CFUN? AT+QENG="servingcell" AT+QTEMP AT+CGCONTRDP AT+QCAINFO AT+QRSRP AT+QMAP="WWAN" AT+C5GREG=2;+C5GREG? AT+CGREG=2;+CGREG? AT+QRSRQ AT+QSINR'
COMMAND_SET_2='AT+CGDCONT? AT+CGCONTRDP AT+QNWPREFCFG="mode_pref" AT+QNWPREFCFG="nr5g_disable_mode" AT+QUIMSLOT? AT+CFUN=?'
COMMAND_SET_3='AT+CGMI AT+CGMM AT+QGMR AT+CNUM AT+CIMI AT+ICCID AT+CGSN AT+QMAP="LANIP" AT+QMAP="WWAN" AT+QGETCAPABILITY'
COMMAND_SET_4='AT+QMAP="MPDN_RULE" AT+QMAP="DHCPV4DNS" AT+QCFG="usbnet"'
COMMAND_SET_5='AT+QRSRP AT+QRSRQ AT+QSINR AT+QCAINFO AT+QSPN'
COMMAND_SET_6='AT+CEREG=2;+CEREG? AT+C5GREG=2;+C5GREG? AT+CPIN? AT+CGDCONT? AT+CGCONTRDP AT+QMAP="WWAN" AT+QRSRP AT+QTEMP AT+QNETRC?'
COMMAND_SET_7='AT+QNWPREFCFG="policy_band" AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band"'
COMMAND_SET_8='AT+QNWLOCK="common/4g" AT+QNWLOCK="common/5g" AT+QNWLOCK="save_ctrl"'
# Get command set from query string with validation
COMMAND_SET=$(echo "$QUERY_STRING" | grep -o 'set=[1-8]' | cut -d'=' -f2 | tr -cd '0-9')
if [ -z "$COMMAND_SET" ] || [ "$COMMAND_SET" -lt 1 ] || [ "$COMMAND_SET" -gt 8 ]; then
COMMAND_SET=1
fi
# Select the appropriate command set
case "$COMMAND_SET" in
1) COMMANDS="$COMMAND_SET_1";;
2) COMMANDS="$COMMAND_SET_2";;
3) COMMANDS="$COMMAND_SET_3";;
4) COMMANDS="$COMMAND_SET_4";;
5) COMMANDS="$COMMAND_SET_5";;
6) COMMANDS="$COMMAND_SET_6";;
7) COMMANDS="$COMMAND_SET_7";;
8) COMMANDS="$COMMAND_SET_8";;
esac
# Set priority based on content
PRIORITY=10
if echo "$COMMANDS" | grep -qi "AT+QSCAN"; then
PRIORITY=1
fi
# Process commands with timeout protection
( sleep 60; kill -TERM $$ 2>/dev/null ) &
TIMEOUT_PID=$!
process_all_commands "$COMMANDS" "$PRIORITY"
# Clean up
kill $TIMEOUT_PID 2>/dev/null
release_token

View File

@@ -0,0 +1,113 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Load UCI functions
. /lib/functions.sh
# Function to safely get UCI value with default
get_uci_value() {
local value
config_get value cell_lock "$1" "$2"
echo "${value:-$2}"
}
# Function to check if daemon is running
check_service_status() {
if [ -f "/var/run/cell_lock_scheduler.pid" ]; then
pid=$(cat /var/run/cell_lock_scheduler.pid 2>/dev/null)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "running"
return
fi
fi
echo "stopped"
}
# Function to get current status with proper JSON handling
get_current_status() {
local STATUS_FILE="/tmp/cell_lock_status.json"
local status="unknown"
local message="Status not available"
local active="0"
local locked="0"
local timestamp=$(date +%s)
if [ -f "$STATUS_FILE" ]; then
# Try to extract values from status file
if grep -q "status" "$STATUS_FILE"; then
status=$(cat "$STATUS_FILE" | jsonfilter -e '@.status' 2>/dev/null)
# Extract message and remove any surrounding quotes
message=$(cat "$STATUS_FILE" | jsonfilter -e '@.message' 2>/dev/null | sed 's/^"//;s/"$//')
active=$(cat "$STATUS_FILE" | jsonfilter -e '@.active' 2>/dev/null)
locked=$(cat "$STATUS_FILE" | jsonfilter -e '@.locked' 2>/dev/null)
timestamp=$(cat "$STATUS_FILE" | jsonfilter -e '@.timestamp' 2>/dev/null)
fi
fi
# Escape quotes and special characters in message
message=$(echo "$message" | sed 's/\\/\\\\/g; s/"/\\"/g')
# Return the status as a JSON object with properly quoted message
echo "{\"status\":\"$status\",\"message\":\"$message\",\"active\":$active,\"locked\":$locked,\"timestamp\":$timestamp}"
}
# Load configuration
config_load quecmanager
# Check if cell lock section exists
if ! uci -q get quecmanager.cell_lock >/dev/null; then
echo '{"status":"inactive","message":"Cell lock is not configured","enabled":false,"startTime":"","endTime":"","active":false,"locked":false}'
exit 0
fi
# Get service status
service_status=$(check_service_status)
# Get current status
current_status=$(get_current_status)
# Get configuration values
enabled=$(get_uci_value "enabled" "0")
start_time=$(get_uci_value "start_time" "")
end_time=$(get_uci_value "end_time" "")
active=$(get_uci_value "active" "0")
lte_params=$(get_uci_value "lte_params" "")
nr5g_params=$(get_uci_value "nr5g_params" "")
lte_persist=$(get_uci_value "lte_persist" "0")
nr5g_persist=$(get_uci_value "nr5g_persist" "0")
# Convert numeric values to boolean for JSON
enabled_bool="false"
active_bool="false"
locked_bool="false"
[ "$enabled" = "1" ] && enabled_bool="true"
[ "$active" = "1" ] && active_bool="true"
# Get locked status from current_status
locked=$(echo "$current_status" | jsonfilter -e '@.locked' 2>/dev/null)
[ "$locked" = "1" ] && locked_bool="true"
# Extract the message properly from current status
message_value=$(echo "$current_status" | jsonfilter -e '@.message' 2>/dev/null | sed 's/^"//;s/"$//')
# Prepare JSON response in format expected by the component
cat <<EOF
{
"enabled": $enabled_bool,
"start_time": "$start_time",
"end_time": "$end_time",
"active": $active_bool,
"status": "$(echo "$current_status" | jsonfilter -e '@.status')",
"message": "$message_value",
"locked": $locked_bool,
"serviceStatus": "$service_status",
"lteParams": "$lte_params",
"nr5gParams": "$nr5g_params",
"ltePersist": "$lte_persist",
"nr5gPersist": "$nr5g_persist"
}
EOF

View File

@@ -0,0 +1,205 @@
#!/bin/sh
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
UCI_CONFIG="quecmanager"
STATUS_FILE="/tmp/cell_lock_status.json"
QUEUE_DIR="/tmp/at_queue"
TOKEN_FILE="$QUEUE_DIR/token"
LOG_DIR="/tmp/log/cell_lock"
LOG_FILE="$LOG_DIR/cell_lock.log"
DEBUG_FILE="$LOG_DIR/debug.log"
# Ensure log directory exists
mkdir -p "$LOG_DIR"
# 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"
# Debug logging
echo "[$timestamp] [$level] $message" >> "$DEBUG_FILE"
# Log to system log
logger -t cell_lock -p "daemon.$level" "$message"
}
# Log request details for debugging
log_request_info() {
echo "==== NEW REQUEST ====" >> "$DEBUG_FILE"
echo "METHOD: $REQUEST_METHOD" >> "$DEBUG_FILE"
echo "QUERY_STRING: $QUERY_STRING" >> "$DEBUG_FILE"
echo "CONTENT_LENGTH: $CONTENT_LENGTH" >> "$DEBUG_FILE"
echo "CONTENT_TYPE: $CONTENT_TYPE" >> "$DEBUG_FILE"
}
# Function to validate time format (HH:MM)
validate_time_format() {
local time="$1"
local name="$2"
if ! echo "$time" | grep -q '^[0-2][0-9]:[0-5][0-9]$'; then
echo "{\"status\":\"error\",\"message\":\"$name must be in format HH:MM (24-hour)\"}"
log_message "$name has invalid format: $time" "error"
return 1
fi
# Further validate hour (00-23)
local hour=$(echo "$time" | cut -d':' -f1)
if [ "$hour" -gt 23 ]; then
echo "{\"status\":\"error\",\"message\":\"Hour in $name must be between 00-23\"}"
log_message "$name has invalid hour: $hour" "error"
return 1
fi
return 0
}
# Log request info for debugging
log_request_info
# Handle GET requests for status
if [ "$REQUEST_METHOD" = "GET" ]; then
log_message "Handling GET request" "debug"
# Load UCI configuration
if [ -f "/etc/config/quecmanager" ]; then
ENABLED=$(uci -q get "$UCI_CONFIG.cell_lock.enabled" || echo "0")
START_TIME=$(uci -q get "$UCI_CONFIG.cell_lock.start_time" || echo "")
END_TIME=$(uci -q get "$UCI_CONFIG.cell_lock.end_time" || echo "")
ACTIVE=$(uci -q get "$UCI_CONFIG.cell_lock.active" || echo "0")
# Convert to JSON boolean format
[ "$ENABLED" = "1" ] && ENABLED="true" || ENABLED="false"
[ "$ACTIVE" = "1" ] && ACTIVE="true" || ACTIVE="false"
# Get current status from status file
STATUS="disabled"
MESSAGE="\"Scheduler is disabled\""
if [ -f "$STATUS_FILE" ]; then
STATUS=$(cat "$STATUS_FILE" | jsonfilter -e '@.status' 2>/dev/null)
MESSAGE=$(cat "$STATUS_FILE" | jsonfilter -e '@.message' 2>/dev/null)
if [ -n "$MESSAGE" ]; then
MESSAGE="\"$MESSAGE\""
else
MESSAGE="\"Status not available\""
fi
fi
# Output JSON response
echo "{\"enabled\":$ENABLED,\"start_time\":\"$START_TIME\",\"end_time\":\"$END_TIME\",\"active\":$ACTIVE,\"status\":\"$STATUS\",\"message\":$MESSAGE}"
log_message "Returned status response" "debug"
else
echo "{\"enabled\":false,\"start_time\":\"\",\"end_time\":\"\",\"active\":false,\"status\":\"unknown\",\"message\":\"Configuration not found\"}"
log_message "No configuration found" "warn"
fi
exit 0
fi
# Handle POST requests for enabling/disabling scheduling
if [ "$REQUEST_METHOD" = "POST" ]; then
log_message "Handling POST request" "debug"
# Read POST data
CONTENT_LENGTH=${CONTENT_LENGTH:-0}
if [ $CONTENT_LENGTH -gt 0 ]; then
POST_DATA=$(dd bs=1 count=$CONTENT_LENGTH 2>/dev/null)
echo "POST_DATA: $POST_DATA" >> "$DEBUG_FILE"
else
POST_DATA=""
echo "No POST_DATA (empty)" >> "$DEBUG_FILE"
fi
# Try to parse JSON data
if [ -n "$POST_DATA" ] && command -v jsonfilter >/dev/null 2>&1; then
log_message "Attempting to parse JSON data" "debug"
# Try to extract values from JSON - allow for differently named fields
ENABLED=$(echo "$POST_DATA" | jsonfilter -e '@.enabled' 2>/dev/null)
if [ -z "$ENABLED" ]; then
ENABLED=$(echo "$POST_DATA" | jsonfilter -e '@.enable' 2>/dev/null)
fi
START_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.startTime' 2>/dev/null)
if [ -z "$START_TIME" ]; then
START_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.start_time' 2>/dev/null)
fi
END_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.endTime' 2>/dev/null)
if [ -z "$END_TIME" ]; then
END_TIME=$(echo "$POST_DATA" | jsonfilter -e '@.end_time' 2>/dev/null)
fi
echo "Parsed JSON: enabled=$ENABLED, start=$START_TIME, end=$END_TIME" >> "$DEBUG_FILE"
# Handle enable/disable logic
if [ "$ENABLED" = "true" ] || [ "$ENABLED" = "1" ]; then
# Validate times for enable request
if [ -z "$START_TIME" ] || [ -z "$END_TIME" ]; then
echo "{\"status\":\"error\",\"message\":\"Start time and end time are required\"}"
log_message "Missing start or end time" "error"
exit 1
fi
# Validate time formats
validate_time_format "$START_TIME" "Start time" || exit 1
validate_time_format "$END_TIME" "End time" || exit 1
# Update configuration
log_message "Enabling scheduling with start=$START_TIME, end=$END_TIME" "info"
uci -q set "$UCI_CONFIG.cell_lock=scheduler"
uci set "$UCI_CONFIG.cell_lock.enabled=1"
uci set "$UCI_CONFIG.cell_lock.start_time=$START_TIME"
uci set "$UCI_CONFIG.cell_lock.end_time=$END_TIME"
uci commit "$UCI_CONFIG"
# Ensure service is running
if [ -x "/etc/init.d/quecmanager_cell_locking" ]; then
/etc/init.d/quecmanager_cell_locking enable
/etc/init.d/quecmanager_cell_locking restart
log_message "Started scheduler service" "info"
else
log_message "Service script not found" "error"
echo "{\"status\":\"error\",\"message\":\"Service script not found\"}"
exit 1
fi
echo "{\"status\":\"success\",\"message\":\"Scheduling enabled\",\"startTime\":\"$START_TIME\",\"endTime\":\"$END_TIME\"}"
log_message "Successfully enabled scheduling" "info"
else
# Disable scheduling
log_message "Disabling scheduling" "info"
uci -q set "$UCI_CONFIG.cell_lock=scheduler"
uci set "$UCI_CONFIG.cell_lock.enabled=0"
uci commit "$UCI_CONFIG"
# Stop service
if [ -x "/etc/init.d/quecmanager_cell_locking" ]; then
/etc/init.d/quecmanager_cell_locking stop
/etc/init.d/quecmanager_cell_locking disable
log_message "Stopped scheduler service" "info"
fi
echo "{\"status\":\"success\",\"message\":\"Scheduling disabled\"}"
log_message "Successfully disabled scheduling" "info"
fi
else
log_message "Failed to parse JSON data or no JSON data received" "error"
echo "{\"status\":\"error\",\"message\":\"Invalid request or missing JSON data\"}"
fi
exit 0
fi
# If no valid method was handled
echo "{\"status\":\"error\",\"message\":\"Invalid request method\"}"
log_message "Invalid request method: $REQUEST_METHOD" "error"
exit 1

View File

@@ -0,0 +1,127 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error tracking
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Function to log cleanup events
log_message() {
local level="$1"
local message="$2"
local LOG_DIR="/tmp/log/apnprofile"
local LOG_FILE="${LOG_DIR}/apnprofile.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t apnprofile "${level}: ${message}"
}
log_message "INFO" "Starting APN Profile cleanup process"
# Stop and disable the service
if [ -f "/etc/init.d/apnprofile-service" ]; then
if /etc/init.d/apnprofile-service stop; then
log_message "INFO" "APN Profile service stopped"
else
append_error "Failed to stop APN Profile service"
log_message "ERROR" "Failed to stop APN Profile service"
fi
if /etc/init.d/apnprofile-service disable; then
log_message "INFO" "APN Profile service disabled"
else
append_error "Failed to disable APN Profile service"
log_message "ERROR" "Failed to disable APN Profile service"
fi
# Remove the init.d script
if rm -f "/etc/init.d/apnprofile-service"; then
log_message "INFO" "Removed init.d script"
else
append_error "Failed to remove init.d script"
log_message "ERROR" "Failed to remove init.d script"
fi
fi
# Remove service script
if [ -f "/www/cgi-bin/services/apnprofile.sh" ]; then
if rm -f "/www/cgi-bin/services/apnprofile.sh"; then
log_message "INFO" "Removed service script"
else
append_error "Failed to remove service script"
log_message "ERROR" "Failed to remove service script"
fi
fi
# Remove symlinks in rc.d if they exist
for link in /etc/rc.d/S??apnprofile-service /etc/rc.d/K??apnprofile-service; do
if [ -L "$link" ]; then
if rm -f "$link"; then
log_message "INFO" "Removed rc.d symlink: $link"
else
append_error "Failed to remove rc.d symlink: $link"
log_message "ERROR" "Failed to remove rc.d symlink: $link"
fi
fi
done
# Remove UCI configuration (only removes apn_profile section, leaves other sections intact)
if uci -q get quecmanager.apn_profile >/dev/null; then
if uci delete quecmanager.apn_profile && uci commit quecmanager; then
log_message "INFO" "Removed UCI configuration"
else
append_error "Failed to remove UCI configuration"
log_message "ERROR" "Failed to remove UCI configuration"
fi
fi
# Kill any remaining processes
if pkill -f "/www/cgi-bin/services/apnprofile.sh"; then
log_message "INFO" "Killed remaining APN Profile processes"
fi
# Clean up temporary files
for file in \
"/tmp/at_pipe.txt" \
"/var/run/apnprofile.pid" \
"/tmp/apn_result.txt" \
"/tmp/debug.log" \
"/tmp/inputICCID.txt" \
"/tmp/outputICCID.txt" \
"/tmp/inputAPN.txt" \
"/tmp/outputAPN.txt"
do
if [ -f "$file" ]; then
if rm -f "$file"; then
log_message "INFO" "Removed temporary file: $file"
else
append_error "Failed to remove temporary file: $file"
log_message "ERROR" "Failed to remove temporary file: $file"
fi
fi
done
log_message "INFO" "APN Profile cleanup completed"
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"APN Profile service successfully removed\"}"
fi

View File

@@ -0,0 +1,144 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Load UCI functions
. /lib/functions.sh
# Function to safely get UCI value with default
get_uci_value() {
local value
config_get value apn_profile "$1" "$2"
echo "${value:-$2}"
}
# Function to check if service is running
check_service_status() {
if [ -f "/var/run/apnprofile.pid" ]; then
pid=$(cat /var/run/apnprofile.pid)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "running"
return
fi
fi
# Double check using process search
if pgrep -f "/www/cgi-bin/services/apnprofile.sh" >/dev/null; then
echo "running"
return
fi
echo "stopped"
}
# Function to get last log entry
get_last_log() {
local LOG_FILE="/tmp/log/apnprofile/apnprofile.log"
if [ -f "$LOG_FILE" ]; then
tail -n 1 "$LOG_FILE"
else
echo "No log entries found"
fi
}
# Function to check if init.d service is enabled
check_service_enabled() {
if [ -f "/etc/init.d/apnprofile-service" ]; then
if /etc/init.d/apnprofile-service enabled; then
echo "true"
return
fi
fi
echo "false"
}
# Load QuecManager configuration
config_load quecmanager
# Check if APN Profile section exists
if ! uci -q get quecmanager.apn_profile >/dev/null; then
echo '{"status": "inactive", "message": "APN Profile service is not configured"}'
exit 0
fi
# Get enabled status from UCI
enabled=$(get_uci_value "enabled" "0")
if [ "$enabled" != "1" ]; then
echo '{"status": "inactive", "message": "APN Profile service is disabled"}'
exit 0
fi
# Check if service script exists
if [ ! -f "/www/cgi-bin/services/apnprofile.sh" ]; then
echo '{"status": "error", "message": "Service script is missing"}'
exit 0
fi
# Get service status information
service_status=$(check_service_status)
service_enabled=$(check_service_enabled)
last_log=$(get_last_log)
# Fetch all configuration values from UCI
iccid_profile1=$(get_uci_value "iccid_profile1" "")
apn_profile1=$(get_uci_value "apn_profile1" "")
pdp_type1=$(get_uci_value "pdp_type1" "")
iccid_profile2=$(get_uci_value "iccid_profile2" "")
apn_profile2=$(get_uci_value "apn_profile2" "")
pdp_type2=$(get_uci_value "pdp_type2" "")
# Function to check if profile data exists
validate_profile_data() {
local iccid="$1"
local apn="$2"
local pdp="$3"
[ -n "$iccid" ] && [ -n "$apn" ] && [ -n "$pdp" ]
}
# Build JSON response
cat <<EOF
{
"status": "active",
"service": {
"status": "${service_status}",
"enabled": ${service_enabled},
"script": "$([ -f "/www/cgi-bin/services/apnprofile.sh" ] && echo "present" || echo "missing")",
"initScript": "$([ -f "/etc/init.d/apnprofile-service" ] && echo "present" || echo "missing")"
},
"profiles": {
EOF
# Add Profile 1 if it exists
if validate_profile_data "$iccid_profile1" "$apn_profile1" "$pdp_type1"; then
cat <<EOF
"profile1": {
"iccid": "${iccid_profile1}",
"apn": "${apn_profile1}",
"pdpType": "${pdp_type1}"
}
EOF
fi
# Add Profile 2 if it exists
if validate_profile_data "$iccid_profile2" "$apn_profile2" "$pdp_type2"; then
# Add comma if Profile 1 was added
[ -n "$iccid_profile1" ] && echo ","
cat <<EOF
"profile2": {
"iccid": "${iccid_profile2}",
"apn": "${apn_profile2}",
"pdpType": "${pdp_type2}"
}
EOF
fi
# Close the profiles object and add last activity
cat <<EOF
},
"lastActivity": "${last_log}"
}
EOF

View File

@@ -0,0 +1,345 @@
#!/bin/sh
# Read POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile1=\([^&]*\).*/\1/p' | tr -d "'")
pdpType1=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
apnProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*apnProfile2=\([^&]*\).*/\1/p' | tr -d "'")
pdpType2=$(echo "$QUERY_STRING" | sed -n 's/.*pdpType2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
apnProfile1=$(urldecode "$apnProfile1")
pdpType1=$(urldecode "$pdpType1")
iccidProfile2=$(urldecode "$iccidProfile2")
apnProfile2=$(urldecode "$apnProfile2")
pdpType2=$(urldecode "$pdpType2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$apnProfile1" ] || [ -z "$pdpType1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Function to log messages
log_message() {
local level="$1"
local message="$2"
local LOG_DIR="/tmp/log/apnprofile"
local LOG_FILE="${LOG_DIR}/apnprofile.log"
mkdir -p "${LOG_DIR}"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t apnprofile "${level}: ${message}"
}
# Create required directories
mkdir -p /www/cgi-bin/services
mkdir -p /etc/init.d
# Function to create service script
create_service_script() {
cat > /www/cgi-bin/services/apnprofile.sh <<'EOL'
#!/bin/sh
# Load UCI functions
. /lib/functions.sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_DIR="/tmp/log/apnprofile"
LOG_FILE="${LOG_DIR}/apnprofile.log"
PID_FILE="/var/run/apnprofile.pid"
STATE_FILE="/tmp/apnprofile_state.json"
mkdir -p "${LOG_DIR}"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Save PID
echo $$ > "${PID_FILE}"
# Enhanced logging function
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t apnprofile "${level}: ${message}"
}
# AT command handling with locking
handle_lock() {
local max_wait=30
local wait_count=0
while [ -f "$QUEUE_FILE" ] && grep -q "AT_COMMAND" "$QUEUE_FILE" && [ $wait_count -lt $max_wait ]; do
sleep 1
wait_count=$((wait_count + 1))
done
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' "$$" "$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
}
# Execute AT command with retries
execute_at_command() {
local command="$1"
local result=""
local retry_count=0
local max_retries=3
while [ $retry_count -lt $max_retries ]; do
handle_lock
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -eq 0 ] && [ -n "$result" ]; then
echo "$result"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
return 1
}
# Get current ICCID
get_current_iccid() {
local result=$(execute_at_command "AT+ICCID")
if [ $? -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]'
return 0
fi
return 1
}
# Set APN with error handling
set_apn() {
local pdp_type="$1"
local apn="$2"
if [ -z "$pdp_type" ] || [ -z "$apn" ]; then
return 1
fi
if execute_at_command "AT+CGDCONT=1,\"$pdp_type\",\"$apn\";+COPS=2;+COPS=0"; then
return 0
fi
return 1
}
# Function to get current configuration hash
get_config_hash() {
config_load quecmanager
local hash_input=""
# Get Profile 1
config_get ICCID_PROFILE1 apn_profile iccid_profile1
config_get APN_PROFILE1 apn_profile apn_profile1
config_get PDP_TYPE1 apn_profile pdp_type1
# Get Profile 2
config_get ICCID_PROFILE2 apn_profile iccid_profile2
config_get APN_PROFILE2 apn_profile apn_profile2
config_get PDP_TYPE2 apn_profile pdp_type2
hash_input="${ICCID_PROFILE1}${APN_PROFILE1}${PDP_TYPE1}${ICCID_PROFILE2}${APN_PROFILE2}${PDP_TYPE2}"
echo "$hash_input" | md5sum | cut -d' ' -f1
}
# Function to read state file
read_state() {
if [ -f "$STATE_FILE" ]; then
cat "$STATE_FILE"
else
echo "{}"
fi
}
# Function to write state file
write_state() {
local current_iccid="$1"
local config_hash="$2"
local status="$3"
printf '{"iccid":"%s","config_hash":"%s","status":"%s","timestamp":"%s"}' \
"$current_iccid" "$config_hash" "$status" "$(date '+%Y-%m-%d %H:%M:%S')" > "$STATE_FILE"
}
# Main service loop
while true; do
# Get current state
current_state=$(read_state)
current_iccid=$(get_current_iccid)
config_hash=$(get_config_hash)
# Extract values from current state
state_iccid=$(echo "$current_state" | sed -n 's/.*"iccid":"\([^"]*\)".*/\1/p')
state_hash=$(echo "$current_state" | sed -n 's/.*"config_hash":"\([^"]*\)".*/\1/p')
needs_update=0
# Check if update is needed
if [ ! -f "$STATE_FILE" ]; then
log_message "INFO" "No state file found, will apply profile"
needs_update=1
elif [ "$current_iccid" != "$state_iccid" ]; then
log_message "INFO" "ICCID changed from $state_iccid to $current_iccid"
needs_update=1
elif [ "$config_hash" != "$state_hash" ]; then
log_message "INFO" "Configuration changed"
needs_update=1
fi
if [ $needs_update -eq 1 ] && [ -n "$current_iccid" ]; then
config_load quecmanager
# Get Profile 1
config_get ICCID_PROFILE1 apn_profile iccid_profile1
config_get APN_PROFILE1 apn_profile apn_profile1
config_get PDP_TYPE1 apn_profile pdp_type1
# Get Profile 2
config_get ICCID_PROFILE2 apn_profile iccid_profile2
config_get APN_PROFILE2 apn_profile apn_profile2
config_get PDP_TYPE2 apn_profile pdp_type2
if [ "${current_iccid}" = "${ICCID_PROFILE1}" ]; then
if set_apn "$PDP_TYPE1" "$APN_PROFILE1"; then
log_message "INFO" "Successfully applied Profile 1"
write_state "$current_iccid" "$config_hash" "success"
else
log_message "ERROR" "Failed to apply Profile 1"
write_state "$current_iccid" "$config_hash" "error"
fi
elif [ -n "$ICCID_PROFILE2" ] && [ "${current_iccid}" = "${ICCID_PROFILE2}" ]; then
if set_apn "$PDP_TYPE2" "$APN_PROFILE2"; then
log_message "INFO" "Successfully applied Profile 2"
write_state "$current_iccid" "$config_hash" "success"
else
log_message "ERROR" "Failed to apply Profile 2"
write_state "$current_iccid" "$config_hash" "error"
fi
else
log_message "INFO" "No matching ICCID profile found"
write_state "$current_iccid" "$config_hash" "no_match"
fi
fi
sleep 10
done
EOL
chmod 755 /www/cgi-bin/services/apnprofile.sh
}
# Function to create init.d script
create_init_script() {
cat > /etc/init.d/apnprofile-service <<'EOL'
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
start_service() {
local enabled
# Check if service is enabled in UCI
config_load quecmanager
config_get enabled apn_profile enabled '0'
[ "$enabled" != "1" ] && return 0
procd_open_instance
procd_set_param command /www/cgi-bin/services/apnprofile.sh
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param nice 19
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "quecmanager"
}
reload_service() {
stop
start
}
EOL
chmod 755 /etc/init.d/apnprofile-service
}
# Initialize UCI configuration
touch /etc/config/quecmanager
# Remove existing APN profile section if it exists
uci -q delete quecmanager.apn_profile
# Create new APN profile section
uci set quecmanager.apn_profile=service
uci set quecmanager.apn_profile.enabled=1
# Set Profile 1 configuration
uci set quecmanager.apn_profile.iccid_profile1="$iccidProfile1"
uci set quecmanager.apn_profile.apn_profile1="$apnProfile1"
uci set quecmanager.apn_profile.pdp_type1="$pdpType1"
# Set Profile 2 configuration if provided
if [ -n "$iccidProfile2" ]; then
uci set quecmanager.apn_profile.iccid_profile2="$iccidProfile2"
uci set quecmanager.apn_profile.apn_profile2="$apnProfile2"
uci set quecmanager.apn_profile.pdp_type2="$pdpType2"
fi
# Commit UCI changes
if ! uci commit quecmanager; then
log_message "ERROR" "Failed to save UCI configuration"
echo '{"status": "error", "message": "Failed to save UCI configuration"}'
exit 1
fi
log_message "INFO" "UCI configuration saved successfully"
# Create service script if it doesn't exist
if [ ! -f "/www/cgi-bin/services/apnprofile.sh" ]; then
create_service_script
log_message "INFO" "Created service script"
fi
# Create init.d script if it doesn't exist
if [ ! -f "/etc/init.d/apnprofile-service" ]; then
create_init_script
log_message "INFO" "Created init.d script"
fi
# Enable and start the service
/etc/init.d/apnprofile-service enable
if /etc/init.d/apnprofile-service restart; then
log_message "INFO" "Service started successfully"
echo '{"status": "success", "message": "APN profiles saved and service started"}'
else
log_message "ERROR" "Failed to start service"
echo '{"status": "error", "message": "Failed to start service"}'
fi

View File

@@ -0,0 +1,127 @@
#!/bin/sh
echo "Content-type: application/json"
echo ""
# Initialize error tracking
has_error=false
error_message=""
# Function to append to error message
append_error() {
if [ -z "$error_message" ]; then
error_message="$1"
else
error_message="$error_message; $1"
fi
has_error=true
}
# Function to log cleanup events
log_message() {
local level="$1"
local message="$2"
local LOG_DIR="/tmp/log/imeiprofile"
local LOG_FILE="${LOG_DIR}/imeiprofile.log"
# Ensure log directory exists
mkdir -p "${LOG_DIR}"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t imeiprofile "${level}: ${message}"
}
log_message "INFO" "Starting IMEI Profile cleanup process"
# Stop and disable the service
if [ -f "/etc/init.d/imeiprofile-service" ]; then
if /etc/init.d/imeiprofile-service stop; then
log_message "INFO" "IMEI Profile service stopped"
else
append_error "Failed to stop IMEI Profile service"
log_message "ERROR" "Failed to stop IMEI Profile service"
fi
if /etc/init.d/imeiprofile-service disable; then
log_message "INFO" "IMEI Profile service disabled"
else
append_error "Failed to disable IMEI Profile service"
log_message "ERROR" "Failed to disable IMEI Profile service"
fi
# Remove the init.d script
if rm -f "/etc/init.d/imeiprofile-service"; then
log_message "INFO" "Removed init.d script"
else
append_error "Failed to remove init.d script"
log_message "ERROR" "Failed to remove init.d script"
fi
fi
# Remove service script
if [ -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
if rm -f "/www/cgi-bin/services/imeiprofile.sh"; then
log_message "INFO" "Removed service script"
else
append_error "Failed to remove service script"
log_message "ERROR" "Failed to remove service script"
fi
fi
# Remove symlinks in rc.d if they exist
for link in /etc/rc.d/S??imeiprofile-service /etc/rc.d/K??imeiprofile-service; do
if [ -L "$link" ]; then
if rm -f "$link"; then
log_message "INFO" "Removed rc.d symlink: $link"
else
append_error "Failed to remove rc.d symlink: $link"
log_message "ERROR" "Failed to remove rc.d symlink: $link"
fi
fi
done
# Remove UCI configuration
if uci -q get quecmanager.imei_profile >/dev/null; then
if uci delete quecmanager.imei_profile && uci commit quecmanager; then
log_message "INFO" "Removed UCI configuration"
else
append_error "Failed to remove UCI configuration"
log_message "ERROR" "Failed to remove UCI configuration"
fi
fi
# Kill any remaining processes
if pkill -f "/www/cgi-bin/services/imeiprofile.sh"; then
log_message "INFO" "Killed remaining IMEI Profile processes"
fi
# Clean up temporary files
for file in \
"/tmp/at_pipe.txt" \
"/var/run/imeiprofile.pid" \
"/tmp/imei_result.txt" \
"/tmp/debug.log" \
"/tmp/inputICCID.txt" \
"/tmp/outputICCID.txt" \
"/tmp/inputIMEI.txt" \
"/tmp/outputIMEI.txt"
do
if [ -f "$file" ]; then
if rm -f "$file"; then
log_message "INFO" "Removed temporary file: $file"
else
append_error "Failed to remove temporary file: $file"
log_message "ERROR" "Failed to remove temporary file: $file"
fi
fi
done
log_message "INFO" "IMEI Profile cleanup completed"
# Return appropriate JSON response
if [ "$has_error" = true ]; then
echo "{\"status\": \"error\", \"message\": \"$error_message\"}"
else
echo "{\"status\": \"success\", \"message\": \"IMEI Profile service successfully removed\"}"
fi

View File

@@ -0,0 +1,138 @@
#!/bin/sh
# Set headers for JSON response
echo "Content-type: application/json"
echo ""
# Load UCI functions
. /lib/functions.sh
# Function to safely get UCI value with default
get_uci_value() {
local value
config_get value imei_profile "$1" "$2"
echo "${value:-$2}"
}
# Function to check if service is running
check_service_status() {
if [ -f "/var/run/imeiprofile.pid" ]; then
pid=$(cat /var/run/imeiprofile.pid)
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
echo "running"
return
fi
fi
# Double check using process search
if pgrep -f "/www/cgi-bin/services/imeiprofile.sh" >/dev/null; then
echo "running"
return
fi
echo "stopped"
}
# Function to get last log entry
get_last_log() {
local LOG_FILE="/tmp/log/imeiprofile/imeiprofile.log"
if [ -f "$LOG_FILE" ]; then
tail -n 1 "$LOG_FILE"
else
echo "No log entries found"
fi
}
# Function to check if init.d service is enabled
check_service_enabled() {
if [ -f "/etc/init.d/imeiprofile-service" ]; then
if /etc/init.d/imeiprofile-service enabled; then
echo "true"
return
fi
fi
echo "false"
}
# Load QuecManager configuration
config_load quecmanager
# Check if IMEI Profile section exists
if ! uci -q get quecmanager.imei_profile >/dev/null; then
echo '{"status": "inactive", "message": "IMEI Profile service is not configured"}'
exit 0
fi
# Get enabled status from UCI
enabled=$(get_uci_value "enabled" "0")
if [ "$enabled" != "1" ]; then
echo '{"status": "inactive", "message": "IMEI Profile service is disabled"}'
exit 0
fi
# Check if service script exists
if [ ! -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
echo '{"status": "error", "message": "Service script is missing"}'
exit 0
fi
# Get service status information
service_status=$(check_service_status)
service_enabled=$(check_service_enabled)
last_log=$(get_last_log)
# Fetch configuration values from UCI
iccid_profile1=$(get_uci_value "iccid_profile1" "")
imei_profile1=$(get_uci_value "imei_profile1" "")
iccid_profile2=$(get_uci_value "iccid_profile2" "")
imei_profile2=$(get_uci_value "imei_profile2" "")
# Function to check if profile data exists
validate_profile_data() {
local iccid="$1"
local imei="$2"
[ -n "$iccid" ] && [ -n "$imei" ]
}
# Build JSON response
cat <<EOF
{
"status": "active",
"service": {
"status": "${service_status}",
"enabled": ${service_enabled},
"script": "$([ -f "/www/cgi-bin/services/imeiprofile.sh" ] && echo "present" || echo "missing")",
"initScript": "$([ -f "/etc/init.d/imeiprofile-service" ] && echo "present" || echo "missing")"
},
"profiles": {
EOF
# Add Profile 1 if it exists
if validate_profile_data "$iccid_profile1" "$imei_profile1"; then
cat <<EOF
"profile1": {
"iccid": "${iccid_profile1}",
"imei": "${imei_profile1}"
}
EOF
fi
# Add Profile 2 if it exists
if validate_profile_data "$iccid_profile2" "$imei_profile2"; then
# Add comma if Profile 1 was added
[ -n "$iccid_profile1" ] && echo ","
cat <<EOF
"profile2": {
"iccid": "${iccid_profile2}",
"imei": "${imei_profile2}"
}
EOF
fi
# Close the profiles object and add last activity
cat <<EOF
},
"lastActivity": "${last_log}"
}
EOF

View File

@@ -0,0 +1,291 @@
#!/bin/sh
# Read POST data
read -r QUERY_STRING
# Function to urldecode
urldecode() {
local value="$1"
value="${value//+/ }"
value="${value//%/\\x}"
printf '%b' "$value"
}
# Extract values from POST data
iccidProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile1=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile1=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile1=\([^&]*\).*/\1/p' | tr -d "'")
iccidProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*iccidProfile2=\([^&]*\).*/\1/p' | tr -d "'")
imeiProfile2=$(echo "$QUERY_STRING" | sed -n 's/.*imeiProfile2=\([^&]*\).*/\1/p' | tr -d "'")
# URL decode the values
iccidProfile1=$(urldecode "$iccidProfile1")
imeiProfile1=$(urldecode "$imeiProfile1")
iccidProfile2=$(urldecode "$iccidProfile2")
imeiProfile2=$(urldecode "$imeiProfile2")
echo "Content-type: application/json"
echo ""
# Validate required first profile
if [ -z "$iccidProfile1" ] || [ -z "$imeiProfile1" ]; then
echo '{"status": "error", "message": "Profile 1 is required"}'
exit 1
fi
# Function to log messages
log_message() {
local level="$1"
local message="$2"
local LOG_DIR="/tmp/log/imeiprofile"
local LOG_FILE="${LOG_DIR}/imeiprofile.log"
mkdir -p "${LOG_DIR}"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t imeiprofile "${level}: ${message}"
}
# Create required directories
mkdir -p /www/cgi-bin/services
# Function to create service script
create_service_script() {
cat > /www/cgi-bin/services/imeiprofile.sh <<'EOL'
#!/bin/sh
# Load UCI functions
. /lib/functions.sh
# Define file paths
QUEUE_FILE="/tmp/at_pipe.txt"
LOG_DIR="/tmp/log/imeiprofile"
LOG_FILE="${LOG_DIR}/imeiprofile.log"
PID_FILE="/var/run/imeiprofile.pid"
mkdir -p "${LOG_DIR}"
[ ! -f "${QUEUE_FILE}" ] && touch "${QUEUE_FILE}"
# Save PID
echo $$ > "${PID_FILE}"
# Enhanced logging function
log_message() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "${timestamp} - [${level}] ${message}" >> "$LOG_FILE"
logger -t imeiprofile "${level}: ${message}"
}
# AT command handling with locking
handle_lock() {
local max_wait=30
local wait_count=0
while [ -f "$QUEUE_FILE" ] && grep -q "AT_COMMAND" "$QUEUE_FILE" && [ $wait_count -lt $max_wait ]; do
sleep 1
wait_count=$((wait_count + 1))
done
printf '{"command":"AT_COMMAND","pid":"%s","timestamp":"%s"}\n' "$$" "$(date '+%H:%M:%S')" >> "$QUEUE_FILE"
}
# Execute AT command with retries
execute_at_command() {
local command="$1"
local result=""
local retry_count=0
local max_retries=3
while [ $retry_count -lt $max_retries ]; do
handle_lock
result=$(sms_tool at "$command" -t 4 2>&1)
local status=$?
sed -i "/\"pid\":\"$$\"/d" "$QUEUE_FILE"
if [ $status -eq 0 ] && [ -n "$result" ]; then
echo "$result"
return 0
fi
retry_count=$((retry_count + 1))
[ $retry_count -lt $max_retries ] && sleep 2
done
return 1
}
# Get current ICCID
get_current_iccid() {
local result=$(execute_at_command "AT+ICCID")
if [ $? -eq 0 ] && echo "$result" | grep -q "+ICCID:"; then
echo "$result" | grep "+ICCID:" | cut -d' ' -f2 | tr -d '[:space:]'
return 0
fi
return 1
}
# Get current IMEI
get_current_imei() {
local result=$(execute_at_command "AT+CGSN")
if [ $? -eq 0 ]; then
echo "$result" | grep -v "AT+CGSN" | grep -v "OK" | tr -d '\r\n[:space:]'
return 0
fi
return 1
}
# Set IMEI
set_imei() {
local imei="$1"
if execute_at_command "AT+EGMR=1,7,\"$imei\";+QPOWD=1"; then
return 0
fi
return 1
}
# Function to safely get UCI value with default
get_uci_value() {
local value
config_get value imei_profile "$1" "$2"
echo "${value:-$2}"
}
# Main service loop
while true; do
# Load current configuration
config_load quecmanager
# Get Profile 1
iccid_profile1=$(get_uci_value "iccid_profile1")
imei_profile1=$(get_uci_value "imei_profile1")
# Get Profile 2
iccid_profile2=$(get_uci_value "iccid_profile2")
imei_profile2=$(get_uci_value "imei_profile2")
# Get current ICCID and IMEI
current_iccid=$(get_current_iccid)
current_imei=$(get_current_imei)
if [ $? -eq 0 ] && [ -n "$current_iccid" ] && [ -n "$current_imei" ]; then
if [ "${current_iccid}" = "${iccid_profile1}" ]; then
if [ "${current_imei}" != "${imei_profile1}" ]; then
if set_imei "${imei_profile1}"; then
log_message "INFO" "Successfully applied Profile 1 IMEI"
else
log_message "ERROR" "Failed to apply Profile 1 IMEI"
fi
fi
elif [ -n "$iccid_profile2" ] && [ "${current_iccid}" = "${iccid_profile2}" ]; then
if [ "${current_imei}" != "${imei_profile2}" ]; then
if set_imei "${imei_profile2}"; then
log_message "INFO" "Successfully applied Profile 2 IMEI"
else
log_message "ERROR" "Failed to apply Profile 2 IMEI"
fi
fi
else
log_message "INFO" "No matching ICCID profile found"
fi
else
log_message "ERROR" "Failed to get current ICCID or IMEI"
fi
sleep 30
done
EOL
chmod 755 /www/cgi-bin/services/imeiprofile.sh
}
# Function to create init.d script
create_init_script() {
cat > /etc/init.d/imeiprofile-service <<'EOL'
#!/bin/sh /etc/rc.common
START=99
STOP=10
USE_PROCD=1
start_service() {
local enabled
# Check if service is enabled in UCI
config_load quecmanager
config_get enabled imei_profile enabled '0'
[ "$enabled" != "1" ] && return 0
procd_open_instance
procd_set_param command /www/cgi-bin/services/imeiprofile.sh
procd_set_param respawn ${respawn_threshold:-3600} ${respawn_timeout:-5} ${respawn_retry:-5}
procd_set_param stdout 1
procd_set_param stderr 1
procd_set_param nice 19
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "quecmanager"
}
reload_service() {
stop
start
}
EOL
chmod 755 /etc/init.d/imeiprofile-service
}
# Initialize UCI configuration
touch /etc/config/quecmanager
# Remove existing IMEI profile section if it exists
uci -q delete quecmanager.imei_profile
# Create new IMEI profile section
uci set quecmanager.imei_profile=service
uci set quecmanager.imei_profile.enabled=1
# Set Profile 1 configuration
uci set quecmanager.imei_profile.iccid_profile1="$iccidProfile1"
uci set quecmanager.imei_profile.imei_profile1="$imeiProfile1"
# Set Profile 2 configuration if provided
if [ -n "$iccidProfile2" ]; then
uci set quecmanager.imei_profile.iccid_profile2="$iccidProfile2"
uci set quecmanager.imei_profile.imei_profile2="$imeiProfile2"
fi
# Commit UCI changes
if ! uci commit quecmanager; then
log_message "ERROR" "Failed to save UCI configuration"
echo '{"status": "error", "message": "Failed to save UCI configuration"}'
exit 1
fi
log_message "INFO" "UCI configuration saved successfully"
# Create service script if it doesn't exist
if [ ! -f "/www/cgi-bin/services/imeiprofile.sh" ]; then
create_service_script
log_message "INFO" "Created service script"
fi
# Create init.d script if it doesn't exist
if [ ! -f "/etc/init.d/imeiprofile-service" ]; then
create_init_script
log_message "INFO" "Created init.d script"
fi
# Enable and start the service
/etc/init.d/imeiprofile-service enable
if /etc/init.d/imeiprofile-service restart; then
log_message "INFO" "Service started successfully"
echo '{"status": "success", "message": "IMEI profiles saved and service started"}'
else
log_message "ERROR" "Failed to start service"
echo '{"status": "error", "message": "Failed to start service"}'
fi

View File

@@ -0,0 +1,168 @@
#!/bin/sh
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
TOKEN_FILE="$QUEUE_DIR/token"
RESULT_FILE="/tmp/qscan_result.json"
WORKER_SCRIPT="/www/cgi-bin/quecmanager/experimental/cell_scanner/cell_scan_worker.sh"
PID_FILE="/tmp/cell_scan.pid"
SCAN_COMMAND="AT+QSCAN=3,1"
SCAN_TIMEOUT=200
LOCK_ID="CELL_SCAN_$(date +%s)_$$"
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t at_queue -p "daemon.$level" "cell_scan: $1"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
log_message "Sending response: status=$status, message=$message"
printf '{"status":"%s","message":"%s"}\n' "$status" "$message"
exit 0
}
# Function to check if worker is running
check_worker_running() {
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
log_message "Worker process $pid is running"
return 0
fi
log_message "Removing stale PID file for process $pid"
rm -f "$PID_FILE"
fi
return 1
}
# Enhanced JSON string escaping function
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$//'
}
# Acquire token directly with high priority
acquire_token() {
local priority=1 # Highest priority for cell scan
local max_attempts=10
local attempt=0
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
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)" "info"
rm -f "$TOKEN_FILE" 2>/dev/null
else
# Try again - higher priority token exists
log_message "Token held by $current_holder with priority $current_priority, retrying..." "debug"
sleep 0.5
attempt=$((attempt + 1))
continue
fi
fi
# Try to create token file
echo "{\"id\":\"$LOCK_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" = "$LOCK_ID" ]; then
log_message "Successfully acquired token with priority $priority" "info"
return 0
fi
sleep 0.5
attempt=$((attempt + 1))
done
log_message "Failed to acquire token after $max_attempts attempts" "error"
return 1
}
# Main execution
{
# If scan is running, return running status
if check_worker_running; then
output_json "running" "Cell scan is in progress"
fi
# Start new scan
rm -f "$RESULT_FILE"
log_message "Starting new cell scan" "info"
# Ensure worker script is executable
chmod +x "$WORKER_SCRIPT" 2>/dev/null
# Start worker script with proper parameters
log_message "Attempting to start worker script: $WORKER_SCRIPT" "info"
# Check if worker script exists
if [ ! -f "$WORKER_SCRIPT" ]; then
log_message "Worker script not found: $WORKER_SCRIPT" "error"
output_json "error" "Worker script not found"
fi
# Ensure QUEUE_DIR exists
mkdir -p "$QUEUE_DIR" "$RESULTS_DIR"
chmod 755 "$QUEUE_DIR"
chmod 755 "$RESULTS_DIR"
# Start worker with debug logging
WORKER_PID=$
(sh "$WORKER_SCRIPT" >/tmp/cell_scan_worker.log 2>&1) &
WORKER_PID=$!
log_message "Worker script started with PID $WORKER_PID" "info"
# The worker process runs in the background and completes quickly
# We don't need to check if it's still running as it might finish before we check
log_message "Worker process $WORKER_PID started in background" "info"
# Instead of checking if the process is running, check if it created the result file
sleep 2
if [ -f "$RESULT_FILE" ]; then
log_message "Worker successfully created result file" "info"
else
log_message "Waiting for worker to create result file..." "info"
# If no result file yet, check for errors
if [ -f "/tmp/cell_scan_worker.log" ]; then
WORKER_LOG=$(cat "/tmp/cell_scan_worker.log" | head -20)
log_message "Worker log: $WORKER_LOG" "info"
fi
fi
output_json "running" "Started new cell scan"
} || {
# Error handler
log_message "Script failed with error" "error"
output_json "error" "Internal error occurred"
}

View File

@@ -0,0 +1,323 @@
#!/bin/sh
# Configuration
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
TOKEN_FILE="$QUEUE_DIR/token"
RESULT_FILE="/tmp/qscan_result.json"
PID_FILE="/tmp/cell_scan.pid"
SCAN_COMMAND="AT+QSCAN=3,1"
SCAN_TIMEOUT=200
LOCK_ID="CELL_SCAN_$(date +%s)_$$"
# Enable shell debugging for better logging
set -x
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t at_queue -p "daemon.$level" "cell_scan_worker: $1"
}
# Function to clean up stale temporary files
cleanup_stale_files() {
log_message "Cleaning up stale temporary files" "info"
# Clean up old start_time files (older than 1 hour)
find "$QUEUE_DIR" -name "start_time.qscan_*" -type f -mmin +60 -delete 2>/dev/null
# Clean up any start_time files that match our current process just in case
find "$QUEUE_DIR" -name "start_time.qscan_*_$" -type f -delete 2>/dev/null
log_message "Stale file cleanup completed" "info"
}
# Function to check directories and permissions
check_environment() {
log_message "Checking environment" "info"
# Clean up stale files first
cleanup_stale_files
# Check if directories exist, create if they don't
if [ ! -d "$QUEUE_DIR" ]; then
mkdir -p "$QUEUE_DIR"
log_message "Created queue directory: $QUEUE_DIR" "info"
fi
if [ ! -d "$RESULTS_DIR" ]; then
mkdir -p "$RESULTS_DIR"
log_message "Created results directory: $RESULTS_DIR" "info"
fi
# Check permissions
chmod 755 "$QUEUE_DIR" 2>/dev/null
chmod 755 "$RESULTS_DIR" 2>/dev/null
# Check if sms_tool exists and is executable
if ! which sms_tool >/dev/null 2>&1; then
log_message "sms_tool not found in PATH" "error"
return 1
fi
# Test directory write permissions
if ! touch "$QUEUE_DIR/test_$$" 2>/dev/null; then
log_message "Cannot write to $QUEUE_DIR" "error"
return 1
fi
rm -f "$QUEUE_DIR/test_$$" 2>/dev/null
if ! touch "$RESULTS_DIR/test_$$" 2>/dev/null; then
log_message "Cannot write to $RESULTS_DIR" "error"
return 1
fi
rm -f "$RESULTS_DIR/test_$$" 2>/dev/null
log_message "Environment check passed" "info"
return 0
}
# Function to clean AT command output
clean_output() {
while IFS= read -r line; do
case "$line" in
"OK" | "" | *"ERROR"*)
continue
;;
*)
printf '%s\n' "$line"
;;
esac
done | sed 's/\r//g' | tr '\n' '\r' | sed 's/\r$//' | tr '\r' '\n'
}
# Enhanced JSON string escaping function
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$//'
}
# Function to check if scan is already running
check_running() {
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
log_message "Cell scan already running (PID: $pid)" "warn"
return 0
fi
rm -f "$PID_FILE"
fi
return 1
}
# Acquire token directly with high priority
acquire_token() {
local priority=1 # Highest priority for cell scan
local max_attempts=10
local attempt=0
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
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)" "info"
rm -f "$TOKEN_FILE" 2>/dev/null
else
# Try again
sleep 0.5
attempt=$((attempt + 1))
continue
fi
fi
# Try to create token file
echo "{\"id\":\"$LOCK_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" = "$LOCK_ID" ]; then
log_message "Successfully acquired token with priority $priority" "info"
return 0
fi
sleep 0.5
attempt=$((attempt + 1))
done
log_message "Failed to acquire token after $max_attempts attempts" "error"
return 1
}
# Release token directly
release_token() {
if [ -f "$TOKEN_FILE" ]; then
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
if [ "$current_holder" = "$LOCK_ID" ]; then
rm -f "$TOKEN_FILE" 2>/dev/null
log_message "Released token" "info"
return 0
fi
log_message "Token held by $current_holder, not by us ($LOCK_ID)" "warn"
fi
return 1
}
# Main execution
main() {
# Start logging
log_message "Worker script started" "info"
# Check if already running
if check_running; then
log_message "Cell scan already running, exiting" "warn"
exit 1
fi
# Create PID file
echo "$$" > "$PID_FILE"
chmod 644 "$PID_FILE" 2>/dev/null
log_message "Created PID file: $$" "info"
# Set up cleanup on exit
trap 'log_message "Cleaning up and exiting" "info"; release_token; rm -f "$PID_FILE"; exit' INT TERM EXIT
# Acquire token for AT command execution
if ! acquire_token; then
log_message "Failed to acquire token, exiting" "error"
rm -f "$PID_FILE"
exit 1
fi
log_message "Token acquired, executing scan command: $SCAN_COMMAND" "info"
# Execute scan with native timeout option (without relying on timeout command)
# Use the -t option of sms_tool instead of the timeout command
log_message "Executing command with timeout: $SCAN_TIMEOUT seconds" "info"
SCAN_OUTPUT=$(sms_tool at "$SCAN_COMMAND" -t $SCAN_TIMEOUT 2>&1 | clean_output)
SCAN_STATUS=$?
log_message "Command execution completed with status: $SCAN_STATUS" "info"
# Process and store result
if [ $SCAN_STATUS -eq 0 ]; then
# Check if output contains valid scan data or error
if echo "$SCAN_OUTPUT" | grep -q "+QSCAN"; then
# Set timestamp
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# Valid scan data found - don't add the "Scan completed but no valid data" prefix
log_message "Scan completed with valid data" "info"
# Create the result file with proper JSON formatting
printf '{"status":"success","timestamp":"%s","output":%s}\n' \
"$TIMESTAMP" \
"$(printf '%s' "$SCAN_OUTPUT" | sed 's/"/\\"/g' | jq -R -s '.')" > "$RESULT_FILE"
chmod 644 "$RESULT_FILE" 2>/dev/null
else
# No valid scan data, but command completed
log_message "Command completed but no valid scan data found: $SCAN_OUTPUT" "warn"
SCAN_OUTPUT="Scan completed but no valid data returned: $SCAN_OUTPUT"
# Create a result file indicating partial success
printf '{"status":"partial","timestamp":"%s","output":%s}\n' \
"$(date '+%Y-%m-%d %H:%M:%S')" \
"$(printf '%s' "$SCAN_OUTPUT" | sed 's/"/\\"/g' | jq -R -s '.')" > "$RESULT_FILE"
chmod 644 "$RESULT_FILE" 2>/dev/null
fi
# Generate a command ID for the AT queue results format - use actual PID instead of $
local my_pid="$$"
local cmd_id="qscan_$(date +%s)_${my_pid}"
local end_time=$(date +%s)
local start_time=$end_time
local duration=0
# Store start time for future reference
echo "$start_time" > "$QUEUE_DIR/start_time.$cmd_id"
log_message "Creating AT queue result with ID: $cmd_id" "info"
# Create JSON response in the AT queue format
local response=$(cat << EOF
{
"command": {
"id": "$cmd_id",
"text": "$SCAN_COMMAND",
"timestamp": "$(date -Iseconds)"
},
"response": {
"status": "success",
"raw_output": "$(escape_json "$SCAN_OUTPUT")",
"completion_time": "$end_time",
"duration_ms": $duration
}
}
EOF
)
# Save the response to the AT queue results directory
printf "%s" "$response" > "$RESULTS_DIR/$cmd_id.json"
chmod 644 "$RESULTS_DIR/$cmd_id.json"
# Clean up temporary files
rm -f "$QUEUE_DIR/start_time.$cmd_id"
log_message "Cleaned up temporary files" "info"
# Release the token
release_token
return 0
else
log_message "Scan failed with status: $SCAN_STATUS" "error"
printf '{"status":"error","timestamp":"%s","message":"Scan failed"}\n' \
"$(date '+%Y-%m-%d %H:%M:%S')" > "$RESULT_FILE"
chmod 644 "$RESULT_FILE" 2>/dev/null
# Release the token
release_token
return 1
fi
}
# Execute main function with proper error handling
{
log_message "Worker script started with PID $$" "info"
# Check environment before proceeding
check_environment || {
log_message "Environment check failed, aborting" "error"
exit 1
}
# Execute main function
main || {
log_message "Main function failed with error $?" "error"
release_token
rm -f "$PID_FILE"
exit 1
}
} 2>/tmp/cell_scan_worker_debug.log || {
log_message "Script failed with error" "error"
release_token
rm -f "$PID_FILE"
exit 1
}

View File

@@ -0,0 +1,124 @@
#!/bin/sh
# Set content type to JSON
echo "Content-type: application/json"
echo ""
# Configuration
QUEUE_DIR="/tmp/at_queue"
RESULTS_DIR="$QUEUE_DIR/results"
RESULT_FILE="/tmp/qscan_result.json"
PID_FILE="/tmp/cell_scan.pid"
TOKEN_FILE="$QUEUE_DIR/token"
# Function to log messages
log_message() {
local level="${2:-info}"
logger -t at_queue -p "daemon.$level" "check_scan: $1"
}
# Function to output JSON response
output_json() {
local status="$1"
local message="$2"
if [ "$status" = "success" ] && [ -f "$RESULT_FILE" ]; then
# Return the contents of the result file
cat "$RESULT_FILE"
else
printf '{"status":"%s","message":"%s","timestamp":"","output":""}\n' "$status" "$message"
fi
}
# Check for scan token holder
check_token_holder() {
if [ -f "$TOKEN_FILE" ]; then
local current_holder=$(cat "$TOKEN_FILE" | jsonfilter -e '@.id' 2>/dev/null)
if [ -n "$current_holder" ] && echo "$current_holder" | grep -q "CELL_SCAN"; then
log_message "Cell scan token is active: $current_holder" "debug"
return 0
fi
fi
return 1
}
# Check if a scan is already in progress
check_scan_progress() {
# First check PID file
if [ -f "$PID_FILE" ]; then
pid=$(cat "$PID_FILE")
if kill -0 "$pid" 2>/dev/null; then
log_message "Scan in progress (PID: $pid)" "info"
output_json "running" "Scan in progress"
exit 0
else
log_message "Removing stale PID file" "warn"
rm -f "$PID_FILE"
fi
fi
# Also check token holder
if check_token_holder; then
log_message "Scan in progress (Token active)" "info"
output_json "running" "Scan in progress (Token active)"
exit 0
fi
}
# Check for existing results
check_results() {
if [ -f "$RESULT_FILE" ]; then
# Check if the result file contains valid JSON data
local result_content=$(cat "$RESULT_FILE" 2>/dev/null)
if [ -n "$result_content" ] && echo "$result_content" | grep -q "status"; then
# Also check the results directory for AT command results
local cmd_id
cmd_id=$(echo "$result_content" | jsonfilter -e '@.command.id' 2>/dev/null)
# Log the result we found
log_message "Found result file with command ID: $cmd_id" "info"
# Check how old the result file is
local file_time=$(stat -c %Y "$RESULT_FILE" 2>/dev/null || echo "0")
local current_time=$(date +%s)
local age=$((current_time - file_time))
log_message "Result file age: $age seconds" "info"
# If file_time is valid and result is less than 1 hour old
if [ $age -lt 3600 ]; then
log_message "Recent scan results available" "info"
output_json "success" "Scan results available"
exit 0
else
log_message "Scan results too old, suggesting new scan" "info"
output_json "idle" "Previous scan results outdated"
exit 0
fi
else
log_message "Result file exists but contains invalid data" "warn"
rm -f "$RESULT_FILE" # Remove invalid result file
output_json "idle" "Invalid previous scan results"
exit 0
fi
fi
}
# Main execution
{
# First check if a scan is in progress
check_scan_progress
# Then check for existing results
check_results
# If no results and no running scan, indicate idle state
log_message "No active scan or recent results" "info"
output_json "idle" "No active scan"
exit 0
} || {
# Error handler
log_message "Failed to check scan status" "error"
output_json "error" "Failed to check scan status"
exit 1
}

View File

@@ -5,7 +5,7 @@ echo "Content-type: application/json"
echo ""
# Configuration
JSON_FILE="/www/cgi-bin/mcc-mnc-list.json"
JSON_FILE="/www/cgi-bin/quecmanager/mcc-mnc-list.json"
# Function to log messages
log_message() {

Some files were not shown because too many files have changed in this diff Show More