#!/bin/bash . /usr/share/openclash/log.sh . /usr/share/openclash/openclash_curl.sh set_lock() { exec 878>"/tmp/lock/openclash_update.lock" 2>/dev/null flock -x 878 2>/dev/null } del_lock() { flock -u 878 2>/dev/null rm -rf "/tmp/lock/openclash_update.lock" 2>/dev/null } set_lock if [ -n "$1" ] && [ "$1" != "one_key_update" ]; then [ ! -f "/tmp/openclash_last_version" ] && /usr/share/openclash/openclash_version.sh "$1" 2>/dev/null elif [ -n "$2" ]; then [ ! -f "/tmp/openclash_last_version" ] && /usr/share/openclash/openclash_version.sh "$2" 2>/dev/null else [ ! -f "/tmp/openclash_last_version" ] && /usr/share/openclash/openclash_version.sh 2>/dev/null fi if [ ! -f "/tmp/openclash_last_version" ]; then LOG_OUT "Error: Failed to get version information, please try again later..." SLOG_CLEAN del_lock exit 0 fi version_compare() { local current_ver="$1" local latest_ver="$2" if echo "1.0.0" | sort -V >/dev/null 2>&1; then if [ "$(printf '%s\n%s\n' "$current_ver" "$latest_ver" | sort -V | head -n1)" = "$current_ver" ] && [ "$current_ver" != "$latest_ver" ]; then return 0 fi else local cv_num=$(echo "$current_ver" | awk -F '.' '{print $2$3}' 2>/dev/null) local lv_num=$(echo "$latest_ver" | awk -F '.' '{print $2$3}' 2>/dev/null) if [ -n "$cv_num" ] && [ -n "$lv_num" ] && [ "$(expr "$lv_num" \> "$cv_num")" -eq 1 ]; then return 0 fi fi return 1 } LAST_OPVER="/tmp/openclash_last_version" LAST_VER=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n") if [ -x "/bin/opkg" ]; then OP_CV=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null) elif [ -x "/usr/bin/apk" ]; then OP_CV=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null) fi OP_LV=$(sed -n 1p "$LAST_OPVER" 2>/dev/null |sed "s/^v//g" |tr -d "\n") RELEASE_BRANCH=$(uci -q get openclash.config.release_branch || echo "master") github_address_mod=$(uci -q get openclash.config.github_address_mod || echo 0) #一键更新 if [ "$1" = "one_key_update" ]; then uci -q set openclash.config.enable=1 uci -q commit openclash if [ "$github_address_mod" = "0" ] && [ -z "$2" ]; then LOG_OUT "Tip: If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options" fi if [ -n "$2" ]; then /usr/share/openclash/openclash_core.sh "Meta" "$1" "$2" >/dev/null 2>&1 & github_address_mod="$2" else /usr/share/openclash/openclash_core.sh "Meta" "$1" >/dev/null 2>&1 & fi wait else if [ "$github_address_mod" = "0" ]; then LOG_OUT "Tip: If the download fails, try setting the CDN in Overwrite Settings - General Settings - Github Address Modify Options" fi fi if [ -n "$OP_CV" ] && [ -n "$OP_LV" ] && version_compare "$OP_CV" "$OP_LV" && [ -f "$LAST_OPVER" ]; then LOG_OUT "Tip: Start downloading【OpenClash - v$LAST_VER】..." if [ "$github_address_mod" != "0" ]; then if [ "$github_address_mod" == "https://cdn.jsdelivr.net/" ] || [ "$github_address_mod" == "https://fastly.jsdelivr.net/" ] || [ "$github_address_mod" == "https://testingcf.jsdelivr.net/" ]; then if [ -x "/bin/opkg" ]; then DOWNLOAD_URL="${github_address_mod}gh/vernesong/OpenClash@package/${RELEASE_BRANCH}/luci-app-openclash_${LAST_VER}_all.ipk" DOWNLOAD_PATH="/tmp/openclash.ipk" elif [ -x "/usr/bin/apk" ]; then DOWNLOAD_URL="${github_address_mod}gh/vernesong/OpenClash@package/${RELEASE_BRANCH}/luci-app-openclash-${LAST_VER}.apk" DOWNLOAD_PATH="/tmp/openclash.apk" fi else if [ -x "/bin/opkg" ]; then DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/luci-app-openclash_${LAST_VER}_all.ipk" DOWNLOAD_PATH="/tmp/openclash.ipk" elif [ -x "/usr/bin/apk" ]; then DOWNLOAD_URL="${github_address_mod}https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/luci-app-openclash-${LAST_VER}.apk" DOWNLOAD_PATH="/tmp/openclash.apk" fi fi else if [ -x "/bin/opkg" ]; then DOWNLOAD_URL="https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/luci-app-openclash_${LAST_VER}_all.ipk" DOWNLOAD_PATH="/tmp/openclash.ipk" elif [ -x "/usr/bin/apk" ]; then DOWNLOAD_URL="https://raw.githubusercontent.com/vernesong/OpenClash/package/${RELEASE_BRANCH}/luci-app-openclash-${LAST_VER}.apk" DOWNLOAD_PATH="/tmp/openclash.apk" fi fi retry_count=0 max_retries=3 while [ "$retry_count" -lt "$max_retries" ]; do retry_count=$((retry_count + 1)) rm -rf "$DOWNLOAD_PATH" >/dev/null 2>&1 LOG_OUT "Tip:【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Downloading..." SHOW_DOWNLOAD_PROGRESS=1 DOWNLOAD_FILE_CURL "$DOWNLOAD_URL" "$DOWNLOAD_PATH" download_result=$? if [ "$download_result" -eq 0 ]; then LOG_OUT "Tip:【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Download successful, start pre update test..." pre_test_success=false if [ -x "/bin/opkg" ]; then if [ -s "/tmp/openclash.ipk" ]; then if [ -n "$(opkg install /tmp/openclash.ipk --noaction 2>/dev/null |grep 'Upgrading luci-app-openclash on root' 2>/dev/null)" ]; then pre_test_success=true fi fi elif [ -x "/usr/bin/apk" ]; then if [ -s "/tmp/openclash.apk" ]; then apk update >/dev/null 2>&1 apk add -s -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk >/dev/null 2>&1 if [ "$?" -eq 0 ]; then pre_test_success=true fi fi fi if [ "$pre_test_success" = "true" ]; then LOG_OUT "Tip:【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Pre update test passed, ready to update and please do not refresh the page and other operations..." break else if [ "$retry_count" -lt "$max_retries" ]; then LOG_OUT "Error:【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Pre update test failed..." sleep 2 continue else if [ -x "/bin/opkg" ]; then LOG_OUT "Error:【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg install /tmp/openclash.ipk】" elif [ -x "/usr/bin/apk" ]; then LOG_OUT "Error:【OpenClash - v$LAST_VER】Pre update test failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】" fi if [ "$(uci -q get openclash.config.restart)" -eq 1 ]; then uci -q set openclash.config.restart=0 uci -q commit openclash /etc/init.d/openclash restart >/dev/null 2>&1 & else SLOG_CLEAN fi del_lock exit 0 fi fi else if [ "$retry_count" -lt "$max_retries" ]; then LOG_OUT "Error:【$retry_count/$max_retries】【OpenClash - v$LAST_VER】Download failed..." sleep 2 continue else LOG_OUT "Error:【OpenClash - v$LAST_VER】Download Failed after 3 attempts, please check the network or try again later!" rm -rf /tmp/openclash.ipk >/dev/null 2>&1 rm -rf /tmp/openclash.apk >/dev/null 2>&1 if [ "$(uci -q get openclash.config.restart)" -eq 1 ]; then uci -q set openclash.config.restart=0 uci -q commit openclash /etc/init.d/openclash restart >/dev/null 2>&1 & else SLOG_CLEAN fi del_lock exit 0 fi fi done cat > /tmp/openclash_update.sh <<"EOF" #!/bin/sh START_LOG="/tmp/openclash_start.log" LOG_FILE="/tmp/openclash.log" LOGTIME=$(date "+%Y-%m-%d %H:%M:%S") UPDATE_LOCK="/tmp/lock/openclash_update_install.lock" mkdir -p /tmp/lock set_update_lock() { exec 879>"$UPDATE_LOCK" 2>/dev/null flock -n 879 2>/dev/null } del_update_lock() { flock -u 879 2>/dev/null rm -rf "$UPDATE_LOCK" 2>/dev/null } if ! set_update_lock; then echo "Update process is already running, exiting..." exit 1 fi trap 'del_update_lock; exit' INT TERM EXIT LOG_OUT() { if [ -n "${1}" ]; then echo -e "${1}" > $START_LOG echo -e "${LOGTIME} ${1}" >> $LOG_FILE fi } SLOG_CLEAN() { echo "" > $START_LOG } check_install_success() { local target_version="$1" local current_version="" if [ -x "/bin/opkg" ]; then current_version=$(rm -f /var/lock/opkg.lock && opkg status luci-app-openclash 2>/dev/null |grep 'Version' |awk -F 'Version: ' '{print $2}' 2>/dev/null) elif [ -x "/usr/bin/apk" ]; then current_version=$(apk list luci-app-openclash 2>/dev/null|grep 'installed' | grep -oE '[0-9]+(\.[0-9]+)*' | head -1 2>/dev/null) fi if [ -n "$current_version" ] && [ "$current_version" = "$target_version" ]; then return 0 else return 1 fi } uci -q set openclash.config.enable=0 uci -q commit openclash install_retry_count=0 max_install_retries=3 install_success=false while [ $install_retry_count -lt $max_install_retries ]; do install_retry_count=$((install_retry_count + 1)) LOG_OUT "Tip:【$install_retry_count/$max_install_retries】Installing the new version, please do not refresh the page or do other operations..." if [ -x "/bin/opkg" ]; then opkg install /tmp/openclash.ipk elif [ -x "/usr/bin/apk" ]; then apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk fi sleep 2 if check_install_success "$LAST_VER"; then install_success=true break else LOG_OUT "Error:【$install_retry_count/$max_install_retries】Installation failed..." if [ $install_retry_count -lt $max_install_retries ]; then sleep 3 fi fi done if [ "$install_success" = true ]; then if [ -x "/bin/opkg" ]; then rm -rf /tmp/openclash.ipk >/dev/null 2>&1 elif [ -x "/usr/bin/apk" ]; then rm -rf /tmp/openclash.apk >/dev/null 2>&1 fi LOG_OUT "Tip: OpenClash update successful, about to restart!" uci -q set openclash.config.enable=1 uci -q commit openclash /etc/init.d/openclash restart 2>/dev/null else if [ -x "/bin/opkg" ]; then LOG_OUT "Error: OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.ipk, please try to update manually with【opkg install /tmp/openclash.ipk】" elif [ -x "/usr/bin/apk" ]; then LOG_OUT "Error: OpenClash update failed after 3 attempts, the file is saved in /tmp/openclash.apk, please try to update manually with【apk add -q --force-overwrite --clean-protected --allow-untrusted /tmp/openclash.apk】" fi SLOG_CLEAN fi del_update_lock EOF chmod 4755 /tmp/openclash_update.sh if [ ! -f "/tmp/openclash_update.sh" ] || [ ! -s "/tmp/openclash_update.sh" ] || [ ! -x "/tmp/openclash_update.sh" ]; then LOG_OUT "Error: Failed to create update script!" rm -rf /tmp/openclash_update.sh del_lock exit 1 fi retry_count=0 max_retries=3 service_started=false while [ $retry_count -lt $max_retries ]; do retry_count=$((retry_count + 1)) LOG_OUT "Tip:【$retry_count/$max_retries】Attempting to start update service..." ubus call service add '{"name":"openclash_update","instances":{"update":{"command":["/tmp/openclash_update.sh"],"stdout":true,"stderr":true,"env":{"LAST_VER":"'"$LAST_VER"'"}}}}' >/dev/null 2>&1 sleep 3 if ubus call service list '{"name":"openclash_update"}' 2>/dev/null | jsonfilter -e '@.openclash_update.instances.*.running' | grep -q 'true'; then service_started=true break else if [ $retry_count -lt $max_retries ]; then LOG_OUT "Error:【$retry_count/$max_retries】Service start failed, retrying in 2 seconds..." sleep 2 fi fi done if [ "$service_started" = false ]; then LOG_OUT "Error: Failed to start update service after 3 attempts, please check and try again later..." fi (sleep 15; rm -f /tmp/openclash_update.sh) & else if [ ! -f "$LAST_OPVER" ] || [ -z "$OP_CV" ] || [ -z "$OP_LV" ]; then LOG_OUT "Error: Failed to get version information, please try again later..." else LOG_OUT "Tip: OpenClash has not been updated, stop continuing!" fi if [ "$(uci -q get openclash.config.restart)" -eq 1 ]; then uci -q set openclash.config.restart=0 uci -q commit openclash /etc/init.d/openclash restart >/dev/null 2>&1 & else SLOG_CLEAN fi fi del_lock