Merging Beta 2.0.0 Release Candidate
This commit is contained in:
@@ -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
|
||||
|
||||
22
ipk-source/sdxpinn-quecmanager-beta/root/etc/init.d/ntp.init
Normal file
22
ipk-source/sdxpinn-quecmanager-beta/root/etc/init.d/ntp.init
Normal 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..."
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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."
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
@@ -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();
|
||||
@@ -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
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
@@ -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
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
@@ -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
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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
|
||||
@@ -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 "}"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 "}"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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\"}"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"}'
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user