#!/bin/sh #-------------------------------------------------------------------------------------------------------------- # # Файл обновления пакета # #-------------------------------------------------------------------------------------------------------------- # по умолчанию включаем режим обновления Кваса UPDATE_MODE=true #-------------------------------------------------------------------------------------------------------------- # Аргументы запуска данного файла #-------------------------------------------------------------------------------------------------------------- # пусто - обычный режим проверки версии обновления # force - режим с полным удалением пакета и принудительным обновлением, даже если версии одинаковые # rollback - режим отката на предыдущую версию пакета, которая есть в релизах на GitHub # full - полное удаление пакета со всеми файлами конфигурации, может задаваться вместе с force или rollback #-------------------------------------------------------------------------------------------------------------- # Функции обновления пакета #-------------------------------------------------------------------------------------------------------------- set_escapes(){ # Устанавливаем эскейп-последовательности # для управления опциями экрана терминала RED="\033[1;31m"; GREEN="\033[1;32m"; BLUE="\033[36m"; NOCL="\033[m"; QST="${RED}?${NOCL}" } WGET='/opt/bin/wget -q --no-check-certificate' # Вы полняем команду отключения DNS провайдера без перезагрузки и выхода из сессии rci_post()($WGET -qO - --post-data="$1" localhost:79/rci/ > /dev/null 2>&1) has_no_internet_here(){ # Если в возвращаемых аргументах нет false значит интернет присутствует # test -z "$(curl -s "localhost:79/rci/show/internet/status" \ # | jq -r 'select(.enabled==true and .reliable==true and ."gateway-accessible"==true and ."captive-accessible"==true and ."dns-accessible"==true and .internet==true)')" # curl -s "localhost:79/rci/show/internet/status" \ # | grep -E 'reliable|gateway-accessible|dns-accessible|internet|enabled|captive-accessible' \ # | grep -q false curl -s "localhost:79/rci/show/internet/status" \ | grep -E 'gateway-accessible|dns-accessible|internet|captive-accessible' \ | grep -q false } #-------------------------------------------------------------------------------------------------------------- print_line(){ # Функция печати строки из WIDTH символов "-" printf "%${WIDTH}s\n" | tr " " "-" } get_n_spaces(){ # Функция возвращает сроку из N пробелов, где N это число переданных пробелов в $1 printf "%${1}s" } #-------------------------------------------------------------------------------------------------------------- diff_len() { # Функция вычисления разницы между шириной WIDTH и длинной переданной строки # используется для фунции ready charlen=$(echo "${1}" | sed -r "s/[\]033\[([0-9]{1,3}(;[0-9]{1,2})?)?[mGK]//g") charlen=${#charlen} echo $(( WIDTH - charlen )) } #-------------------------------------------------------------------------------------------------------------- ready() { # Функция печати строки состояния текущей операции исполнения # которая печатает переданную строку и оставляет курсор на этой же строке size=$(diff_len "${1}") printf "%b%-${size}s%b" "${1}" } print_error(){ print_line echo -e "${RED}[ОШИБКА]${NOCL} ${1}" print_line } #-------------------------------------------------------------------------------------------------------------- when_ok() { # Функция работает в купе с ready и применяется следующим образом для примера: # ready 'Запускаем в работу...' {исполняемый код} && when_ok || when_err # печатает слово ГОТОВО зеленым цветом на одной строке с выводимым ready сообщением # в случае, когда исполняемый код успешно выполнен ok_text=${1:-ГОТОВО} num_left=$((${#ok_text} + 2)) to_left="\033[${num_left}D" echo -e "${to_left}${GREEN}${ok_text}${NOCL}" } #-------------------------------------------------------------------------------------------------------------- when_err() { # Функция работает в купе с ready и применяется следующим образом для примера: # ready 'Запускаем в работу...' {исполняемый код} && when_ok || when_err # печатает слово ОШИБКА красным цветом на одной строке с выводимым ready сообщением # в случае, когда исполняемый код выполнен с ошибкой err_text=${1:-ОШИБКА} num_left=$((${#err_text} + 1)) to_left="\033[${num_left}D" echo -e "${to_left}${RED}${err_text}${NOCL}" } #-------------------------------------------------------------------------------------------------------------- get_package_name(){ # Функция возвращает имя пакета из передаваемой в нее ссылке на ipk пакет echo "${1}" | sed 's/.*\/\(.*ipk\)$/\1/' } #-------------------------------------------------------------------------------------------------------------- rm_tmp_cache(){ # Функция удаляет все временные файлы при установке пакета, # чтобы кеш не мешал установке нового пакета Квас # переводим вывод ошибок в стандартный файл err.stdout # в связи с тем, что это единственный способ перенаправить ошибки # об отсутствии доступа к некоторым файлам которые функция find # в купе с xargs выводят в терминал exec 2> err.stdout find / | grep '/tmp' \ | grep -v "${package_name}" | grep kvas | xargs rm -rf # Переводим вывод ошибок в терминал rm -f err.stdout; exec 2>&1 } #-------------------------------------------------------------------------------------------------------------- select_release_from_list(){ # Функция выводит на экран доступные в репозитории версии пакетов Квас # и позволяет выбрать один из них в случае использования режима "отката" url_list=$(curl -s "${release_url}" | jq -r '.[] | .assets | .[] | .browser_download_url') rel_list=$(echo "${url_list}" | cut -d'/' -f8) num=1; total=$(echo "${rel_list}" | wc -l) if [ -n "${rel_list}" ]; then print_line echo -e "${GREEN}Список доступных релизов пакета Квас:${NOCL}" print_line # читаем данные из переменной со списком доступных релизов # и выводим их на экран, при этом крайняя версия пакета всегда в списке первая printf '%s\n' "${rel_list}" | while IFS= read -r release ; do [ "${num}" -eq 1 ] && latest="${release} ${BLUE}[новая версия]${NOCL}" || latest="${release}" n_spaces=$((${#total} - ${#num})); spaces=$(get_n_spaces "${n_spaces}") echo -e "${GREEN}${num}.${NOCL}${spaces} Версия ${latest}" num=$((num + 1)) done # Производим выбор одного из доступных вариантов в списке релизов while true; do print_line echo -en "${QST}${GREEN} Введите номер из списка${NOCL} [1-${total}, Q-выход, Enter-новая версия]: " read -r num_release case "${num_release}" in [qQ]) # если выбрали выход print_error "Прервано пользователем!" exit 0 ;; [1-["${total}"]) # если выбрали один из номеров из списка print_line eval "${1}=$(echo "${url_list}" | sed -n "${num_release}p")" break ;; '') # если просто нажали Enter (выбираем 1 позицию - крайний релиз) print_line eval "${1}=$(echo "${url_list}" | sed -n '1p')" break ;; *) # при прочих вариантах - выводим сообщение об ошибке print_line echo -e "${RED}Введите цифру от 1 до ${total}.${NOCL}" ;; esac done fi } # --------------------------------------------------------------------------------------------- # Удаляем пакет nano из системы если он установлен, вместо него установим nano-full # --------------------------------------------------------------------------------------------- remove_nano(){ nano_name=$(opkg list-installed | grep 'nano ' | cut -d' ' -f1) [ -n "${nano_name}" ] && opkg --force-remove --force-depends remove "${nano_name}" &> /dev/null } #-------------------------------------------------------------------------------------------------------------- # Переменные используемые в обновлении пакета #-------------------------------------------------------------------------------------------------------------- # Ссылка на репозиторий на GitHub для получения крайней версии пакета release_url=https://api.github.com/repos/qzeleza/kvas/releases # Получаем ссылку на крайний релиз пакета на GitHub package_url=$(curl -sH "Accept: application/vnd.github.v3+json" ${release_url}/latest | sed -n 's/.*browser_download_url\": "\(.*\)\"/\1/p;'| tr -d ' ' | sed '/^$/d') # Выделяем имя пакета из ссылки package_name=$(get_package_name "${package_url}") # путь к файлу конфигурации пакета Квас kvas_conf=/opt/etc/kvas.conf # Вычисляем текущую ширину экрана для печати линий определенной ширины length=$(stty size 2>/dev/null | cut -d' ' -f2) # длина распечатываемой линии символов будет меньше на 12 символов чем ширина экрана [ "${length}" -gt 80 ] && WIDTH=$((length*2/3)) || WIDTH=68 sed -i 's/\(export TERM=\).*/\1xterm-256color/' /opt/etc/profile #-------------------------------------------------------------------------------------------------------------- # # Код исполнения файла # #-------------------------------------------------------------------------------------------------------------- # устанавливаем доступные переменные эскейп-последовательностей set_escapes #-------------------------------------------------------------------------------------------------------------- print_line ready "Проверка наличия интернета" has_no_internet_here && { when_err "ОТСУТСТВУЕТ" print_error "Проверьте свое интернет соединение!" exit 1 } || when_ok "ГОТОВО" #-------------------------------------------------------------------------------------------------------------- # если в параметрах есть аргумент full, # то не важно на каком он месте мы делаем полное удаление пакета if echo "${*}" | grep -q full ; then remove_mode=full UPDATE_MODE=false else remove_mode='' fi #-------------------------------------------------------------------------------------------------------------- # clear #print_line #-------------------------------------------------------------------------------------------------------------- # ищем в параметрах запуска файла наличие ниже перечисленных аргументов if echo "${*}" | grep -qv 'force' ; then # Если это не форсированная установка , то проверяем дальше if echo "${*}" | grep -q 'rollback' ; then # Если параметр rollback значит # выбираем версию для обновления на предыдущую версию или "отката" print_line echo echo -e "${RED}[ВНИМАНИЕ]${NOCL} ${GREEN}Активирован режим возврата к предыдущей версии.${NOCL}" echo select_release_from_list package_url package_name=$(get_package_name "${package_url}") elif [ -f /opt/bin/kvas ] && [ -f ${kvas_conf} ]; then # Если это не форсированная установка и не откат, то # проверяем - обнаружена ли предыдущая версия Кваса # и сравниваем ее версию с новой версией prev_ver=$(cat < ${kvas_conf} \ | grep -E 'VERSION|RELEASE' \ | tr -d '\n' | tr '-' '_' \ | sed 's/^APP_VERSION=\(.*\)APP_RELEASE=\(.*\)/\1-\2\n/') next_ver=$(echo "${package_name}" | sed 's/kvas_\(.*\)_all.*/\1/') if [ "${prev_ver}" = "${next_ver}" ] ; then print_error "Квас все еще свеж, обновлений пока нет." exit 1 fi else # Если НЕ обнаружена предыдущая версия Кваса # то это значит, что производим новую установку Кваса UPDATE_MODE=false fi fi #-------------------------------------------------------------------------------------------------------------- # получаем из имени файла его номер версии version=$(echo "${package_name}" | sed 's/kvas_\(.*\)_all.*/\1/; s/-/ /g; s/_/-/' ) # если в параметрах нет аргумента rollback, то выводим линию echo "${*}" | grep -q 'rollback' && CL_VER=${RED} || { print_line CL_VER=${BLUE} } # запускаем этап установки пакета echo -e "${GREEN}Установка пакета КВАС версии ${CL_VER}[${version}]${NOCL}" # в случае отсутствия возможности создания новой папки cd /opt && mkdir -p /opt/packages || { print_error "Невозможно создать папку ${BLUE}/opt/packages${NOCL}"; exit 1 } print_line #-------------------------------------------------------------------------------------------------------------- ready 'Обновляем библиотеку пакетов opkg...' { opkg update } &>/dev/null && when_ok || when_err # удаляем nano, чтобы поставить nano-full remove_nano #-------------------------------------------------------------------------------------------------------------- ready 'Загружаем пакет...' { cd /opt/packages rm -f "/opt/packages/${package_name}" curl -sOL "${package_url}" } &>/dev/null && when_ok || when_err # в случае если отсутствует соединение с интернетом ! [ -f "${package_name}" ] && { print_error "Проверьте свое интернет соединение!" exit 1 } #-------------------------------------------------------------------------------------------------------------- # если обнаружена предыдущая незавершенная установка пакета if [ -f /opt/bin/kvas ] && kvas | grep -q 'Настройка пакета не завершена' ; then ready 'Удаляем незавершенную ранее установку пакета ...' kvas uninstall "${remove_mode}" yes &>/dev/null && when_ok || when_err else # если все хорошо и обнаружена предыдущая версия пакета, то удаляем ее if [ -f /opt/bin/kvas ]; then ver=$(grep "APP_VERSION=" "${kvas_conf}" | cut -d'=' -f2) rel=$(grep "APP_RELEASE=" "${kvas_conf}" | cut -d'=' -f2) #ready "Удаляем предыдущую версию пакета [${ver} ${rel}]..." kvas uninstall "${remove_mode}" yes # && when_ok || when_err fi fi #-------------------------------------------------------------------------------------------------------------- ready "Устанавливаем новую версию пакета [${version}]..." { opkg update &> /dev/null opkg install "/opt/packages/${package_name}" } &>/dev/null && when_ok || when_err #-------------------------------------------------------------------------------------------------------------- connect_home_nets(){ # подключаем одну гостевую сеть к Квасу, если она имеется /opt/sbin/ip a | grep global | grep -v br0 | grep -qE br[1-9] && { clear kvas vpn net add } } if ! [ -f /opt/bin/kvas ] ; then print_line # если файл пакета не найден после установки пакета, значит произошла ошибка print_error "Пакет установлен некорректно - отсутствуют исполняемые файлы!" echo -e "${GREEN}Попробуйте установить пакет вручную командой " echo -e "${BLUE}'opkg update && opkg install /opt/packages/${package_name}'${NOCL}" print_line exit 1 else sleep 1 curl -s "http://localhost:79/rci/opkg/dns-override" | grep -q true || { # Отключаем системный DNS-сервер роутера echo 'Отключаем работу через DNS-провайдера роутера...' echo "Возможно, что сейчас произойдет выход из сессии..." echo "В этом случае необходимо заново войти в сессию по ssh" echo "и выполнить команду 'kvas setup ${UPDATE_MODE}'" rci_post '[{"opkg": {"dns-override": true}},{"system": {"configuration": {"save": true}}}]' &>/dev/null } # если файл пакета найден после установки пакета, # то запускаем установку и затем тестирование пакета kvas setup "${UPDATE_MODE}" && { # подключаем гостевые сети, если они имется connect_home_nets print_line echo 'Тестируем настройки...' # В данном случае, чтобы не печатать линию после # окончания тестирования дважды передаем параметр upgrade kvas test upgrade } fi rm -f upgrade install