mirror of
https://github.com/juewuy/ShellCrash.git
synced 2026-10-24 03:39:55 +00:00
Merge pull request #1350 from cyxc1124/fix/1344-preserve-crontab
fix(cron): 防止权限或读取失败清空 crontab
This commit is contained in:
+85
-31
@@ -1,41 +1,95 @@
|
|||||||
|
|
||||||
crondir="$(crond -h 2>&1 | grep -oE 'Default:.*' | awk -F ":" '{print $2}'| tr -d ' ')"
|
crondir="$(crond -h 2>&1 | grep -oE 'Default:.*' | awk -F ":" '{print $2}'| tr -d ' ')"
|
||||||
[ ! -w "$crondir" ] && crondir="/etc/storage/cron/crontabs"
|
[ ! -w "$crondir" ] && crondir="/etc/storage/cron/crontabs"
|
||||||
[ ! -w "$crondir" ] && crondir="/var/spool/cron/crontabs"
|
[ ! -w "$crondir" ] && crondir="/var/spool/cron/crontabs"
|
||||||
[ ! -w "$crondir" ] && crondir="/var/spool/cron"
|
[ ! -w "$crondir" ] && crondir="/var/spool/cron"
|
||||||
[ -z "$USER" ] && USER=$(whoami 2>/dev/null)
|
[ -z "$USER" ] && USER=$(id -un)
|
||||||
[ -z "$TASKCFGDIR" ] && TASKCFGDIR="$CRASHDIR"/configs/task
|
[ -z "$TASKCFGDIR" ] && TASKCFGDIR="$CRASHDIR"/configs/task
|
||||||
tmpcron=/tmp/cron_tmp
|
|
||||||
touch "$tmpcron"
|
|
||||||
|
|
||||||
cronadd() { #定时任务工具
|
# ShellCrash 使用的 ash/bash(以及 dash)均支持 test -O。
|
||||||
if crontab -h 2>&1 | grep -q '\-l'; then
|
# shellcheck disable=SC3067
|
||||||
crontab "$1"
|
croncheck() { #在任何写操作前检查实例管理权限,保留普通用户自己的安装
|
||||||
elif [ -w "$crondir" ];then
|
cron_uid=$(id -u) || return 1
|
||||||
cat "$1" >"$crondir"/"$USER" && cru a REFRESH "0 0 1 1 * /bin/true" 2>/dev/null
|
[ "$cron_uid" = 0 ] && return 0
|
||||||
else
|
if [ ! -O "$CRASHDIR/configs/ShellCrash.cfg" ] || [ ! -w "$CRASHDIR/configs/ShellCrash.cfg" ]; then
|
||||||
echo "找不到可用的crond或者crontab应用!No available crond or crontab application can be found!"
|
echo '无权管理此 ShellCrash 实例,请使用安装用户或 root。' >&2
|
||||||
fi
|
|
||||||
}
|
|
||||||
cronload() { #定时任务工具
|
|
||||||
if crontab -h 2>&1 | grep -q '\-l'; then
|
|
||||||
crontab -l
|
|
||||||
elif [ -f "$crondir/$USER" ];then
|
|
||||||
cat "$crondir"/"$USER" 2>/dev/null
|
|
||||||
else
|
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
for cron_pid in $(pidof CrashCore 2>/dev/null); do
|
||||||
cronset() { #定时任务设置
|
if [ ! -O "/proc/$cron_pid" ]; then
|
||||||
# 参数1代表要移除的关键字,参数2代表要添加的任务语句
|
echo '无权管理其他用户启动的 CrashCore。' >&2
|
||||||
cronload | grep -v '^$' | grep -vF "$1" >"$tmpcron"
|
return 1
|
||||||
[ -n "$2" ] && echo "$2" >>"$tmpcron"
|
|
||||||
cronadd "$tmpcron"
|
|
||||||
#华硕/Padavan固件存档在本地,其他则删除
|
|
||||||
if [ -d /jffs ] || [ -d /etc/storage/ShellCrash ];then
|
|
||||||
mkdir -p "$TASKCFGDIR"
|
|
||||||
mv -f "$tmpcron" "$TASKCFGDIR"/cron
|
|
||||||
else
|
|
||||||
rm -f "$tmpcron"
|
|
||||||
fi
|
fi
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cronadd() ( #定时任务工具;子 shell 隔离临时变量和清理 trap
|
||||||
|
croncheck || exit 1
|
||||||
|
[ -f "$1" ] && [ -r "$1" ] || exit 1
|
||||||
|
if crontab -h 2>&1 | grep -q '\-l'; then
|
||||||
|
crontab "$1"
|
||||||
|
elif [ -w "$crondir" ]; then
|
||||||
|
cron_user=$(id -un) || exit 1
|
||||||
|
cron_stage=$(mktemp "$crondir/.shellcrash.XXXXXX") || exit 1
|
||||||
|
trap 'rm -f "$cron_stage"' 0
|
||||||
|
trap 'exit 1' 1 2 3 15
|
||||||
|
[ ! -e "$crondir/$cron_user" ] || cp -p "$crondir/$cron_user" "$cron_stage" || exit 1
|
||||||
|
cat "$1" >"$cron_stage" && mv -f "$cron_stage" "$crondir/$cron_user" || exit 1
|
||||||
|
if command -v cru >/dev/null 2>&1; then
|
||||||
|
cru a REFRESH "0 0 1 1 * /bin/true"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo '找不到可用的 crond 或 crontab!No available crond or crontab!' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
cronload() (
|
||||||
|
cron_user=$(id -un) || exit 1
|
||||||
|
if crontab -h 2>&1 | grep -q '\-l'; then
|
||||||
|
cron_text=$(LC_ALL=C crontab -l 2>&1)
|
||||||
|
cron_status=$?
|
||||||
|
if [ "$cron_status" = 0 ]; then
|
||||||
|
[ -z "$cron_text" ] || printf '%s\n' "$cron_text"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
#首次使用没有 crontab 是合法空表,其他错误必须传回调用者。
|
||||||
|
case "$cron_text" in
|
||||||
|
"no crontab for $cron_user" | "crontab: can't open '$cron_user': No such file or directory") exit 0 ;;
|
||||||
|
esac
|
||||||
|
printf '%s\n' "$cron_text" >&2
|
||||||
|
exit "$cron_status"
|
||||||
|
elif [ -d "$crondir" ] && [ -r "$crondir" ] && [ -x "$crondir" ]; then
|
||||||
|
[ -e "$crondir/$cron_user" ] || [ -L "$crondir/$cron_user" ] || exit 0
|
||||||
|
cat "$crondir/$cron_user"
|
||||||
|
else
|
||||||
|
echo '无法读取原有 crontab,已取消修改。' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
)
|
||||||
|
|
||||||
|
cronupdate() ( #成功读取、生成后才提交;参数是读取 stdin 的过滤命令
|
||||||
|
croncheck || exit 1
|
||||||
|
cron_tmp=$(mktemp -d /tmp/ShellCrash-cron.XXXXXX) || exit 1
|
||||||
|
cron_saved=
|
||||||
|
trap 'rm -rf "$cron_tmp"; [ -z "$cron_saved" ] || rm -f "$cron_saved"' 0
|
||||||
|
trap 'exit 1' 1 2 3 15
|
||||||
|
cronload >"$cron_tmp/old" || exit 1
|
||||||
|
"$@" <"$cron_tmp/old" >"$cron_tmp/new" || exit 1
|
||||||
|
#先准备华硕/Padavan 的持久化副本;任何提交前的写入失败都保留原表。
|
||||||
|
if [ "$cron_persist" = true ] && { [ -d /jffs ] || [ -d /etc/storage/ShellCrash ]; }; then
|
||||||
|
mkdir -p "$TASKCFGDIR" || exit 1
|
||||||
|
cron_saved=$(mktemp "$TASKCFGDIR/.cron.XXXXXX") || exit 1
|
||||||
|
cat "$cron_tmp/new" >"$cron_saved" || exit 1
|
||||||
|
fi
|
||||||
|
cronadd "$cron_tmp/new" || exit 1
|
||||||
|
[ -z "$cron_saved" ] || mv -f "$cron_saved" "$TASKCFGDIR/cron"
|
||||||
|
)
|
||||||
|
|
||||||
|
cronset() ( #参数1:移除的文字;参数2:新增任务。空结果也是合法 crontab。
|
||||||
|
cron_persist=true
|
||||||
|
# shellcheck disable=SC2016
|
||||||
|
CRON_KEY="$1" CRON_TASK="$2" cronupdate awk '
|
||||||
|
NF && !index($0, ENVIRON["CRON_KEY"]) { print }
|
||||||
|
END { if (ENVIRON["CRON_TASK"] != "") print ENVIRON["CRON_TASK"] }
|
||||||
|
'
|
||||||
|
)
|
||||||
|
|||||||
+10
-8
@@ -6,10 +6,11 @@
|
|||||||
cd $(dirname $0)
|
cd $(dirname $0)
|
||||||
pwd
|
pwd
|
||||||
)
|
)
|
||||||
|
. "$CRASHDIR"/libs/set_cron.sh
|
||||||
|
croncheck || exit 1
|
||||||
. "$CRASHDIR"/libs/get_config.sh
|
. "$CRASHDIR"/libs/get_config.sh
|
||||||
#加载工具
|
#加载工具
|
||||||
. "$CRASHDIR"/libs/set_config.sh
|
. "$CRASHDIR"/libs/set_config.sh
|
||||||
. "$CRASHDIR"/libs/set_cron.sh
|
|
||||||
. "$CRASHDIR"/libs/check_cmd.sh
|
. "$CRASHDIR"/libs/check_cmd.sh
|
||||||
. "$CRASHDIR"/libs/check_autostart.sh
|
. "$CRASHDIR"/libs/check_autostart.sh
|
||||||
. "$CRASHDIR"/libs/compare.sh
|
. "$CRASHDIR"/libs/compare.sh
|
||||||
@@ -36,7 +37,9 @@ start_l(){
|
|||||||
case "$1" in
|
case "$1" in
|
||||||
|
|
||||||
start)
|
start)
|
||||||
[ -n "$(pidof CrashCore)" ] && $0 stop #禁止多实例
|
if [ -n "$(pidof CrashCore)" ]; then #禁止多实例
|
||||||
|
"$0" stop || exit 1
|
||||||
|
fi
|
||||||
stop_firewall #清理路由策略
|
stop_firewall #清理路由策略
|
||||||
rm -f "$CRASHDIR"/\.start_error #移除自启失败标记
|
rm -f "$CRASHDIR"/\.start_error #移除自启失败标记
|
||||||
#使用不同方式启动服务
|
#使用不同方式启动服务
|
||||||
@@ -69,9 +72,7 @@ stop)
|
|||||||
logger ShellCrash服务即将关闭......
|
logger ShellCrash服务即将关闭......
|
||||||
[ -n "$(pidof CrashCore)" ] && web_save #保存面板配置
|
[ -n "$(pidof CrashCore)" ] && web_save #保存面板配置
|
||||||
#清理定时任务
|
#清理定时任务
|
||||||
cronload | grep -vE '^$|start_legacy_wd.sh|运行时每' > "$TMPDIR"/cron_tmp
|
cronupdate awk 'NF && !/start_legacy_wd.sh|运行时每/' || exit 1
|
||||||
cronadd "$TMPDIR"/cron_tmp
|
|
||||||
rm -f "$TMPDIR"/cron_tmp
|
|
||||||
#停止tg_bot
|
#停止tg_bot
|
||||||
. "$CRASHDIR"/menus/bot_tg_service.sh && bot_tg_stop
|
. "$CRASHDIR"/menus/bot_tg_service.sh && bot_tg_stop
|
||||||
#多种方式结束进程
|
#多种方式结束进程
|
||||||
@@ -96,8 +97,7 @@ stop)
|
|||||||
rm -rf "$TMPDIR"/CrashCore
|
rm -rf "$TMPDIR"/CrashCore
|
||||||
;;
|
;;
|
||||||
restart)
|
restart)
|
||||||
$0 stop
|
"$0" stop && "$0" start
|
||||||
$0 start
|
|
||||||
;;
|
;;
|
||||||
init)
|
init)
|
||||||
. "$CRASHDIR"/starts/general_init.sh
|
. "$CRASHDIR"/starts/general_init.sh
|
||||||
@@ -110,7 +110,9 @@ daemon)
|
|||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
debug)
|
debug)
|
||||||
[ -n "$(pidof CrashCore)" ] && $0 stop >/dev/null #禁止多实例
|
if [ -n "$(pidof CrashCore)" ]; then #禁止多实例
|
||||||
|
"$0" stop >/dev/null || exit 1
|
||||||
|
fi
|
||||||
stop_firewall >/dev/null #清理路由策略
|
stop_firewall >/dev/null #清理路由策略
|
||||||
bfstart
|
bfstart
|
||||||
if [ -n "$2" ]; then
|
if [ -n "$2" ]; then
|
||||||
|
|||||||
@@ -7,11 +7,12 @@
|
|||||||
cd ..
|
cd ..
|
||||||
pwd
|
pwd
|
||||||
)
|
)
|
||||||
|
. "$CRASHDIR"/libs/set_cron.sh
|
||||||
|
croncheck || exit 1
|
||||||
. "$CRASHDIR"/libs/get_config.sh
|
. "$CRASHDIR"/libs/get_config.sh
|
||||||
#加载工具
|
#加载工具
|
||||||
. "$CRASHDIR"/libs/check_cmd.sh
|
. "$CRASHDIR"/libs/check_cmd.sh
|
||||||
. "$CRASHDIR"/libs/logger.sh
|
. "$CRASHDIR"/libs/logger.sh
|
||||||
. "$CRASHDIR"/libs/set_cron.sh
|
|
||||||
#缺省值
|
#缺省值
|
||||||
[ -z "$firewall_area" ] && firewall_area=1
|
[ -z "$firewall_area" ] && firewall_area=1
|
||||||
#延迟启动
|
#延迟启动
|
||||||
@@ -37,14 +38,24 @@ if [ -n "$test" -o -n "$(pidof CrashCore)" ]; then
|
|||||||
} &
|
} &
|
||||||
ckcmd mtd_storage.sh && mtd_storage.sh save >/dev/null 2>&1 #Padavan保存/etc/storage
|
ckcmd mtd_storage.sh && mtd_storage.sh save >/dev/null 2>&1 #Padavan保存/etc/storage
|
||||||
#加载定时任务
|
#加载定时任务
|
||||||
cronload | grep -v '^$' >"$TMPDIR"/cron_tmp
|
set -- -
|
||||||
[ -s "$TASKCFGDIR"/cron ] && cat "$TASKCFGDIR"/cron >>"$TMPDIR"/cron_tmp
|
for cron_file in "$TASKCFGDIR/cron" "$TASKCFGDIR/running"; do
|
||||||
[ -s "$TASKCFGDIR"/running ] && cat "$TASKCFGDIR"/running >>"$TMPDIR"/cron_tmp
|
[ ! -e "$cron_file" ] || set -- "$@" "$cron_file"
|
||||||
[ "$bot_tg_service" = ON ] && echo "* * * * * /bin/sh $CRASHDIR/starts/start_legacy_wd.sh bot_tg #ShellCrash-TG_BOT守护进程" >>"$TMPDIR"/cron_tmp
|
done
|
||||||
[ "$start_old" = ON ] && echo "* * * * * /bin/sh $CRASHDIR/starts/start_legacy_wd.sh shellcrash #ShellCrash保守模式守护进程" >>"$TMPDIR"/cron_tmp
|
# shellcheck disable=SC2016
|
||||||
awk '!x[$0]++' "$TMPDIR"/cron_tmp >"$TMPDIR"/cron_tmp2 #删除重复行
|
CRON_BOT="$bot_tg_service" CRON_LEGACY="$start_old" CRON_DIR="$CRASHDIR" cronupdate awk '
|
||||||
cronadd "$TMPDIR"/cron_tmp2
|
NF && !seen[$0]++ { print }
|
||||||
rm -f "$TMPDIR"/cron_tmp "$TMPDIR"/cron_tmp2
|
END {
|
||||||
|
if (ENVIRON["CRON_BOT"] == "ON") {
|
||||||
|
line = "* * * * * /bin/sh " ENVIRON["CRON_DIR"] "/starts/start_legacy_wd.sh bot_tg #ShellCrash-TG_BOT守护进程"
|
||||||
|
if (!seen[line]++) print line
|
||||||
|
}
|
||||||
|
if (ENVIRON["CRON_LEGACY"] == "ON") {
|
||||||
|
line = "* * * * * /bin/sh " ENVIRON["CRON_DIR"] "/starts/start_legacy_wd.sh shellcrash #ShellCrash保守模式守护进程"
|
||||||
|
if (!seen[line]++) print line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' "$@" || exit 1
|
||||||
#加载条件任务
|
#加载条件任务
|
||||||
[ -s "$TASKCFGDIR"/afstart ] && { . "$TASKCFGDIR"/afstart; } &
|
[ -s "$TASKCFGDIR"/afstart ] && { . "$TASKCFGDIR"/afstart; } &
|
||||||
[ -s "$TASKCFGDIR"/affirewall -a -s /etc/init.d/firewall -a ! -f /etc/init.d/firewall.bak ] && {
|
[ -s "$TASKCFGDIR"/affirewall -a -s /etc/init.d/firewall -a ! -f /etc/init.d/firewall.bak ] && {
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
CRASHDIR="$(uci get firewall.ShellCrash.path | sed 's/\/starts.*//')"
|
CRASHDIR="$(uci get firewall.ShellCrash.path | sed 's/\/starts.*//')"
|
||||||
#防止提前自启
|
#防止提前自启
|
||||||
/etc/init.d/shellcrash disable
|
/etc/init.d/shellcrash disable
|
||||||
crontab -l | grep -v 'start_legacy_wd.sh shellcrash' | crontab -
|
|
||||||
#防止usb未加载
|
#防止usb未加载
|
||||||
i=0
|
i=0
|
||||||
while [ ! -f "$CRASHDIR/configs/ShellCrash.cfg" ]; do
|
while [ ! -f "$CRASHDIR/configs/ShellCrash.cfg" ]; do
|
||||||
@@ -13,6 +12,8 @@ while [ ! -f "$CRASHDIR/configs/ShellCrash.cfg" ]; do
|
|||||||
sleep 3
|
sleep 3
|
||||||
done
|
done
|
||||||
. "$CRASHDIR"/configs/ShellCrash.cfg
|
. "$CRASHDIR"/configs/ShellCrash.cfg
|
||||||
|
. "$CRASHDIR"/libs/set_cron.sh
|
||||||
|
cronset 'start_legacy_wd.sh shellcrash' || exit 1
|
||||||
|
|
||||||
autoSSH() {
|
autoSSH() {
|
||||||
#自动开启SSH
|
#自动开启SSH
|
||||||
|
|||||||
Reference in New Issue
Block a user