Files
op-packages/luci-app-quickactions/root/usr/libexec/rpcd/luci.quickactions-scripts
T

339 lines
9.6 KiB
Bash
Executable File

#!/bin/sh
# ubus RPC module for Quick Actions Scripts
. /usr/share/libubox/jshn.sh
SCRIPTS_DIR=/etc/quickactions/scripts
mkdir -p "$SCRIPTS_DIR"
list_methods() {
cat <<'EOF'
{
"list": {},
"read": { "sid": "string" },
"write": { "sid": "string", "name": "string", "category": "string", "content": "string", "args": "string", "timeout": "string", "enabled": "string" },
"delete": { "sid": "string" },
"run": { "sid": "string" },
"chmod": { "sid": "string", "mode": "string" },
"install_preset": { "preset": "string" },
"detail": { "sid": "string" }
}
EOF
}
method_list() {
cat >/dev/null
json_init
json_add_array "scripts"
# No pipe into while → no subshell → json_add works
for sid in $(uci show quickactions 2>/dev/null | grep '=script$' | cut -d. -f2 | cut -d= -f1); do
name=$(uci -q get "quickactions.$sid.name")
category=$(uci -q get "quickactions.$sid.category")
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
enabled=$(uci -q get "quickactions.$sid.enabled")
[ -z "$enabled" ] && enabled="1"
sz=0
[ -f "$path" ] && sz=$(wc -c < "$path" 2>/dev/null)
[ -z "$sz" ] && sz=0
json_add_object
json_add_string "sid" "$sid"
json_add_string "name" "$name"
json_add_string "category" "$category"
json_add_string "path" "$path"
json_add_string "enabled" "$enabled"
json_add_int "size" "$sz"
json_close_object
done
json_close_array
json_dump
}
method_read() {
local sid=""
json_load "$(cat)"
json_get_var sid "sid"
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
local path
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
json_init
if [ -f "$path" ]; then
json_add_string "content" "$(cat "$path")"
else
json_add_string "content" ""
fi
json_dump
}
method_write() {
local payload sid name category content args timeout enabled path
payload=$(cat)
json_load "$payload"
json_get_var sid "sid"
json_get_var name "name"
json_get_var category "category"
json_get_var content "content"
json_get_var args "args"
json_get_var timeout "timeout"
json_get_var enabled "enabled"
[ -z "$sid" ] && sid="script_$(date +%s)"
[ -z "$name" ] && name="$sid"
[ -z "$category" ] && category="custom"
[ -z "$timeout" ] && timeout="60"
[ -z "$enabled" ] && enabled="1"
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
mkdir -p "$(dirname "$path")"
printf '%s' "$content" > "$path"
chmod 755 "$path" 2>/dev/null
uci -q set "quickactions.$sid=script"
uci -q set "quickactions.$sid.name=$name"
uci -q set "quickactions.$sid.category=$category"
uci -q set "quickactions.$sid.path=$path"
uci -q set "quickactions.$sid.enabled=$enabled"
uci -q set "quickactions.$sid.timeout=$timeout"
[ -n "$args" ] && uci -q set "quickactions.$sid.args=$args"
uci -q commit quickactions
json_init
json_add_string "sid" "$sid"
json_add_boolean "ok" 1
json_dump
}
method_delete() {
local sid=""
json_load "$(cat)"
json_get_var sid "sid"
[ -z "$sid" ] && { json_init; json_add_boolean "ok" 0; json_dump; return; }
local path
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
[ -f "$path" ] && rm -f "$path"
uci -q delete "quickactions.$sid"
uci -q commit quickactions
json_init
json_add_boolean "ok" 1
json_dump
}
method_run() {
local sid=""
json_load "$(cat)"
json_get_var sid "sid"
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
local path timeout args
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
timeout=$(uci -q get "quickactions.$sid.timeout")
[ -z "$timeout" ] && timeout=60
args=$(uci -q get "quickactions.$sid.args")
if [ ! -f "$path" ]; then
json_init
json_add_string "output" "Script not found: $path"
json_add_int "exit_code" 127
json_dump
return
fi
[ -x "$path" ] || chmod 755 "$path" 2>/dev/null
local start_sec end_sec out rc
start_sec=$(date +%s 2>/dev/null)
out=$(cd / && timeout "$timeout" "$path" $args 2>&1)
rc=$?
end_sec=$(date +%s 2>/dev/null)
json_init
json_add_string "output" "$out"
json_add_int "exit_code" "$rc"
json_add_int "duration" "$((end_sec - start_sec))"
json_dump
}
method_chmod() {
local payload sid mode
payload=$(cat)
json_load "$payload"
json_get_var sid "sid"
json_get_var mode "mode"
[ -z "$mode" ] && mode="755"
local path
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
[ -f "$path" ] && chmod "$mode" "$path" 2>/dev/null
json_init
json_add_boolean "ok" 1
json_dump
}
method_detail() {
local sid=""
json_load "$(cat)"
json_get_var sid "sid"
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
local path
path=$(uci -q get "quickactions.$sid.path")
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
json_init
json_add_string "sid" "$sid"
json_add_string "name" "$(uci -q get quickactions.$sid.name)"
json_add_string "category" "$(uci -q get quickactions.$sid.category)"
json_add_string "path" "$path"
json_add_string "enabled" "$(uci -q get quickactions.$sid.enabled)"
json_add_string "timeout" "$(uci -q get quickactions.$sid.timeout)"
json_add_string "args" "$(uci -q get quickactions.$sid.args)"
json_add_string "description" "$(uci -q get quickactions.$sid.description)"
if [ -f "$path" ]; then
json_add_string "content" "$(cat "$path")"
json_add_int "size" "$(wc -c < "$path")"
json_add_string "permissions" "$(ls -l "$path" | awk '{print $1}')"
else
json_add_string "content" ""
json_add_int "size" 0
json_add_string "permissions" ""
fi
json_dump
}
method_install_preset() {
local preset=""
json_load "$(cat)"
json_get_var preset "preset"
local sid="failover-lite"
local path="$SCRIPTS_DIR/$sid.sh"
mkdir -p "$SCRIPTS_DIR"
if [ "$preset" = "failover" ] || [ -z "$preset" ]; then
cat > "$path" << 'FO_EOF'
#!/bin/sh
# Failover-lite — MWAN3 substitute for low-RAM routers.
. /lib/functions.sh
config_load quickactions
cfg() { config_get v failover "$1" "$2"; echo "$v"; }
ENABLED=$(cfg enabled 1); [ "$ENABLED" = "0" ] && exit 0
PRIMARY=$(cfg primary ""); [ -z "$PRIMARY" ] && exit 0
CHECK_IPS=$(cfg check_ips "1.1.1.1 8.8.8.8")
PING_TIMEOUT=$(cfg ping_timeout 5)
FAIL_AT=$(cfg fail_threshold 2)
REC_AT=$(cfg recover_threshold 1)
LOCK=/tmp/qa-failover-preset.lock
FAIL_FILE=/tmp/qa-failover-preset.fails
OK_FILE=/tmp/qa-failover-preset.oks
phys_iface() {
local log="$1" dev
[ -e "/sys/class/net/pppoe-$log" ] && { echo "pppoe-$log"; return; }
case "$log" in *pppoe*) [ -e "/sys/class/net/$log" ] && { echo "$log"; return; } ;; esac
dev=$(uci -q get network.$log.device)
[ -n "$dev" ] && [ -e "/sys/class/net/$dev" ] && { echo "$dev"; return; }
echo "$log"
}
ping_ok() {
local iface="$1" ip
for ip in $CHECK_IPS; do
ping -I "$iface" -c 1 -W "$PING_TIMEOUT" "$ip" >/dev/null 2>&1 && return 0
done
return 1
}
flush_ct() {
[ -e /proc/net/nf_conntrack ] && echo f > /proc/net/nf_conntrack
[ -e /proc/net/ip_conntrack ] && echo f > /proc/net/ip_conntrack
return 0
}
DEV=$(phys_iface "$PRIMARY")
if [ -f "$LOCK" ]; then
OK_N=0; [ -f "$OK_FILE" ] && OK_N=$(cat "$OK_FILE")
if ping_ok "$DEV"; then
OK_N=$((OK_N + 1))
if [ "$OK_N" -ge "$REC_AT" ]; then
rm -f "$LOCK" "$FAIL_FILE" "$OK_FILE"
flush_ct
logger -t qa-failover-preset "PRIMARY $PRIMARY recovered"
else
echo "$OK_N" > "$OK_FILE"
fi
else
echo 0 > "$OK_FILE"
fi
exit 0
fi
if ping_ok "$DEV"; then
rm -f "$FAIL_FILE"
exit 0
fi
FAIL_N=0; [ -f "$FAIL_FILE" ] && FAIL_N=$(cat "$FAIL_FILE")
FAIL_N=$((FAIL_N + 1))
echo "$FAIL_N" > "$FAIL_FILE"
if [ "$FAIL_N" -ge "$FAIL_AT" ]; then
touch "$LOCK"; rm -f "$FAIL_FILE"; flush_ct
logger -t qa-failover-preset "PRIMARY $PRIMARY DOWN after $FAIL_AT failures"
fi
exit 0
FO_EOF
fi
chmod 755 "$path"
uci -q set "quickactions.$sid=script"
uci -q set "quickactions.$sid.name=Failover-lite"
uci -q set "quickactions.$sid.category=failover"
uci -q set "quickactions.$sid.path=$path"
uci -q set "quickactions.$sid.enabled=0"
uci -q set "quickactions.$sid.timeout=30"
uci -q set "quickactions.$sid.description=MWAN3 substitute: ping test + conntrack flush"
uci -q commit quickactions
json_init
json_add_string "sid" "$sid"
json_add_string "path" "$path"
json_add_boolean "ok" 1
json_dump
}
call_method() {
local method="$1"
case "$method" in
list) method_list ;;
read) method_read ;;
write) method_write ;;
delete) method_delete ;;
run) method_run ;;
chmod) method_chmod ;;
detail) method_detail ;;
install_preset) method_install_preset ;;
*) cat >/dev/null
json_init
json_add_string "error" "unknown_method"
json_dump ;;
esac
}
case "$1" in
list) list_methods ;;
call) call_method "$2" ;;
*) echo '{"error":"usage"}' ;;
esac