mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-31 15:45:13 +08:00
💋 Sync 2026-10-04 04:16:09
This commit is contained in:
1 parent
f6b2df73ec
commit
f62992fd80
745 files changed
+212416
-1173
No files matched your search
@@ -0,0 +1,52 @@
|
||||
package quickactions
|
||||
|
||||
config settings 'global'
|
||||
option poll_interval '5'
|
||||
option design_style '3d'
|
||||
|
||||
config mapping
|
||||
option keyword 'reboot'
|
||||
option service 'system'
|
||||
option dangerous '1'
|
||||
option icon '⚠️'
|
||||
|
||||
config essential 'reboot'
|
||||
option label 'Reboot Router'
|
||||
option icon '🔄'
|
||||
option command '/sbin/reboot'
|
||||
option confirm '1'
|
||||
|
||||
config essential 'shutdown'
|
||||
option label 'Shutdown'
|
||||
option icon '⏻'
|
||||
option command '/sbin/poweroff'
|
||||
option confirm '1'
|
||||
|
||||
config essential 'wifi_toggle'
|
||||
option label 'WiFi Off/On'
|
||||
option icon '📶'
|
||||
option command '/usr/bin/quickactions-wifi-toggle'
|
||||
option confirm '1'
|
||||
|
||||
config essential 'cache_clear'
|
||||
option label 'Clear LuCI Cache'
|
||||
option icon '🧹'
|
||||
option command 'rm -rf /tmp/luci-indexcache /tmp/luci-modulecache*; /etc/init.d/rpcd restart; /etc/init.d/uhttpd restart'
|
||||
option confirm '0'
|
||||
|
||||
config shortcut 'openvpn'
|
||||
option label 'OpenVPN'
|
||||
option icon '🔒'
|
||||
option path 'admin/services/openvpn'
|
||||
|
||||
config shortcut 'firewall'
|
||||
option label 'Firewall'
|
||||
option icon '🛡️'
|
||||
option path 'admin/network/firewall'
|
||||
|
||||
config essential 'backup'
|
||||
option order '14'
|
||||
option label 'Download Config Backup'
|
||||
option icon '💾'
|
||||
option command '/sbin/sysupgrade -b /tmp/backup-$(date +%Y%m%d-%H%M%S).tar.gz && ls -la /tmp/backup-*.tar.gz | tail -1'
|
||||
option confirm '0'
|
||||
@@ -0,0 +1,3 @@
|
||||
config global 'global'
|
||||
option customscript ' '
|
||||
option customscript2 ' '
|
||||
@@ -0,0 +1 @@
|
||||
config wizard 'default'
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
# Flush conntrack when a watched WAN interface goes up or down.
|
||||
# Watched list = primary + backups from /etc/config/quickactions failover.
|
||||
|
||||
[ "$ACTION" = "ifup" ] || [ "$ACTION" = "ifdown" ] || exit 0
|
||||
|
||||
. /lib/functions.sh
|
||||
config_load quickactions
|
||||
|
||||
config_get WATCH failover primary ""
|
||||
config_get BACKUPS failover backups ""
|
||||
|
||||
IFACE="$INTERFACE"
|
||||
for i in $WATCH $BACKUPS; do
|
||||
if [ "$i" = "$IFACE" ]; then
|
||||
if [ -e /proc/net/nf_conntrack ]; then
|
||||
echo f > /proc/net/nf_conntrack
|
||||
elif [ -e /proc/net/ip_conntrack ]; then
|
||||
echo f > /proc/net/ip_conntrack
|
||||
fi
|
||||
logger -t quickactions-hotplug "IFACE $IFACE $ACTION; conntrack flushed"
|
||||
break
|
||||
fi
|
||||
done
|
||||
exit 0
|
||||
@@ -0,0 +1,30 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
START=95
|
||||
STOP=05
|
||||
USE_PROCD=0
|
||||
|
||||
HP=/etc/hotplug.d/iface/99-quickactions-conntrack-flush
|
||||
CRON_LINE="* * * * * /usr/bin/wan-watchdog.sh"
|
||||
|
||||
start() {
|
||||
en=$(uci -q get quickactions.failover.enabled)
|
||||
[ -z "$en" ] && en=1
|
||||
if [ "$en" = "1" ]; then
|
||||
[ -f "$HP" ] && chmod 755 "$HP"
|
||||
(crontab -l 2>/dev/null | grep -v "wan-watchdog.sh"; echo "$CRON_LINE") | crontab -
|
||||
else
|
||||
[ -f "$HP" ] && chmod 644 "$HP"
|
||||
crontab -l 2>/dev/null | grep -v "wan-watchdog.sh" | crontab -
|
||||
fi
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
stop() {
|
||||
crontab -l 2>/dev/null | grep -v "wan-watchdog.sh" | crontab -
|
||||
/etc/init.d/cron restart
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=90
|
||||
STOP=10
|
||||
|
||||
# Unique path prefix so this coexists with the original hotplug-generator
|
||||
IFACE_PATH="/etc/hotplug.d/iface/91-qa-hp"
|
||||
|
||||
add_iface_rule() {
|
||||
local enabled action command description interface target
|
||||
config_get enabled "$1" enabled
|
||||
[ "$enabled" = "0" ] && return
|
||||
config_get action "$1" action
|
||||
config_get description "$1" description
|
||||
config_get interface "$1" interface
|
||||
|
||||
[ -z "$action" ] && return
|
||||
[ -z "$interface" ] && return
|
||||
|
||||
target="$IFACE_PATH-$1"
|
||||
{
|
||||
echo "#!/bin/sh"
|
||||
echo "# Generated by luci-app-quickactions - do not edit directly"
|
||||
echo "# Source: /etc/config/hotplug section [$1]"
|
||||
description=$(echo $description | tr '\n' ' ')
|
||||
echo "# Description: $description"
|
||||
echo ""
|
||||
echo "if [ \"\$ACTION\" = \"$action\" ]; then"
|
||||
echo " if [ \"\$INTERFACE\" = \"$interface\" ]; then"
|
||||
} > "$target"
|
||||
|
||||
command_list=$(uci -q get "hotplug.$1.command")
|
||||
[ "${command_list:0:1}" = "'" ] && command_list="${command_list:1}"
|
||||
[ "${command_list: -1}" = "'" ] && command_list="${command_list%?}"
|
||||
i=0
|
||||
while true ; do
|
||||
i=$((i+1))
|
||||
command=$(echo "$command_list" | awk -v i=$i -F "' '" '{print $i}')
|
||||
[ -z "$command" ] && break
|
||||
echo " $command" >> "$target"
|
||||
done
|
||||
|
||||
{
|
||||
echo " fi"
|
||||
echo "fi"
|
||||
echo "exit 0"
|
||||
} >> "$target"
|
||||
chmod 755 "$target"
|
||||
}
|
||||
|
||||
start() {
|
||||
mkdir -p /etc/hotplug.d/iface
|
||||
rm -f "${IFACE_PATH}-"* 2>/dev/null
|
||||
config_load hotplug
|
||||
config_foreach add_iface_rule iface
|
||||
logger -t quickactions-hotplug "Handlers regenerated from /etc/config/hotplug"
|
||||
}
|
||||
|
||||
stop() {
|
||||
rm -f "${IFACE_PATH}-"* 2>/dev/null
|
||||
logger -t quickactions-hotplug "Handlers removed"
|
||||
}
|
||||
|
||||
restart() {
|
||||
stop
|
||||
start
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
USE_PROCD=1
|
||||
|
||||
SHORTCUT_APPLIER=/usr/libexec/quickactions-netwizard/apply-shortcuts.sh
|
||||
|
||||
clean_shortcuts() {
|
||||
local sec
|
||||
for sec in $(uci -q show nginx 2>/dev/null | sed -n "s/^nginx\.\(_sc_[^=.]*\)=server$/\1/p"); do
|
||||
uci -q delete nginx."$sec"
|
||||
done
|
||||
for sec in $(uci -q show dhcp 2>/dev/null | sed -n "s/^dhcp\.\(_sc_[^=.]*\)=domain$/\1/p"); do
|
||||
uci -q delete dhcp."$sec"
|
||||
done
|
||||
}
|
||||
|
||||
process_shortcut() {
|
||||
local shortcut to_url lanaddr cfg="$1"
|
||||
lanaddr="$(uci -q get network.lan.ipaddr | tr ' ' '\n' | head -n1)"
|
||||
lanaddr="${lanaddr%%/*}"
|
||||
[ -z "$lanaddr" ] && lanaddr="10.0.0.1"
|
||||
|
||||
config_get shortcut "$cfg" shortcut
|
||||
config_get to_url "$cfg" to_url
|
||||
[ -z "$shortcut" ] || [ -z "$to_url" ] && return 0
|
||||
|
||||
if [ -f /etc/nginx/uci.conf ]; then
|
||||
SHORTCUTS_TOUCHED=1
|
||||
uci -q set nginx._sc_$shortcut=server
|
||||
uci -q set nginx._sc_$shortcut.server_name="$shortcut"
|
||||
uci -q add_list nginx._sc_$shortcut.listen="80"
|
||||
uci -q set nginx._sc_$shortcut.return="302 $to_url"
|
||||
uci -q set dhcp._sc_$shortcut=domain
|
||||
uci -q set dhcp._sc_$shortcut.name="$shortcut"
|
||||
uci -q set dhcp._sc_$shortcut.ip="$lanaddr"
|
||||
fi
|
||||
}
|
||||
|
||||
sethttps() {
|
||||
local cfg="${1:-default}" https
|
||||
config_get https "$cfg" https 0
|
||||
# Safety: only touch redirect_https if wizard.default.https is explicitly set
|
||||
local explicit
|
||||
explicit=$(uci -q get wizard.default.https)
|
||||
if [ -z "$explicit" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -x /etc/init.d/nginx ] && [ -f /etc/nginx/uci.conf ]; then
|
||||
if [ "x${https}" = "x1" ]; then
|
||||
[ -z "$(uci -q get nginx._redirect2ssl)" ] && {
|
||||
uci -q set nginx._redirect2ssl=server
|
||||
uci -q set nginx._redirect2ssl.server_name='_redirect2ssl'
|
||||
uci -q set nginx._redirect2ssl.return='302 https://$host$request_uri'
|
||||
uci -q set nginx._redirect2ssl.access_log='off;'
|
||||
}
|
||||
uci -q del nginx.default_server.listen
|
||||
uci -q add_list nginx.default_server.listen='80'
|
||||
uci -q add_list nginx.default_server.listen='[::]:80'
|
||||
uci -q del nginx._redirect2ssl.listen
|
||||
uci -q add_list nginx._redirect2ssl.listen='80 default_server'
|
||||
uci -q add_list nginx._redirect2ssl.listen='[::]:80 default_server'
|
||||
else
|
||||
uci -q delete nginx._redirect2ssl
|
||||
uci -q del nginx.default_server.listen
|
||||
uci -q add_list nginx.default_server.listen='80 default_server'
|
||||
uci -q add_list nginx.default_server.listen='[::]:80 default_server'
|
||||
fi
|
||||
uci -q commit nginx
|
||||
/etc/init.d/nginx reload >/dev/null 2>&1
|
||||
elif [ -x /etc/init.d/lighttpd ] && [ -f /etc/lighttpd/conf.d/82-https.conf ]; then
|
||||
if [ "x${https}" = "x1" ]; then
|
||||
sed -i "s/^[ \t]*#*[ \t]*url\.redirect[ \t]*=.*/\turl.redirect =/" /etc/lighttpd/conf.d/82-https.conf 2>/dev/null
|
||||
else
|
||||
sed -i "s/^[ \t]*url\.redirect[ \t]*=.*/\t# url.redirect =/" /etc/lighttpd/conf.d/82-https.conf 2>/dev/null
|
||||
fi
|
||||
/etc/init.d/lighttpd reload >/dev/null 2>&1
|
||||
elif [ -x /etc/init.d/uhttpd ]; then
|
||||
if [ "x${https}" = "x1" ]; then
|
||||
uci -q set uhttpd.main.redirect_https='1'
|
||||
else
|
||||
uci -q set uhttpd.main.redirect_https='0'
|
||||
fi
|
||||
uci -q commit uhttpd
|
||||
/etc/init.d/uhttpd reload >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
reload_services() {
|
||||
# Only commit if we actually wrote to dhcp/nginx (shortcuts changed)
|
||||
if [ "$SHORTCUTS_TOUCHED" = "1" ]; then
|
||||
uci -q commit dhcp
|
||||
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq reload >/dev/null 2>&1
|
||||
if [ -f /etc/nginx/uci.conf ] && [ -x /etc/init.d/nginx ]; then
|
||||
uci -q commit nginx
|
||||
/etc/init.d/nginx reload >/dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
SHORTCUTS_TOUCHED=0
|
||||
|
||||
start_service() {
|
||||
config_load wizard
|
||||
|
||||
# Cookie persist → luci.sgi (only if wizard.default.persistent_cookies is explicitly set)
|
||||
local explicit_pc
|
||||
explicit_pc=$(uci -q get wizard.default.persistent_cookies)
|
||||
if [ -n "$explicit_pc" ]; then
|
||||
[ -z "$(uci -q get luci.sgi)" ] && uci -q set luci.sgi=sgi
|
||||
uci -q set luci.sgi.persistent_cookies="$explicit_pc"
|
||||
uci -q commit luci
|
||||
fi
|
||||
|
||||
# Shortcuts (nginx + dnsmasq)
|
||||
clean_shortcuts
|
||||
config_foreach process_shortcut shortcuts
|
||||
|
||||
# HTTPS redirect
|
||||
sethttps default
|
||||
|
||||
reload_services
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
clean_shortcuts
|
||||
reload_services
|
||||
}
|
||||
|
||||
service_triggers() {
|
||||
procd_add_reload_trigger "wizard"
|
||||
}
|
||||
|
||||
boot() {
|
||||
start "$@"
|
||||
# Background coremark if enabled and not yet run
|
||||
local cm
|
||||
cm=$(uci -q get wizard.@wizard[0].coremark)
|
||||
[ "$cm" = "1" ] || cm=$(uci -q get wizard.default.coremark)
|
||||
if [ "$cm" = "1" ] && [ ! -f /etc/bench.log ]; then
|
||||
(sleep 5; /sbin/coremark >/dev/null 2>&1) &
|
||||
fi
|
||||
}
|
||||
+135
@@ -0,0 +1,135 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Merged from luci-app-taskplan — full independence edition
|
||||
# Author: sirpdboy (original) / quickactions merge
|
||||
|
||||
START=99
|
||||
STOP=10
|
||||
TMP=/etc/quickactions-taskplan
|
||||
LOG=$TMP/taskplan.log
|
||||
TT=$TMP/taskplanrun
|
||||
CR=/etc/crontabs/root
|
||||
HANDLER=/usr/bin/quickactions-taskplanhandler
|
||||
|
||||
[ ! -d $TMP ] && mkdir -p $TMP 2>/dev/null
|
||||
[ ! -s $LOG ] && echo '' > $LOG
|
||||
|
||||
run_taskplan()
|
||||
{
|
||||
[ -n "$(uci -q get taskplan.@global[0].customscript)" ] && \
|
||||
uci -q get taskplan.@global[0].customscript > $TMP/taskplancustomscript && \
|
||||
sed -i 's/\r$//' $TMP/taskplancustomscript
|
||||
|
||||
[ -n "$(uci -q get taskplan.@global[0].customscript2)" ] && \
|
||||
uci -q get taskplan.@global[0].customscript2 > $TMP/taskplancustomscript2 && \
|
||||
sed -i 's/\r$//' $TMP/taskplancustomscript2
|
||||
|
||||
ssum=$(uci -q show taskplan | grep -c "stime\[[0-9]\]" || echo 0)
|
||||
lsum=$(uci -q show taskplan | grep -c "ltime\[[0-9]\]" || echo 0)
|
||||
|
||||
sed -i '/quickactions-taskplanhandler/d' $CR >/dev/null 2>&1
|
||||
|
||||
for i in $(seq 0 $((ssum-1)) 2>/dev/null); do
|
||||
enable=$(uci -q get taskplan.@stime[$i].enable)
|
||||
if [ "x$enable" = "x1" ]; then
|
||||
month=$(uci -q get taskplan.@stime[$i].month || echo "*")
|
||||
stype=$(uci -q get taskplan.@stime[$i].stype)
|
||||
week=$(uci -q get taskplan.@stime[$i].week || echo "*")
|
||||
minute=$(uci -q get taskplan.@stime[$i].minute || echo "0")
|
||||
hour=$(uci -q get taskplan.@stime[$i].hour || echo "*")
|
||||
|
||||
[ "$hour" = "0" ] && hour="0"
|
||||
[ "$minute" = "0" ] && minute="0"
|
||||
|
||||
case "$stype" in
|
||||
1) cmd="$minute $hour * $month $week $HANDLER reboot Scheduled_task" ;;
|
||||
2) cmd="$minute $hour * $month $week $HANDLER poweroff Scheduled_task" ;;
|
||||
3) cmd="$minute $hour * $month $week $HANDLER network Scheduled_task" ;;
|
||||
4) cmd="$minute $hour * $month $week $HANDLER restartsamba Scheduled_task" ;;
|
||||
5) cmd="$minute $hour * $month $week $HANDLER restartwan Scheduled_task" ;;
|
||||
6) cmd="$minute $hour * $month $week $HANDLER closewan Scheduled_task" ;;
|
||||
7) cmd="$minute $hour * $month $week $HANDLER clearmem Scheduled_task" ;;
|
||||
8) cmd="$minute $hour * $month $week $HANDLER sysfree Scheduled_task" ;;
|
||||
9) cmd="$minute $hour * $month $week $HANDLER disreconn Scheduled_task" ;;
|
||||
10) cmd="$minute $hour * $month $week $HANDLER disrereboot Scheduled_task" ;;
|
||||
11) cmd="$minute $hour * $month $week $HANDLER restartmwan3 Scheduled_task" ;;
|
||||
12) cmd="$minute $hour * $month $week $HANDLER customscript Scheduled_task" ;;
|
||||
13) cmd="$minute $hour * $month $week $HANDLER upwifi Scheduled_task" ;;
|
||||
14) cmd="$minute $hour * $month $week $HANDLER downwifi Scheduled_task" ;;
|
||||
15) cmd="$minute $hour * $month $week $HANDLER customscript2 Scheduled_task" ;;
|
||||
16) cmd="$minute $hour * $month $week $HANDLER restartlan Scheduled_task" ;;
|
||||
esac
|
||||
echo "$cmd" >> $CR
|
||||
fi
|
||||
done
|
||||
|
||||
echo "#!/bin/sh" > $TT
|
||||
chmod +x $TT
|
||||
|
||||
for i in $(seq 0 $((lsum-1)) 2>/dev/null); do
|
||||
enable=$(uci -q get taskplan.@ltime[$i].enable)
|
||||
if [ "x$enable" = "x1" ]; then
|
||||
stype=$(uci -q get taskplan.@ltime[$i].stype)
|
||||
delay=$(uci -q get taskplan.@ltime[$i].delay || echo 10)
|
||||
|
||||
case "$stype" in
|
||||
1) echo "(sleep $delay && $HANDLER reboot Startup_task) &" >>$TT ;;
|
||||
2) echo "(sleep $delay && $HANDLER poweroff Startup_task) &" >>$TT ;;
|
||||
3) echo "(sleep $delay && $HANDLER network Startup_task) &" >>$TT ;;
|
||||
4) echo "(sleep $delay && $HANDLER restartsamba Startup_task) &" >>$TT ;;
|
||||
5) echo "(sleep $delay && $HANDLER restartwan Startup_task) &" >>$TT ;;
|
||||
6) echo "(sleep $delay && $HANDLER closewan Startup_task) &" >>$TT ;;
|
||||
7) echo "(sleep $delay && $HANDLER clearmem Startup_task) &" >>$TT ;;
|
||||
8) echo "(sleep $delay && $HANDLER sysfree Startup_task) &" >>$TT ;;
|
||||
9) echo "(sleep $delay && $HANDLER disreconn Startup_task) &" >>$TT ;;
|
||||
10) echo "(sleep $delay && $HANDLER disrereboot Startup_task) &" >>$TT ;;
|
||||
11) echo "(sleep $delay && $HANDLER restartmwan3 Startup_task) &" >>$TT ;;
|
||||
12) echo "(sleep $delay && $HANDLER customscript Startup_task) &" >>$TT ;;
|
||||
13) echo "(sleep $delay && $HANDLER upwifi Startup_task) &" >>$TT ;;
|
||||
14) echo "(sleep $delay && $HANDLER downwifi Startup_task) &" >>$TT ;;
|
||||
15) echo "(sleep $delay && $HANDLER customscript2 Startup_task) &" >>$TT ;;
|
||||
16) echo "(sleep $delay && $HANDLER restartlan Startup_task) &" >>$TT ;;
|
||||
esac
|
||||
fi
|
||||
done
|
||||
|
||||
echo 'exit 0' >> $TT
|
||||
}
|
||||
|
||||
start()
|
||||
{
|
||||
del_cru
|
||||
run_taskplan
|
||||
/etc/init.d/cron reload
|
||||
echo "$(date): quickactions-taskplan started" >> $LOG
|
||||
}
|
||||
|
||||
boot()
|
||||
{
|
||||
del_cru
|
||||
run_taskplan
|
||||
/etc/init.d/cron reload
|
||||
if [ -f $TT ] && [ -s $TT ]; then
|
||||
echo "$(date +'%Y-%m-%d %H:%M:%S'): Executing taskplanrun at boot" >> $LOG
|
||||
if command -v bash >/dev/null 2>&1; then bash $TT >> $LOG 2>&1 & else sh $TT >> $LOG 2>&1 & fi
|
||||
fi
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
del_cru
|
||||
/etc/init.d/cron reload
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
stop
|
||||
sleep 2
|
||||
start
|
||||
}
|
||||
|
||||
del_cru()
|
||||
{
|
||||
sed -i '/quickactions-taskplanhandler/d' $CR >/dev/null 2>&1 || true
|
||||
echo "#!/bin/sh" > $TT
|
||||
chmod +x $TT
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/sh
|
||||
# Seed failover config on first install + append our scripts to sysupgrade.conf.
|
||||
|
||||
# ---- 1. Failover config ----
|
||||
have=0
|
||||
[ -f /etc/config/quickactions ] && have=$(uci -q get quickactions.failover.primary)
|
||||
if [ -z "$have" ]; then
|
||||
uci -q set quickactions.failover=failover
|
||||
uci -q set quickactions.failover.enabled=1
|
||||
uci -q set quickactions.failover.primary=wan
|
||||
uci -q set quickactions.failover.backups="wanb wanbpppoe usbwan wandhcp"
|
||||
uci -q set quickactions.failover.check_ips="1.1.1.1 8.8.8.8"
|
||||
uci -q set quickactions.failover.check_interval=60
|
||||
uci -q set quickactions.failover.ping_timeout=5
|
||||
uci -q set quickactions.failover.fail_threshold=2
|
||||
uci -q set quickactions.failover.recover_threshold=1
|
||||
uci -q set quickactions.failover.tailscale_restart=0
|
||||
uci -q set quickactions.failover.firewall_reset=1
|
||||
uci -q set quickactions.failover.log_healthy=0
|
||||
uci -q commit quickactions
|
||||
fi
|
||||
|
||||
# ---- 2. Persist scripts through sysupgrade ----
|
||||
for f in /usr/bin/wan-watchdog.sh \
|
||||
/usr/bin/quickactions-failover \
|
||||
/etc/hotplug.d/iface/99-quickactions-conntrack-flush
|
||||
do
|
||||
grep -qxF "$f" /etc/sysupgrade.conf 2>/dev/null || echo "$f" >> /etc/sysupgrade.conf
|
||||
done
|
||||
|
||||
# ---- 3. Activate the failover subsystem ----
|
||||
/etc/init.d/quickactions-failover start >/dev/null 2>&1
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
# Seed /etc/config/guestwifi on first install only.
|
||||
# Never overwrites an existing config → survives upgrades cleanly.
|
||||
[ -f /etc/config/guestwifi ] && exit 0
|
||||
|
||||
cat > /etc/config/guestwifi << 'CONF'
|
||||
# Guest WiFi configuration managed by luci-app-quickactions
|
||||
CONF
|
||||
exit 0
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
# Seed /etc/config/hotplug if the user has no rules yet.
|
||||
# The Hotplug tab in luci-app-quickactions writes to this config.
|
||||
[ -f /etc/config/hotplug ] && exit 0
|
||||
cat > /etc/config/hotplug << 'CONF'
|
||||
# Hotplug rules managed by luci-app-quickactions
|
||||
#
|
||||
# iface sections - run commands on network interface events.
|
||||
# Example:
|
||||
# config iface 'wan_up'
|
||||
# option action 'ifup'
|
||||
# option enabled '1'
|
||||
# option interface 'wan'
|
||||
# list command '/etc/init.d/firewall restart'
|
||||
CONF
|
||||
exit 0
|
||||
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Create seed configs only if missing. Do NOT touch network, firewall, dhcp, wireless.
|
||||
[ -f /etc/config/wizard ] || echo "config wizard 'default'" > /etc/config/wizard
|
||||
[ -f /etc/config/netwizard ] || printf "config netwizard 'default'\n\toption lan_netmask '255.255.255.0'\n" > /etc/config/netwizard
|
||||
|
||||
# Ensure scripts are executable
|
||||
chmod +x /usr/libexec/quickactions-netwizard/*.sh 2>/dev/null
|
||||
|
||||
# Enable the init so shortcuts/https/coremark hooks work
|
||||
/etc/init.d/quickactions-netwizard enable 2>/dev/null
|
||||
/etc/init.d/quickactions-netwizard start 2>/dev/null
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
mkdir -p /etc/quickactions/scripts
|
||||
chmod 755 /etc/quickactions/scripts
|
||||
exit 0
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
[ -f /etc/config/taskplan ] || cat > /etc/config/taskplan << 'EOF'
|
||||
config global 'global'
|
||||
option customscript ' '
|
||||
option customscript2 ' '
|
||||
EOF
|
||||
|
||||
mkdir -p /etc/quickactions-taskplan
|
||||
touch /etc/quickactions-taskplan/taskplan.log
|
||||
chmod 600 /etc/quickactions-taskplan/taskplan.log
|
||||
chmod +x /usr/bin/quickactions-taskplanhandler
|
||||
chmod +x /etc/init.d/quickactions-taskplan
|
||||
chmod +x /usr/libexec/rpcd/luci.quickactions-taskplan
|
||||
exit 0
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# Seed /etc/config/taskplan with one sample stime + ltime entry
|
||||
# so the Task Plan tab is not empty on first install.
|
||||
|
||||
[ -f /etc/config/taskplan ] || touch /etc/config/taskplan
|
||||
|
||||
# Only seed if there are no stime/ltime sections yet
|
||||
if ! uci -q show taskplan | grep -q "taskplan.@stime\|taskplan.@ltime"; then
|
||||
# Ensure global exists
|
||||
uci -q get taskplan.@global[0] >/dev/null 2>&1 || \
|
||||
uci set taskplan.@global[0]=global
|
||||
|
||||
# Sample scheduled task: daily reboot at 04:00
|
||||
sec=$(uci add taskplan stime)
|
||||
uci set taskplan.$sec.remarks='Daily Reboot'
|
||||
uci set taskplan.$sec.enable='0'
|
||||
uci set taskplan.$sec.stype='1'
|
||||
uci set taskplan.$sec.month='*'
|
||||
uci set taskplan.$sec.week='*'
|
||||
uci set taskplan.$sec.hour='4'
|
||||
uci set taskplan.$sec.minute='0'
|
||||
|
||||
# Sample startup task: clear memory 30s after boot
|
||||
sec=$(uci add taskplan ltime)
|
||||
uci set taskplan.$sec.remarks='Startup: Clear Memory'
|
||||
uci set taskplan.$sec.enable='0'
|
||||
uci set taskplan.$sec.stype='7'
|
||||
uci set taskplan.$sec.delay='30'
|
||||
|
||||
uci commit taskplan
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
# Seed the VLAN working directories on first install.
|
||||
mkdir -p /etc/quickactions/vlan/templates
|
||||
mkdir -p /etc/quickactions/vlan/generated
|
||||
chmod 755 /etc/quickactions/vlan /etc/quickactions/vlan/templates /etc/quickactions/vlan/generated
|
||||
|
||||
# Default config section
|
||||
have=$(uci -q get quickactions.vlan.tier)
|
||||
if [ -z "$have" ]; then
|
||||
uci -q set quickactions.vlan=vlan
|
||||
uci -q set quickactions.vlan.tier=auto
|
||||
uci -q set quickactions.vlan.snapshot_keep=20
|
||||
uci -q commit quickactions
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# Master switch for the quickactions failover system.
|
||||
# quickactions-failover on|off|status|test
|
||||
|
||||
LOCK=/tmp/quickactions_wan_down.lock
|
||||
FAILS=/tmp/quickactions_wan_fails.count
|
||||
OKS=/tmp/quickactions_wan_oks.count
|
||||
HP=/etc/hotplug.d/iface/99-quickactions-conntrack-flush
|
||||
CRON_LINE="* * * * * /usr/bin/wan-watchdog.sh"
|
||||
|
||||
case "$1" in
|
||||
on)
|
||||
uci -q set quickactions.failover.enabled=1
|
||||
uci -q commit quickactions
|
||||
[ -f "$HP" ] && chmod 755 "$HP"
|
||||
(crontab -l 2>/dev/null | grep -v "wan-watchdog.sh"; echo "$CRON_LINE") | crontab -
|
||||
/etc/init.d/cron restart
|
||||
echo "ENABLED"
|
||||
logger -t quickactions-failover "master switch: enabled"
|
||||
;;
|
||||
off)
|
||||
uci -q set quickactions.failover.enabled=0
|
||||
uci -q commit quickactions
|
||||
[ -f "$HP" ] && chmod 644 "$HP"
|
||||
crontab -l 2>/dev/null | grep -v "wan-watchdog.sh" | crontab -
|
||||
rm -f "$LOCK" "$FAILS" "$OKS"
|
||||
/etc/init.d/cron restart
|
||||
echo "DISABLED"
|
||||
logger -t quickactions-failover "master switch: disabled"
|
||||
;;
|
||||
status)
|
||||
en=$(uci -q get quickactions.failover.enabled)
|
||||
[ -z "$en" ] && en=1
|
||||
[ "$en" = "1" ] && echo "STATUS: [ON]" || echo "STATUS: [OFF]"
|
||||
[ -f "$LOCK" ] && echo "MODE: [BACKUP]" || echo "MODE: [PRIMARY]"
|
||||
;;
|
||||
test)
|
||||
/usr/bin/wan-watchdog.sh
|
||||
echo "manual run complete"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: quickactions-failover [on|off|status|test]"
|
||||
;;
|
||||
esac
|
||||
exit 0
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/bin/sh
|
||||
# Merged from luci-app-taskplan — quickactions edition
|
||||
|
||||
# Use bash if available, else fall back to busybox sh
|
||||
if command -v bash >/dev/null 2>&1; then
|
||||
SHELL_BIN=/bin/bash
|
||||
else
|
||||
SHELL_BIN=/bin/sh
|
||||
fi
|
||||
|
||||
# Author: sirpdboy (original) / quickactions merge
|
||||
|
||||
TMP_T=/var/quickactions-taskplan/taskplan.tmp
|
||||
LOG=/etc/quickactions-taskplan/taskplan.log
|
||||
CUSTOM_DIR=/etc/quickactions-taskplan
|
||||
|
||||
log(){
|
||||
echo "$(date +'%Y-%m-%d %H:%M:%S') $*" >> $LOG
|
||||
}
|
||||
|
||||
limit_log() {
|
||||
local logf=$1
|
||||
[ ! -f "$logf" ] && return
|
||||
local sc=100
|
||||
[ -n "$2" ] && sc=$2
|
||||
local count=$(grep -c "" $logf 2>/dev/null || echo 0)
|
||||
if [ $count -gt $sc ]; then
|
||||
let count=count-$sc
|
||||
sed -i "1,$count d" $logf 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
remwan3() {
|
||||
while true; do
|
||||
status=$(/usr/sbin/mwan3 status 2>/dev/null | grep -i error)
|
||||
if [ -z "$status" ]; then
|
||||
log "Mwan3 is OK"
|
||||
exit 0
|
||||
else
|
||||
log "mwan3 restarting ..."
|
||||
/usr/sbin/mwan3 restart
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
}
|
||||
|
||||
disreconnwan() {
|
||||
i=0
|
||||
PingA=114.114.114.114
|
||||
PingB=223.5.5.5
|
||||
PingErr=1
|
||||
|
||||
while [ $i -lt 5 ]; do
|
||||
if ping -c 1 -W 3 $PingA >/dev/null 2>&1; then
|
||||
PingErr=0
|
||||
break
|
||||
elif ping -c 1 -W 3 $PingB >/dev/null 2>&1; then
|
||||
PingErr=0
|
||||
break
|
||||
else
|
||||
i=$((i + 1))
|
||||
sleep 10
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
trigger() {
|
||||
case "$1" in
|
||||
reboot) reboot ;;
|
||||
poweroff) poweroff ;;
|
||||
network) /etc/init.d/network restart ;;
|
||||
clearmem) sync && echo 3 > /proc/sys/vm/drop_caches ;;
|
||||
sysfree)
|
||||
cd /overlay
|
||||
rm -rf $(ls | egrep -v '(upper|.fs_state)') 2>/dev/null
|
||||
cd upper 2>/dev/null
|
||||
rm -rf $(ls | egrep -v '(etc)') 2>/dev/null
|
||||
cd etc 2>/dev/null
|
||||
rm -rf $(ls | egrep -v '(config|ssr|bench.log|shadow)') 2>/dev/null
|
||||
rm -rf /var/luci-modulecache 2>/dev/null
|
||||
rm -rf /var/luci-indexcache 2>/dev/null
|
||||
rm -rf /tmp/cache/* 2>/dev/null
|
||||
reboot ;;
|
||||
restartsamba)
|
||||
/etc/init.d/ksmdb restart 2>/dev/null
|
||||
/etc/init.d/samba restart 2>/dev/null
|
||||
/etc/init.d/samba4 restart 2>/dev/null
|
||||
log "Samba restarted" ;;
|
||||
restartlan) ifdown lan && ifup lan; log "restart lan succeeded!" ;;
|
||||
restartwan) ifup wan; log "restart wan succeeded!" ;;
|
||||
closewan) ifdown wan ;;
|
||||
disreconn)
|
||||
disreconnwan
|
||||
if [ $PingErr = 1 ]; then ifup wan; log "Redial succeeded!"; fi ;;
|
||||
disrereboot)
|
||||
disreconnwan
|
||||
if [ $PingErr = 1 ]; then log "Reboot succeeded!"; reboot; fi ;;
|
||||
restartmwan3) [ -x /usr/sbin/mwan3 ] && remwan3 ;;
|
||||
customscript)
|
||||
if [ -s $CUSTOM_DIR/taskplancustomscript ]; then
|
||||
$SHELL_BIN $CUSTOM_DIR/taskplancustomscript
|
||||
log "CustomScript succeeded!"
|
||||
else log "CustomScript run Error!"; fi ;;
|
||||
customscript2)
|
||||
if [ -s $CUSTOM_DIR/taskplancustomscript2 ]; then
|
||||
$SHELL_BIN $CUSTOM_DIR/taskplancustomscript2
|
||||
log "CustomScript2 succeeded!"
|
||||
else log "CustomScript2 run Error!"; fi ;;
|
||||
upwifi)
|
||||
ifconfig wlan0 up 2>/dev/null
|
||||
uci set wireless.radio0.disabled=0 2>/dev/null
|
||||
uci set wireless.radio1.disabled=0 2>/dev/null
|
||||
uci commit wireless 2>/dev/null
|
||||
wifi up ;;
|
||||
downwifi)
|
||||
ifconfig wlan0 down 2>/dev/null
|
||||
uci set wireless.radio0.disabled=1 2>/dev/null
|
||||
uci set wireless.radio1.disabled=1 2>/dev/null
|
||||
uci commit wireless 2>/dev/null
|
||||
wifi down ;;
|
||||
esac
|
||||
}
|
||||
|
||||
limit_log $LOG 500
|
||||
PingErr=0
|
||||
log "Scheduled operation $2: $1" && trigger $1
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
# Quick Actions — toggle all WiFi radios on/off
|
||||
if wifi status 2>/dev/null | grep -qE '"up":[[:space:]]*true'; then
|
||||
wifi down
|
||||
logger -t quickactions "WiFi turned OFF"
|
||||
echo "WiFi turned OFF"
|
||||
else
|
||||
wifi up
|
||||
logger -t quickactions "WiFi turned ON"
|
||||
echo "WiFi turned ON"
|
||||
fi
|
||||
exit 0
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
#!/bin/sh
|
||||
# quickactions WAN failover watchdog.
|
||||
# Runs from cron every N seconds. Reads config from
|
||||
# /etc/config/quickactions section 'failover'. Zero background RAM when idle.
|
||||
|
||||
. /lib/functions.sh
|
||||
|
||||
config_load quickactions
|
||||
|
||||
cfg() {
|
||||
local v
|
||||
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)
|
||||
TAILSCALE_RESTART=$(cfg tailscale_restart 0)
|
||||
FIREWALL_RESET=$(cfg firewall_reset 1)
|
||||
LOG_HEALTHY=$(cfg log_healthy 0)
|
||||
|
||||
LOCK=/tmp/quickactions_wan_down.lock
|
||||
FAILS=/tmp/quickactions_wan_fails.count
|
||||
OKS=/tmp/quickactions_wan_oks.count
|
||||
|
||||
# Logical interface name -> kernel device name
|
||||
phys_iface() {
|
||||
local log="$1" dev
|
||||
# pppoe-* style kernel interface
|
||||
if [ -e "/sys/class/net/pppoe-$log" ]; then echo "pppoe-$log"; return; fi
|
||||
# interface with pppoe in the name
|
||||
case "$log" in
|
||||
*pppoe*) [ -e "/sys/class/net/$log" ] && { echo "$log"; return; } ;;
|
||||
esac
|
||||
# read device from UCI network
|
||||
dev=$(uci -q get network.$log.device)
|
||||
[ -n "$dev" ] && [ -e "/sys/class/net/$dev" ] && { echo "$dev"; return; }
|
||||
# fallback
|
||||
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() {
|
||||
if [ -e /proc/net/nf_conntrack ]; then
|
||||
echo f > /proc/net/nf_conntrack
|
||||
elif [ -e /proc/net/ip_conntrack ]; then
|
||||
echo f > /proc/net/ip_conntrack
|
||||
fi
|
||||
}
|
||||
|
||||
PRIMARY_DEV=$(phys_iface "$PRIMARY")
|
||||
|
||||
# Recovery mode: we believe primary is down; check if it's back
|
||||
if [ -f "$LOCK" ]; then
|
||||
OKS=0
|
||||
[ -f "$OKS" ] && OKS=$(cat "$OKS" 2>/dev/null)
|
||||
if ping_ok "$PRIMARY_DEV"; then
|
||||
OKS=$((OKS + 1))
|
||||
if [ "$OKS" -ge "$REC_AT" ]; then
|
||||
rm -f "$LOCK" "$FAILS" "$OKS"
|
||||
flush_ct
|
||||
logger -t quickactions-failover "PRIMARY $PRIMARY recovered; conntrack flushed"
|
||||
[ "$TAILSCALE_RESTART" = "1" ] && /etc/init.d/tailscale restart 2>/dev/null
|
||||
else
|
||||
echo "$OKS" > "$OKS"
|
||||
fi
|
||||
else
|
||||
echo 0 > "$OKS"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Normal mode: is primary healthy?
|
||||
if ping_ok "$PRIMARY_DEV"; then
|
||||
rm -f "$FAILS"
|
||||
[ "$LOG_HEALTHY" = "1" ] && logger -t quickactions-failover "PRIMARY $PRIMARY HEALTHY"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Primary failed once
|
||||
FAILS=0
|
||||
[ -f "$FAILS" ] && FAILS=$(cat "$FAILS" 2>/dev/null)
|
||||
FAILS=$((FAILS + 1))
|
||||
echo "$FAILS" > "$FAILS"
|
||||
|
||||
if [ "$FAILS" -ge "$FAIL_AT" ]; then
|
||||
touch "$LOCK"
|
||||
rm -f "$FAILS"
|
||||
flush_ct
|
||||
logger -t quickactions-failover "PRIMARY $PRIMARY DOWN after $FAIL_AT failures; failover engaged"
|
||||
if [ "$FIREWALL_RESET" = "1" ]; then
|
||||
/etc/init.d/firewall restart 2>/dev/null
|
||||
fi
|
||||
if [ "$TAILSCALE_RESTART" = "1" ]; then
|
||||
sleep 30
|
||||
/etc/init.d/tailscale restart 2>/dev/null
|
||||
fi
|
||||
fi
|
||||
|
||||
exit 0
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
# Aggressive rebuild — matches source netwizard behaviour. Called only if user opts in.
|
||||
|
||||
MODE="$1"; LAN_IP="$2"; PPPOE_USER="$3"; PPPOE_PASS="$4"; WAN_IFACE="$5"
|
||||
[ -z "$MODE" ] && MODE="dhcp"
|
||||
[ -z "$LAN_IP" ] && LAN_IP="192.168.10.1"
|
||||
|
||||
BACKUP_DIR="/etc/config.bak.$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
for f in network firewall dhcp wireless system wizard netwizard; do
|
||||
[ -f /etc/config/$f ] && cp /etc/config/$f "$BACKUP_DIR/"
|
||||
done
|
||||
echo "Backup saved to $BACKUP_DIR"
|
||||
|
||||
if [ -z "$WAN_IFACE" ]; then
|
||||
WAN_IFACE=$(uci -q get network.wan.device)
|
||||
[ -z "$WAN_IFACE" ] && WAN_IFACE=$(ls /sys/class/net/ 2>/dev/null | grep -E '^(eth[01]|wan)' | head -n1)
|
||||
[ -z "$WAN_IFACE" ] && WAN_IFACE="eth1"
|
||||
fi
|
||||
|
||||
uci -q delete network.wan 2>/dev/null
|
||||
uci -q delete network.wan6 2>/dev/null
|
||||
uci -q delete network.lan6 2>/dev/null
|
||||
|
||||
WAN_IDX=$(uci show firewall | sed -n "s/^firewall\.@zone\[\([0-9]*\)\]\.name='wan'$/\1/p")
|
||||
[ -n "$WAN_IDX" ] && uci -q delete firewall.@zone[$WAN_IDX] 2>/dev/null
|
||||
|
||||
if [ "$MODE" = "siderouter" ]; then
|
||||
LAN_IDX=$(uci show firewall | sed -n "s/^firewall\.@zone\[\([0-9]*\)\]\.name='lan'$/\1/p")
|
||||
[ -n "$LAN_IDX" ] && uci -q delete firewall.@zone[$LAN_IDX].masq 2>/dev/null
|
||||
uci set network.lan=interface
|
||||
uci set network.lan.proto='static'
|
||||
uci set network.lan.ipaddr="$LAN_IP"
|
||||
uci set network.lan.netmask='255.255.255.0'
|
||||
else
|
||||
uci set network.wan=interface
|
||||
uci set network.wan.device="$WAN_IFACE"
|
||||
if [ "$MODE" = "pppoe" ]; then
|
||||
uci set network.wan.proto='pppoe'
|
||||
[ -n "$PPPOE_USER" ] && uci set network.wan.username="$PPPOE_USER"
|
||||
[ -n "$PPPOE_PASS" ] && uci set network.wan.password="$PPPOE_PASS"
|
||||
else
|
||||
uci set network.wan.proto='dhcp'
|
||||
fi
|
||||
uci set network.wan6=interface
|
||||
uci set network.wan6.device="@wan"
|
||||
uci set network.wan6.proto='dhcpv6'
|
||||
|
||||
uci add firewall zone >/dev/null
|
||||
uci set firewall.@zone[-1].name='wan'
|
||||
uci set firewall.@zone[-1].input='REJECT'
|
||||
uci set firewall.@zone[-1].output='ACCEPT'
|
||||
uci set firewall.@zone[-1].forward='REJECT'
|
||||
uci set firewall.@zone[-1].masq='1'
|
||||
uci set firewall.@zone[-1].mtu_fix='1'
|
||||
uci add_list firewall.@zone[-1].network='wan'
|
||||
uci add_list firewall.@zone[-1].network='wan6'
|
||||
|
||||
uci add firewall forwarding >/dev/null
|
||||
uci set firewall.@forwarding[-1].src='lan'
|
||||
uci set firewall.@forwarding[-1].dest='wan'
|
||||
|
||||
uci set network.lan.ipaddr="$LAN_IP"
|
||||
uci set network.lan.netmask='255.255.255.0'
|
||||
fi
|
||||
|
||||
uci -q commit network
|
||||
uci -q commit firewall
|
||||
uci -q commit dhcp
|
||||
|
||||
/etc/init.d/network restart >/dev/null 2>&1 &
|
||||
sleep 2
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1 &
|
||||
/etc/init.d/dnsmasq reload >/dev/null 2>&1 &
|
||||
|
||||
echo "Aggressive apply complete. Mode: $MODE, WAN: $WAN_IFACE, LAN: $LAN_IP"
|
||||
echo "Backup: $BACKUP_DIR"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# Regenerate nginx shortcut server blocks + dnsmasq domain entries from /etc/config/wizard shortcuts.
|
||||
# Called after the user adds/removes a shortcut in the UI.
|
||||
|
||||
clean() {
|
||||
local sec
|
||||
for sec in $(uci -q show nginx 2>/dev/null | sed -n "s/^nginx\.\(_sc_[^=.]*\)=server$/\1/p"); do
|
||||
uci -q delete nginx."$sec"
|
||||
done
|
||||
for sec in $(uci -q show dhcp 2>/dev/null | sed -n "s/^dhcp\.\(_sc_[^=.]*\)=domain$/\1/p"); do
|
||||
uci -q delete dhcp."$sec"
|
||||
done
|
||||
}
|
||||
|
||||
process_one() {
|
||||
local shortcut to_url lanaddr cfg="$1"
|
||||
lanaddr="$(uci -q get network.lan.ipaddr | tr ' ' '\n' | head -n1)"
|
||||
lanaddr="${lanaddr%%/*}"
|
||||
[ -z "$lanaddr" ] && lanaddr="10.0.0.1"
|
||||
|
||||
config_get shortcut "$cfg" shortcut
|
||||
config_get to_url "$cfg" to_url
|
||||
[ -z "$shortcut" ] || [ -z "$to_url" ] && return 0
|
||||
|
||||
if [ -f /etc/nginx/uci.conf ]; then
|
||||
uci -q set nginx._sc_$shortcut=server
|
||||
uci -q set nginx._sc_$shortcut.server_name="$shortcut"
|
||||
uci -q add_list nginx._sc_$shortcut.listen="80"
|
||||
uci -q set nginx._sc_$shortcut.return="302 $to_url"
|
||||
uci -q set dhcp._sc_$shortcut=domain
|
||||
uci -q set dhcp._sc_$shortcut.name="$shortcut"
|
||||
uci -q set dhcp._sc_$shortcut.ip="$lanaddr"
|
||||
fi
|
||||
}
|
||||
|
||||
clean
|
||||
config_load wizard
|
||||
config_foreach process_one shortcuts
|
||||
|
||||
uci -q commit nginx 2>/dev/null
|
||||
uci -q commit dhcp 2>/dev/null
|
||||
[ -x /etc/init.d/nginx ] && /etc/init.d/nginx reload >/dev/null 2>&1
|
||||
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq reload >/dev/null 2>&1
|
||||
|
||||
echo "Shortcuts applied."
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
BACKUP_DIR="/etc/config.bak.$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
COUNT=0
|
||||
for f in network firewall dhcp wireless system wizard netwizard taskplan; do
|
||||
if [ -f /etc/config/$f ]; then
|
||||
cp /etc/config/$f "$BACKUP_DIR/"
|
||||
COUNT=$((COUNT + 1))
|
||||
fi
|
||||
done
|
||||
echo "Backed up $COUNT files to $BACKUP_DIR"
|
||||
ls -1 "$BACKUP_DIR"
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
ls -1d /etc/config.bak.* 2>/dev/null | sort -r
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
DIR="$1"
|
||||
[ -z "$DIR" ] && { echo "Usage: restore.sh <backup-dir>"; exit 1; }
|
||||
[ ! -d "$DIR" ] && { echo "Directory not found: $DIR"; exit 1; }
|
||||
|
||||
SAFETY="/etc/config.bak.pre-restore.$(date +%s)"
|
||||
mkdir -p "$SAFETY"
|
||||
for f in "$DIR"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
base=$(basename "$f")
|
||||
[ -f "/etc/config/$base" ] && cp "/etc/config/$base" "$SAFETY/"
|
||||
cp "$f" "/etc/config/$base"
|
||||
done
|
||||
|
||||
for c in network firewall dhcp wireless wizard netwizard taskplan; do
|
||||
uci -q commit $c 2>/dev/null
|
||||
done
|
||||
|
||||
/etc/init.d/network reload >/dev/null 2>&1 &
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1 &
|
||||
|
||||
echo "Restored from $DIR"
|
||||
echo "Previous state saved to $SAFETY"
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions Failover
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"status": {},
|
||||
"interfaces": {},
|
||||
"action": { "action": "string" }
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
method_status() {
|
||||
cat >/dev/null
|
||||
local en lock
|
||||
en=$(uci -q get quickactions.failover.enabled); [ -z "$en" ] && en=1
|
||||
[ -f /tmp/quickactions_wan_down.lock ] && lock=1 || lock=0
|
||||
json_init
|
||||
json_add_int "enabled" "$en"
|
||||
json_add_int "on_backup" "$lock"
|
||||
json_add_string "primary" "$(uci -q get quickactions.failover.primary)"
|
||||
json_add_string "backups" "$(uci -q get quickactions.failover.backups)"
|
||||
json_add_string "check_ips" "$(uci -q get quickactions.failover.check_ips)"
|
||||
json_add_string "interval" "$(uci -q get quickactions.failover.check_interval)"
|
||||
json_add_string "last_log" "$(logread 2>/dev/null | grep -E 'quickactions-(failover|hotplug)' | tail -1)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_interfaces() {
|
||||
cat >/dev/null
|
||||
local list
|
||||
list=$(
|
||||
{
|
||||
uci show network 2>/dev/null | grep '=interface$' | cut -d. -f2 | cut -d= -f1
|
||||
ls -1 /sys/class/net/ 2>/dev/null | grep -E '^(pppoe-|eth|usb)'
|
||||
} | sort -u | tr '\n' ' '
|
||||
)
|
||||
json_init
|
||||
json_add_string "interfaces" "$list"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_action() {
|
||||
local payload action out
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
json_get_var action "action"
|
||||
|
||||
case "$action" in
|
||||
on|off|status|test)
|
||||
out=$(/usr/bin/quickactions-failover "$action" 2>&1)
|
||||
;;
|
||||
*)
|
||||
out="unknown action: [$action]"
|
||||
;;
|
||||
esac
|
||||
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
case "$method" in
|
||||
action) method_action ;;
|
||||
status) method_status ;;
|
||||
interfaces) method_interfaces ;;
|
||||
*) 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: '$0' {list|call <method>}"}' ;;
|
||||
esac
|
||||
@@ -0,0 +1,338 @@
|
||||
#!/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
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions Task Plan
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
LOG_FILE="/etc/quickactions-taskplan/taskplan.log"
|
||||
CONFIG_FILE="/etc/config/taskplan"
|
||||
CRON_FILE="/etc/crontabs/root"
|
||||
INIT_SCRIPT="/etc/init.d/quickactions-taskplan"
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"status": {},
|
||||
"list": {},
|
||||
"task_list": {},
|
||||
"start": {},
|
||||
"stop": {},
|
||||
"restart": {},
|
||||
"reload": {}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
method_status() {
|
||||
local running=0 cron_tasks=0 scheduled=0 startup=0 log_content=""
|
||||
pgrep -f quickactions-taskplan >/dev/null 2>&1 && running=1
|
||||
[ -f "$CRON_FILE" ] && cron_tasks=$(grep -c "quickactions-taskplanhandler" "$CRON_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && scheduled=$(grep -c "stime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && startup=$(grep -c "ltime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$LOG_FILE" ] && log_content=$(tail -n 50 "$LOG_FILE" 2>/dev/null)
|
||||
|
||||
json_init
|
||||
json_add_int "running" $running
|
||||
json_add_int "cron_tasks" $cron_tasks
|
||||
json_add_int "scheduled_tasks" $scheduled
|
||||
json_add_int "startup_tasks" $startup
|
||||
json_add_string "log" "$log_content"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_list() {
|
||||
local ssum=0 lsum=0
|
||||
[ -f "$CONFIG_FILE" ] && ssum=$(grep -c "stime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && lsum=$(grep -c "ltime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
json_init
|
||||
json_add_int "scheduled" $ssum
|
||||
json_add_int "startup" $lsum
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_task_list() {
|
||||
json_init
|
||||
json_add_array "tasks"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
local index=0
|
||||
while true; do
|
||||
local section=$(uci -q get taskplan.@stime[$index] 2>/dev/null)
|
||||
[ -z "$section" ] && break
|
||||
json_add_object
|
||||
json_add_string "type" "scheduled"
|
||||
json_add_int "index" $index
|
||||
json_add_int "enable" "$(uci -q get taskplan.@stime[$index].enable || echo 0)"
|
||||
json_add_string "remarks" "$(uci -q get taskplan.@stime[$index].remarks || echo "")"
|
||||
json_add_string "stype" "$(uci -q get taskplan.@stime[$index].stype || echo "")"
|
||||
json_add_string "schedule" "$(uci -q get taskplan.@stime[$index].minute) $(uci -q get taskplan.@stime[$index].hour) $(uci -q get taskplan.@stime[$index].week) $(uci -q get taskplan.@stime[$index].month)"
|
||||
json_close_object
|
||||
index=$((index + 1))
|
||||
done
|
||||
index=0
|
||||
while true; do
|
||||
local section=$(uci -q get taskplan.@ltime[$index] 2>/dev/null)
|
||||
[ -z "$section" ] && break
|
||||
json_add_object
|
||||
json_add_string "type" "startup"
|
||||
json_add_int "index" $index
|
||||
json_add_int "enable" "$(uci -q get taskplan.@ltime[$index].enable || echo 0)"
|
||||
json_add_string "remarks" "$(uci -q get taskplan.@ltime[$index].remarks || echo "")"
|
||||
json_add_string "stype" "$(uci -q get taskplan.@ltime[$index].stype || echo "")"
|
||||
json_add_int "delay" "$(uci -q get taskplan.@ltime[$index].delay || echo 10)"
|
||||
json_close_object
|
||||
index=$((index + 1))
|
||||
done
|
||||
fi
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
service_action() {
|
||||
local action="$1"
|
||||
[ -x "$INIT_SCRIPT" ] && "$INIT_SCRIPT" "$action" >/dev/null 2>&1
|
||||
local ret=$?
|
||||
json_init
|
||||
json_add_int "result" $ret
|
||||
[ $ret -eq 0 ] && json_add_string "message" "Service $action ok"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
cat >/dev/null
|
||||
case "$method" in
|
||||
status) method_status ;;
|
||||
list) method_list ;;
|
||||
task_list) method_task_list ;;
|
||||
start) service_action start ;;
|
||||
stop) service_action stop ;;
|
||||
restart) service_action restart ;;
|
||||
reload) service_action reload ;;
|
||||
*) json_init; json_add_string "error" "unknown_method"; json_dump ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list) list_methods ;;
|
||||
call) call_method "$2" ;;
|
||||
*) echo '{"error":"usage: '$0' {list|call <method>}"}' ;;
|
||||
esac
|
||||
@@ -0,0 +1,640 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions VLAN tab.
|
||||
# Params arrive on stdin as JSON. No positional args.
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
VLAN_DIR=/etc/quickactions/vlan
|
||||
TPL_DIR=$VLAN_DIR/templates
|
||||
GEN_DIR=$VLAN_DIR/generated
|
||||
mkdir -p "$VLAN_DIR" "$TPL_DIR" "$GEN_DIR"
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"detect": {},
|
||||
"preview": { "plan": "string" },
|
||||
"apply": { "plan": "string", "safe": "string" },
|
||||
"snapshot": { "note": "string" },
|
||||
"list_snapshots": {},
|
||||
"restore": { "path": "string" },
|
||||
"confirm": {},
|
||||
"generate_cli": { "plan": "string", "target": "string" },
|
||||
"save_template": { "name": "string", "target": "string", "plan": "string", "notes": "string" },
|
||||
"list_templates": {},
|
||||
"load_template": { "name": "string" },
|
||||
"delete_template": { "name": "string" },
|
||||
"save_generated": { "name": "string", "target": "string", "content": "string" },
|
||||
"list_generated": {},
|
||||
"delete_generated": { "name": "string" },
|
||||
"lldp_neighbors": {},
|
||||
"snmp_query": { "ip": "string", "community": "string" },
|
||||
"bridge_vlan_show": {},
|
||||
"kernel_ifaces": {},
|
||||
"iface_stats": { "ifaces": "string" },
|
||||
"ping_test": { "iface": "string", "ip": "string" }
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# read stdin and populate named vars (var=json_key pairs)
|
||||
_load() {
|
||||
local payload
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
while [ "$#" -ge 2 ]; do
|
||||
eval "$1=\"\$(json_get_var __v '$2'; echo \$__v)\""
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
detect() {
|
||||
json_init
|
||||
local mode="none"
|
||||
uci show network 2>/dev/null | grep -q "\.type='bridge'" && mode="dsa"
|
||||
uci show network 2>/dev/null | grep -q "^network\.@switch\[0\]" && mode="swconfig"
|
||||
|
||||
json_add_string "mode" "$mode"
|
||||
|
||||
json_add_array "bridges"
|
||||
for s in $(uci show network 2>/dev/null | grep "=device$" | cut -d. -f2 | cut -d= -f1); do
|
||||
t=$(uci -q get "network.$s.type")
|
||||
[ "$t" != "bridge" ] && continue
|
||||
name=$(uci -q get "network.$s.name")
|
||||
[ -z "$name" ] && name="$s"
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "name" "$name"
|
||||
vf=$(uci -q get "network.$s.vlan_filtering")
|
||||
json_add_string "vlan_filtering" "${vf:-0}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "bridge_vlans"
|
||||
for s in $(uci show network 2>/dev/null | grep "=bridge-vlan$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get network.$s.device)"
|
||||
json_add_string "vlan" "$(uci -q get network.$s.vlan)"
|
||||
json_add_string "ports" "$(uci -q get network.$s.ports | tr '\n' ' ')"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "interfaces"
|
||||
for s in $(uci show network 2>/dev/null | grep "=interface$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get network.$s.device)"
|
||||
json_add_string "proto" "$(uci -q get network.$s.proto)"
|
||||
json_add_string "ipaddr" "$(uci -q get network.$s.ipaddr)"
|
||||
json_add_string "netmask" "$(uci -q get network.$s.netmask)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "dhcp"
|
||||
for s in $(uci show dhcp 2>/dev/null | grep "=dhcp$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "interface" "$(uci -q get dhcp.$s.interface)"
|
||||
json_add_string "start" "$(uci -q get dhcp.$s.start)"
|
||||
json_add_string "limit" "$(uci -q get dhcp.$s.limit)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "zones"
|
||||
local i=0
|
||||
while true; do
|
||||
local name
|
||||
name=$(uci -q get "firewall.@zone[$i].name")
|
||||
[ -z "$name" ] && break
|
||||
json_add_object
|
||||
json_add_string "name" "$name"
|
||||
json_add_string "network" "$(uci -q get firewall.@zone[$i].network | tr '\n' ' ')"
|
||||
json_add_string "input" "$(uci -q get firewall.@zone[$i].input)"
|
||||
json_add_string "output" "$(uci -q get firewall.@zone[$i].output)"
|
||||
json_add_string "forward" "$(uci -q get firewall.@zone[$i].forward)"
|
||||
json_close_object
|
||||
i=$((i + 1))
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "wifi"
|
||||
for s in $(uci show wireless 2>/dev/null | grep "=wifi-iface$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get wireless.$s.device)"
|
||||
json_add_string "mode" "$(uci -q get wireless.$s.mode)"
|
||||
json_add_string "ssid" "$(uci -q get wireless.$s.ssid)"
|
||||
json_add_string "network" "$(uci -q get wireless.$s.network)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "easymesh"
|
||||
for iface in /sys/class/net/bat0.*; do
|
||||
[ -e "$iface" ] || continue
|
||||
json_add_string "" "$(basename "$iface")"
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_string "kernel" "$(uname -r)"
|
||||
json_add_string "mem_mb" "$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)"
|
||||
json_add_string "hostname" "$(cat /proc/sys/kernel/hostname 2>/dev/null)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
kernel_ifaces() {
|
||||
json_init
|
||||
json_add_array "ifaces"
|
||||
for d in /sys/class/net/*; do
|
||||
[ -e "$d" ] || continue
|
||||
local n
|
||||
n=$(basename "$d")
|
||||
case "$n" in
|
||||
lo|sit*|ip6tnl*|gre*|gretap*|erspan*|ifb*|veth*) continue ;;
|
||||
esac
|
||||
local up
|
||||
up="0"; [ "$(cat "$d/operstate" 2>/dev/null)" = "up" ] && up="1"
|
||||
json_add_object
|
||||
json_add_string "name" "$n"
|
||||
json_add_int "up" "$up"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
preview() {
|
||||
local plan
|
||||
_load plan plan
|
||||
[ -z "$plan" ] && { json_init; json_add_string "error" "no plan"; json_dump; return; }
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
local out
|
||||
out=$(
|
||||
python3 - <<'PYPREVIEW' 2>&1
|
||||
import json
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
lines = []
|
||||
for v in plan.get("vlans", []):
|
||||
lines.append("network.%s=bridge-vlan device=%s vlan=%s" % (
|
||||
v.get("sid","vlan"), v.get("bridge",""), v.get("vlan","")))
|
||||
for i in plan.get("interfaces", []):
|
||||
lines.append("network.%s=interface device=%s proto=%s ip=%s" % (
|
||||
i.get("name",""), i.get("device",""), i.get("proto",""), i.get("ipaddr","")))
|
||||
print("\n".join(lines))
|
||||
PYPREVIEW
|
||||
)
|
||||
json_init
|
||||
json_add_string "diff" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
apply() {
|
||||
local plan safe
|
||||
_load plan plan safe safe
|
||||
[ -z "$plan" ] && { json_init; json_add_string "error" "no plan"; json_dump; return; }
|
||||
[ -z "$safe" ] && safe="0"
|
||||
|
||||
local ts
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
cp /etc/config/network "$VLAN_DIR/network.bak.$ts" 2>/dev/null
|
||||
echo "auto before apply" > "$VLAN_DIR/network.bak.$ts.note"
|
||||
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
json_init
|
||||
json_add_string "error" "python3 required for VLAN apply"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
python3 - <<'PYAPPLY'
|
||||
import json, subprocess
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
|
||||
def uci(*args):
|
||||
try:
|
||||
subprocess.run(["uci"] + list(args), check=True, capture_output=True)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
return True
|
||||
|
||||
for v in plan.get("vlans", []):
|
||||
name = v.get("sid") or ("vlan_%s_%s" % (v.get("bridge","br-lan"), v.get("vlan","0")))
|
||||
uci("set", "network.%s=bridge-vlan" % name)
|
||||
uci("set", "network.%s.device=%s" % (name, v.get("bridge","")))
|
||||
uci("set", "network.%s.vlan=%s" % (name, v.get("vlan","")))
|
||||
for p in v.get("tagged", []):
|
||||
uci("add_list", "network.%s.ports=%s:t" % (name, p))
|
||||
for p in v.get("untagged", []):
|
||||
uci("add_list", "network.%s.ports=%s:u*" % (name, p))
|
||||
|
||||
for i in plan.get("interfaces", []):
|
||||
n = i.get("name","")
|
||||
if not n: continue
|
||||
uci("set", "network.%s=interface" % n)
|
||||
uci("set", "network.%s.device=%s" % (n, i.get("device","")))
|
||||
uci("set", "network.%s.proto=%s" % (n, i.get("proto","static")))
|
||||
if i.get("ipaddr"): uci("set", "network.%s.ipaddr=%s" % (n, i["ipaddr"]))
|
||||
if i.get("netmask"): uci("set", "network.%s.netmask=%s" % (n, i["netmask"]))
|
||||
|
||||
for d in plan.get("dhcp", []):
|
||||
n = d.get("name","")
|
||||
if not n: continue
|
||||
uci("set", "dhcp.%s=dhcp" % n)
|
||||
uci("set", "dhcp.%s.interface=%s" % (n, d.get("interface","")))
|
||||
uci("set", "dhcp.%s.start=%s" % (n, d.get("start","100")))
|
||||
uci("set", "dhcp.%s.limit=%s" % (n, d.get("limit","150")))
|
||||
uci("set", "dhcp.%s.leasetime=%s" % (n, d.get("leasetime","12h")))
|
||||
|
||||
for z in plan.get("zones", []):
|
||||
n = z.get("name","")
|
||||
if not n: continue
|
||||
exists = subprocess.run(["uci","-q","get","firewall.%s" % n], capture_output=True).returncode == 0
|
||||
if not exists:
|
||||
uci("set", "firewall.%s=zone" % n)
|
||||
uci("set", "firewall.%s.name=%s" % (n, n))
|
||||
for net in z.get("network", []):
|
||||
uci("add_list", "firewall.%s.network=%s" % (n, net))
|
||||
uci("set", "firewall.%s.input=%s" % (n, z.get("input","REJECT")))
|
||||
uci("set", "firewall.%s.output=%s" % (n, z.get("output","ACCEPT")))
|
||||
uci("set", "firewall.%s.forward=%s" % (n, z.get("forward","REJECT")))
|
||||
|
||||
subprocess.run(["uci","commit","network"])
|
||||
subprocess.run(["uci","commit","dhcp"])
|
||||
subprocess.run(["uci","commit","firewall"])
|
||||
PYAPPLY
|
||||
|
||||
if [ "$safe" = "1" ]; then
|
||||
local now deadline
|
||||
now=$(date +%s)
|
||||
deadline=$((now + 90))
|
||||
echo "$deadline" > "$VLAN_DIR/pending_rollback"
|
||||
( sleep 90
|
||||
if [ -f "$VLAN_DIR/pending_rollback" ]; then
|
||||
dl=$(cat "$VLAN_DIR/pending_rollback" 2>/dev/null)
|
||||
if [ "$dl" = "$deadline" ]; then
|
||||
cp "$VLAN_DIR/network.bak.$ts" /etc/config/network
|
||||
uci commit network
|
||||
/etc/init.d/network reload
|
||||
rm -f "$VLAN_DIR/pending_rollback"
|
||||
fi
|
||||
fi ) >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
/etc/init.d/network reload >/dev/null 2>&1
|
||||
sleep 2
|
||||
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_add_string "snapshot" "$VLAN_DIR/network.bak.$ts"
|
||||
[ "$safe" = "1" ] && json_add_int "rollback_in" 90
|
||||
json_dump
|
||||
}
|
||||
|
||||
snapshot() {
|
||||
local note
|
||||
_load note note
|
||||
[ -z "$note" ] && note="manual"
|
||||
local ts path
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
path="$VLAN_DIR/network.bak.$ts"
|
||||
cp /etc/config/network "$path" 2>/dev/null || { json_init; json_add_string "error" "cp failed"; json_dump; return; }
|
||||
echo "$note" > "$path.note" 2>/dev/null
|
||||
ls -1t $VLAN_DIR/network.bak.* 2>/dev/null | grep -v '\.note$' | tail -n +21 | while read -r old; do
|
||||
rm -f "$old" "$old.note"
|
||||
done
|
||||
json_init
|
||||
json_add_string "path" "$path"
|
||||
json_add_string "ts" "$ts"
|
||||
json_dump
|
||||
}
|
||||
|
||||
list_snapshots() {
|
||||
json_init
|
||||
json_add_array "snapshots"
|
||||
for f in $(ls -1t $VLAN_DIR/network.bak.* 2>/dev/null | grep -v '\.note$'); do
|
||||
[ -f "$f" ] || continue
|
||||
local sz note
|
||||
sz=$(wc -c < "$f" 2>/dev/null)
|
||||
note=""
|
||||
[ -f "$f.note" ] && note=$(cat "$f.note" 2>/dev/null)
|
||||
json_add_object
|
||||
json_add_string "path" "$f"
|
||||
json_add_string "size" "${sz:-0}"
|
||||
json_add_string "note" "$note"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_add_string "pending" "$(cat $VLAN_DIR/pending_rollback 2>/dev/null)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
restore() {
|
||||
local path
|
||||
_load path path
|
||||
[ -z "$path" ] || [ ! -f "$path" ] && { json_init; json_add_string "error" "bad path"; json_dump; return; }
|
||||
cp "$path" /etc/config/network
|
||||
uci commit network
|
||||
/etc/init.d/network reload >/dev/null 2>&1
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
confirm() {
|
||||
rm -f "$VLAN_DIR/pending_rollback"
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
generate_cli() {
|
||||
local plan target
|
||||
_load plan plan target target
|
||||
[ -z "$target" ] && target="generic"
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
local out
|
||||
out=$(
|
||||
python3 - <<PYGEN
|
||||
import json
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
target = "$target"
|
||||
out = []
|
||||
|
||||
if target == "mikrotik":
|
||||
bridge = plan["vlans"][0].get("bridge","bridge1") if plan.get("vlans") else "bridge1"
|
||||
pvid = {}
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("untagged", []):
|
||||
pvid[p] = v.get("vlan")
|
||||
out.append("/interface bridge")
|
||||
out.append("add name=%s vlan-filtering=yes" % bridge)
|
||||
out.append("/interface bridge port")
|
||||
for p, vid in pvid.items():
|
||||
out.append("add bridge=%s interface=%s pvid=%s" % (bridge, p, vid))
|
||||
out.append("/interface bridge vlan")
|
||||
for v in plan.get("vlans", []):
|
||||
t = ",".join(v.get("tagged",[]))
|
||||
u = ",".join(v.get("untagged",[]))
|
||||
parts = ["bridge=%s" % bridge, "vlan-ids=%s" % v.get("vlan","")]
|
||||
if t: parts.append("tagged=%s" % t)
|
||||
if u: parts.append("untagged=%s" % u)
|
||||
out.append("add " + " ".join(parts))
|
||||
|
||||
elif target == "cisco":
|
||||
for v in plan.get("vlans", []):
|
||||
out.append("vlan %s" % v.get("vlan",""))
|
||||
out.append(" name VLAN_%s" % v.get("vlan",""))
|
||||
out.append("!")
|
||||
trunks = set()
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("tagged", []):
|
||||
trunks.add(p)
|
||||
for p in sorted(trunks):
|
||||
out.append("interface %s" % p)
|
||||
out.append(" switchport trunk encapsulation dot1q")
|
||||
out.append(" switchport mode trunk")
|
||||
allowed = []
|
||||
for v in plan.get("vlans", []):
|
||||
if p in v.get("tagged", []):
|
||||
allowed.append(str(v.get("vlan")))
|
||||
out.append(" switchport trunk allowed vlan %s" % ",".join(allowed))
|
||||
out.append("!")
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("untagged", []):
|
||||
out.append("interface %s" % p)
|
||||
out.append(" switchport mode access")
|
||||
out.append(" switchport access vlan %s" % v.get("vlan",""))
|
||||
out.append("!")
|
||||
|
||||
elif target == "edgeos":
|
||||
for v in plan.get("vlans", []):
|
||||
vid = v.get("vlan","")
|
||||
for p in v.get("tagged", []):
|
||||
out.append("set interfaces ethernet %s vif %s description VLAN_%s" % (p, vid, vid))
|
||||
for p in v.get("untagged", []):
|
||||
out.append("set interfaces ethernet %s description VLAN_%s" % (p, vid))
|
||||
out.append("set interfaces ethernet %s pvid %s" % (p, vid))
|
||||
|
||||
else:
|
||||
out.append("VLAN Ports (T=tagged, U=untagged)")
|
||||
for v in plan.get("vlans", []):
|
||||
plist = []
|
||||
for p in v.get("tagged", []): plist.append("%s T" % p)
|
||||
for p in v.get("untagged", []): plist.append("%s U" % p)
|
||||
out.append("%-5s %s" % (v.get("vlan",""), ", ".join(plist)))
|
||||
|
||||
print("\n".join(out))
|
||||
PYGEN
|
||||
)
|
||||
json_init
|
||||
json_add_string "cli" "$out"
|
||||
json_add_string "target" "$target"
|
||||
json_dump
|
||||
}
|
||||
|
||||
save_template() {
|
||||
local name target plan notes
|
||||
_load name name target target plan plan notes notes
|
||||
[ -z "$name" ] && { json_init; json_add_string "error" "name required"; json_dump; return; }
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
printf '%s\n' "$plan" > "$TPL_DIR/$fname.json"
|
||||
printf '{"target":"%s","notes":"%s"}\n' "$target" "$notes" > "$TPL_DIR/$fname.meta"
|
||||
json_init
|
||||
json_add_string "name" "$fname"
|
||||
json_dump
|
||||
}
|
||||
|
||||
list_templates() {
|
||||
json_init
|
||||
json_add_array "templates"
|
||||
for f in $TPL_DIR/*.json; do
|
||||
[ -f "$f" ] || continue
|
||||
local b meta
|
||||
b=$(basename "$f" .json)
|
||||
meta="{}"
|
||||
[ -f "$TPL_DIR/$b.meta" ] && meta=$(cat "$TPL_DIR/$b.meta")
|
||||
json_add_object
|
||||
json_add_string "name" "$b"
|
||||
json_add_string "meta" "$meta"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
load_template() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
if [ ! -f "$TPL_DIR/$fname.json" ]; then
|
||||
json_init; json_add_string "error" "not found"; json_dump; return
|
||||
fi
|
||||
json_init
|
||||
json_add_string "plan" "$(cat "$TPL_DIR/$fname.json")"
|
||||
[ -f "$TPL_DIR/$fname.meta" ] && json_add_string "meta" "$(cat "$TPL_DIR/$fname.meta")"
|
||||
json_dump
|
||||
}
|
||||
|
||||
delete_template() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
rm -f "$TPL_DIR/$fname.json" "$TPL_DIR/$fname.meta"
|
||||
json_init; json_add_boolean "ok" 1; json_dump
|
||||
}
|
||||
|
||||
save_generated() {
|
||||
local name target content
|
||||
_load name name target target content content
|
||||
[ -z "$name" ] && name="gen-$(date +%s)"
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
printf '%s\n' "$content" > "$GEN_DIR/$fname.txt"
|
||||
echo "$target" > "$GEN_DIR/$fname.target"
|
||||
ls -1t $GEN_DIR/*.txt 2>/dev/null | tail -n +51 | while read -r old; do
|
||||
rm -f "$old" "$old.target"
|
||||
done
|
||||
json_init; json_add_string "name" "$fname"; json_dump
|
||||
}
|
||||
|
||||
list_generated() {
|
||||
json_init
|
||||
json_add_array "generated"
|
||||
for f in $GEN_DIR/*.txt; do
|
||||
[ -f "$f" ] || continue
|
||||
local b tgt
|
||||
b=$(basename "$f" .txt)
|
||||
tgt=""
|
||||
[ -f "$GEN_DIR/$b.target" ] && tgt=$(cat "$GEN_DIR/$b.target")
|
||||
json_add_object
|
||||
json_add_string "name" "$b"
|
||||
json_add_string "target" "$tgt"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
delete_generated() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
rm -f "$GEN_DIR/$fname.txt" "$GEN_DIR/$fname.target"
|
||||
json_init; json_add_boolean "ok" 1; json_dump
|
||||
}
|
||||
|
||||
lldp_neighbors() {
|
||||
if ! command -v lldpcli >/dev/null 2>&1; then
|
||||
json_init; json_add_string "error" "lldpcli not installed"; json_dump; return
|
||||
fi
|
||||
local out
|
||||
out=$(lldpcli show neighbors 2>&1)
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
snmp_query() {
|
||||
local ip community
|
||||
_load ip ip community community
|
||||
[ -z "$community" ] && community="public"
|
||||
if ! command -v snmpwalk >/dev/null 2>&1; then
|
||||
json_init; json_add_string "error" "snmpwalk not installed"; json_dump; return
|
||||
fi
|
||||
local out
|
||||
out=$(snmpwalk -v2c -c "$community" -t 3 -r 1 "$ip" 1.3.6.1.2.1.17.7.1.4.3.1.2 2>&1)
|
||||
json_init
|
||||
json_add_string "ip" "$ip"
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
bridge_vlan_show() {
|
||||
local out
|
||||
out=$(bridge vlan show 2>&1)
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
iface_stats() {
|
||||
local ifaces
|
||||
_load ifaces ifaces
|
||||
json_init
|
||||
json_add_array "stats"
|
||||
for i in $ifaces; do
|
||||
[ -d "/sys/class/net/$i" ] || continue
|
||||
local rx tx
|
||||
rx=$(cat /sys/class/net/$i/statistics/rx_bytes 2>/dev/null)
|
||||
tx=$(cat /sys/class/net/$i/statistics/tx_bytes 2>/dev/null)
|
||||
json_add_object
|
||||
json_add_string "iface" "$i"
|
||||
json_add_int "rx" "${rx:-0}"
|
||||
json_add_int "tx" "${tx:-0}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
ping_test() {
|
||||
local iface ip
|
||||
_load iface iface ip ip
|
||||
[ -z "$iface" ] && { json_init; json_add_string "error" "missing iface"; json_dump; return; }
|
||||
[ -z "$ip" ] && { json_init; json_add_string "error" "missing ip"; json_dump; return; }
|
||||
local out rc
|
||||
out=$(ping -I "$iface" -c 3 -W 3 "$ip" 2>&1)
|
||||
rc=$?
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_add_int "exit_code" "$rc"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
case "$method" in
|
||||
detect) detect ;;
|
||||
preview) preview ;;
|
||||
apply) apply ;;
|
||||
snapshot) snapshot ;;
|
||||
list_snapshots) list_snapshots ;;
|
||||
restore) restore ;;
|
||||
confirm) confirm ;;
|
||||
generate_cli) generate_cli ;;
|
||||
save_template) save_template ;;
|
||||
list_templates) list_templates ;;
|
||||
load_template) load_template ;;
|
||||
delete_template) delete_template ;;
|
||||
save_generated) save_generated ;;
|
||||
list_generated) list_generated ;;
|
||||
delete_generated) delete_generated ;;
|
||||
lldp_neighbors) lldp_neighbors ;;
|
||||
snmp_query) snmp_query ;;
|
||||
bridge_vlan_show) bridge_vlan_show ;;
|
||||
kernel_ifaces) kernel_ifaces ;;
|
||||
iface_stats) iface_stats ;;
|
||||
ping_test) ping_test ;;
|
||||
*) 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
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"admin/quickactions": {
|
||||
"title": "Quick Actions",
|
||||
"action": {
|
||||
"type": "view",
|
||||
"path": "system/quickactions"
|
||||
},
|
||||
"order": 25
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
{
|
||||
"luci-app-quickactions": {
|
||||
"description": "Grant access to Quick Actions",
|
||||
"read": {
|
||||
"ubus": {
|
||||
"file": [
|
||||
"exec",
|
||||
"read"
|
||||
],
|
||||
"luci": [
|
||||
"getInitList",
|
||||
"getThemes"
|
||||
],
|
||||
"luci.quickactions-taskplan": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-failover": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-scripts": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-vlan": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"file": {
|
||||
"/etc/crontabs/root": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/hotplug": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplan.log": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplancustomscript": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplancustomscript2": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/taskplan": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/wizard": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/netwizard": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/network": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/firewall": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/dhcp": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/wireless": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/nginx": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/uhttpd": [
|
||||
"read"
|
||||
],
|
||||
"/etc/config/lighttpd": [
|
||||
"read"
|
||||
],
|
||||
"/tmp/quickactions_wan_down.lock": [
|
||||
"read"
|
||||
],
|
||||
"/tmp/quickactions_wan_fails.count": [
|
||||
"read"
|
||||
],
|
||||
"/tmp/quickactions_wan_oks.count": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions/scripts/*": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions/vlan/*": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions/vlan/templates/*": [
|
||||
"read"
|
||||
],
|
||||
"/etc/quickactions/vlan/generated/*": [
|
||||
"read"
|
||||
]
|
||||
},
|
||||
"uci": [
|
||||
"luci",
|
||||
"quickactions",
|
||||
"hotplug",
|
||||
"guestwifi",
|
||||
"network",
|
||||
"wireless",
|
||||
"dhcp",
|
||||
"firewall",
|
||||
"taskplan",
|
||||
"wizard",
|
||||
"netwizard",
|
||||
"nginx"
|
||||
],
|
||||
"execute": {
|
||||
"/usr/libexec/quickactions-netwizard/list-backups.sh": [
|
||||
"exec"
|
||||
]
|
||||
}
|
||||
},
|
||||
"write": {
|
||||
"ubus": {
|
||||
"file": [
|
||||
"exec",
|
||||
"read",
|
||||
"write"
|
||||
],
|
||||
"uci": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-taskplan": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-failover": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-scripts": [
|
||||
"*"
|
||||
],
|
||||
"luci.quickactions-vlan": [
|
||||
"*"
|
||||
]
|
||||
},
|
||||
"file": {
|
||||
"/etc/crontabs/root": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/hotplug": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplan.log": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplancustomscript": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions-taskplan/taskplancustomscript2": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/taskplan": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/wizard": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/netwizard": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/network": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/firewall": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/dhcp": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/wireless": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/nginx": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/uhttpd": [
|
||||
"write"
|
||||
],
|
||||
"/etc/config/lighttpd": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions/scripts/*": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions/vlan/*": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions/vlan/templates/*": [
|
||||
"write"
|
||||
],
|
||||
"/etc/quickactions/vlan/generated/*": [
|
||||
"write"
|
||||
]
|
||||
},
|
||||
"uci": [
|
||||
"luci",
|
||||
"quickactions",
|
||||
"hotplug",
|
||||
"guestwifi",
|
||||
"network",
|
||||
"wireless",
|
||||
"dhcp",
|
||||
"firewall",
|
||||
"taskplan",
|
||||
"wizard",
|
||||
"netwizard",
|
||||
"nginx"
|
||||
],
|
||||
"execute": {
|
||||
"/etc/init.d/quickactions-taskplan": [
|
||||
"start",
|
||||
"stop",
|
||||
"restart",
|
||||
"reload"
|
||||
],
|
||||
"/usr/libexec/quickactions-netwizard/apply-aggressive.sh": [
|
||||
"exec"
|
||||
],
|
||||
"/usr/libexec/quickactions-netwizard/backup.sh": [
|
||||
"exec"
|
||||
],
|
||||
"/usr/libexec/quickactions-netwizard/restore.sh": [
|
||||
"exec"
|
||||
],
|
||||
"/usr/libexec/quickactions-netwizard/apply-shortcuts.sh": [
|
||||
"exec"
|
||||
],
|
||||
"/usr/bin/quickactions-failover": [
|
||||
"on",
|
||||
"off",
|
||||
"status",
|
||||
"test"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user