Advertisement
bandsaw12

SpdMerlin Test Build (388) Rev 2

Dec 20th, 2022 (edited)
97
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 133.45 KB | Source Code | 0 0
  1. #!/bin/sh
  2.  
  3. ##############################################################
  4. ## _ __ __ _ _ ##
  5. ## | || \/ | | |(_) ##
  6. ## ___ _ __ __| || \ / | ___ _ __ | | _ _ __ ##
  7. ## / __|| '_ \ / _` || |\/| | / _ \| '__|| || || '_ \ ##
  8. ## \__ \| |_) || (_| || | | || __/| | | || || | | | ##
  9. ## |___/| .__/ \__,_||_| |_| \___||_| |_||_||_| |_| ##
  10. ## | | ##
  11. ## |_| ##
  12. ## ##
  13. ## https://github.com/jackyaz/spdMerlin ##
  14. ## ##
  15. ##############################################################
  16.  
  17. ############## Shellcheck directives #############
  18. # shellcheck disable=SC2009
  19. # shellcheck disable=SC2012
  20. # shellcheck disable=SC2016
  21. # shellcheck disable=SC2018
  22. # shellcheck disable=SC2019
  23. # shellcheck disable=SC2028
  24. # shellcheck disable=SC2039
  25. # shellcheck disable=SC2059
  26. # shellcheck disable=SC2086
  27. # shellcheck disable=SC2155
  28. # shellcheck disable=SC3045
  29. ##############################################################
  30.  
  31. ### Start of script variables ###
  32. readonly SCRIPT_NAME="spdMerlin"
  33. readonly SCRIPT_NAME_LOWER="$(echo "$SCRIPT_NAME" | tr 'A-Z' 'a-z')"
  34. readonly SCRIPT_VERSION="v4.4.4"
  35. SCRIPT_BRANCH="master"
  36. SCRIPT_REPO="https://raw.githubusercontent.com/jackyaz/$SCRIPT_NAME/$SCRIPT_BRANCH"
  37. readonly SCRIPT_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d"
  38. readonly SCRIPT_WEBPAGE_DIR="$(readlink /www/user)"
  39. readonly SCRIPT_WEB_DIR="$SCRIPT_WEBPAGE_DIR/$SCRIPT_NAME_LOWER"
  40. readonly SHARED_DIR="/jffs/addons/shared-jy"
  41. readonly SHARED_REPO="https://raw.githubusercontent.com/jackyaz/shared-jy/master"
  42. readonly SHARED_WEB_DIR="$SCRIPT_WEBPAGE_DIR/shared-jy"
  43.  
  44. readonly HOME_DIR="/$(readlink "$HOME")"
  45. readonly OOKLA_DIR="$SCRIPT_DIR/ookla"
  46. readonly OOKLA_LICENSE_DIR="$SCRIPT_DIR/ooklalicense"
  47. readonly OOKLA_HOME_DIR="$HOME_DIR/.config/ookla"
  48.  
  49. # Added by ja.young for 388 codebase to work with internal ookla binary
  50. readonly MERLINVER=$(nvram get buildno)
  51. readonly MERLINBASE=${MERLINVER%.*}
  52.  
  53. [ -z "$(nvram get odmpid)" ] && ROUTER_MODEL=$(nvram get productid) || ROUTER_MODEL=$(nvram get odmpid)
  54. [ -f /opt/bin/sqlite3 ] && SQLITE3_PATH=/opt/bin/sqlite3 || SQLITE3_PATH=/usr/sbin/sqlite3
  55.  
  56. [ "$(uname -m)" = "aarch64" ] && ARCH="aarch64" || ARCH="arm"
  57. ### End of script variables ###
  58.  
  59. ### Start of output format variables ###
  60. readonly CRIT="\\e[41m"
  61. readonly ERR="\\e[31m"
  62. readonly WARN="\\e[33m"
  63. readonly PASS="\\e[32m"
  64. readonly BOLD="\\e[1m"
  65. readonly SETTING="${BOLD}\\e[36m"
  66. readonly CLEARFORMAT="\\e[0m"
  67. ### End of output format variables ###
  68.  
  69. ### Start of Speedtest Server Variables ###
  70. serverno=""
  71. servername=""
  72. ### End of Speedtest Server Variables ###
  73.  
  74. # $1 = print to syslog, $2 = message to print, $3 = log level
  75. Print_Output(){
  76. if [ "$1" = "true" ]; then
  77. logger -t "$SCRIPT_NAME" "$2"
  78. fi
  79. printf "${BOLD}${3}%s${CLEARFORMAT}\\n\\n" "$2"
  80. }
  81.  
  82. Firmware_Version_Check(){
  83. if nvram get rc_support | grep -qF "am_addons"; then
  84. return 0
  85. else
  86. return 1
  87. fi
  88. }
  89.  
  90. ### Code for these functions inspired by https://github.com/Adamm00 - credit to @Adamm ###
  91. Check_Lock(){
  92. if [ -f "/tmp/$SCRIPT_NAME.lock" ]; then
  93. ageoflock=$(($(date +%s) - $(date +%s -r /tmp/$SCRIPT_NAME.lock)))
  94. if [ "$ageoflock" -gt 600 ]; then
  95. Print_Output true "Stale lock file found (>600 seconds old) - purging lock" "$ERR"
  96. kill "$(sed -n '1p' /tmp/$SCRIPT_NAME.lock)" >/dev/null 2>&1
  97. Clear_Lock
  98. echo "$$" > "/tmp/$SCRIPT_NAME.lock"
  99. return 0
  100. else
  101. Print_Output true "Lock file found (age: $ageoflock seconds) - stopping to prevent duplicate runs" "$ERR"
  102. if [ -z "$1" ]; then
  103. exit 1
  104. else
  105. if [ "$1" = "webui" ]; then
  106. echo 'var spdteststatus = "LOCKED";' > /tmp/detect_spdtest.js
  107. exit 1
  108. fi
  109. return 1
  110. fi
  111. fi
  112. else
  113. echo "$$" > "/tmp/$SCRIPT_NAME.lock"
  114. return 0
  115. fi
  116. }
  117.  
  118. Clear_Lock(){
  119. rm -f "/tmp/$SCRIPT_NAME.lock" 2>/dev/null
  120. return 0
  121. }
  122.  
  123. Check_Swap(){
  124. if [ "$(wc -l < /proc/swaps)" -ge 2 ]; then return 0; else return 1; fi
  125. }
  126.  
  127. ############################################################################
  128.  
  129. Set_Version_Custom_Settings(){
  130. SETTINGSFILE="/jffs/addons/custom_settings.txt"
  131. case "$1" in
  132. local)
  133. if [ -f "$SETTINGSFILE" ]; then
  134. if [ "$(grep -c "spdmerlin_version_local" $SETTINGSFILE)" -gt 0 ]; then
  135. if [ "$2" != "$(grep "spdmerlin_version_local" /jffs/addons/custom_settings.txt | cut -f2 -d' ')" ]; then
  136. sed -i "s/spdmerlin_version_local.*/spdmerlin_version_local $2/" "$SETTINGSFILE"
  137. fi
  138. else
  139. echo "spdmerlin_version_local $2" >> "$SETTINGSFILE"
  140. fi
  141. else
  142. echo "spdmerlin_version_local $2" >> "$SETTINGSFILE"
  143. fi
  144. ;;
  145. server)
  146. if [ -f "$SETTINGSFILE" ]; then
  147. if [ "$(grep -c "spdmerlin_version_server" $SETTINGSFILE)" -gt 0 ]; then
  148. if [ "$2" != "$(grep "spdmerlin_version_server" /jffs/addons/custom_settings.txt | cut -f2 -d' ')" ]; then
  149. sed -i "s/spdmerlin_version_server.*/spdmerlin_version_server $2/" "$SETTINGSFILE"
  150. fi
  151. else
  152. echo "spdmerlin_version_server $2" >> "$SETTINGSFILE"
  153. fi
  154. else
  155. echo "spdmerlin_version_server $2" >> "$SETTINGSFILE"
  156. fi
  157. ;;
  158. esac
  159. }
  160.  
  161. Update_Check(){
  162. echo 'var updatestatus = "InProgress";' > "$SCRIPT_WEB_DIR/detect_update.js"
  163. doupdate="false"
  164. localver=$(grep "SCRIPT_VERSION=" "/jffs/scripts/$SCRIPT_NAME_LOWER" | grep -m1 -oE 'v[0-9]{1,2}([.][0-9]{1,2})([.][0-9]{1,2})')
  165. /usr/sbin/curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" | grep -qF "jackyaz" || { Print_Output true "404 error detected - stopping update" "$ERR"; return 1; }
  166. serverver=$(/usr/sbin/curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" | grep "SCRIPT_VERSION=" | grep -m1 -oE 'v[0-9]{1,2}([.][0-9]{1,2})([.][0-9]{1,2})')
  167. if [ "$localver" != "$serverver" ]; then
  168. doupdate="version"
  169. Set_Version_Custom_Settings server "$serverver"
  170. echo 'var updatestatus = "'"$serverver"'";' > "$SCRIPT_WEB_DIR/detect_update.js"
  171. else
  172. localmd5="$(md5sum "/jffs/scripts/$SCRIPT_NAME_LOWER" | awk '{print $1}')"
  173. remotemd5="$(curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" | md5sum | awk '{print $1}')"
  174. if [ "$localmd5" != "$remotemd5" ]; then
  175. doupdate="md5"
  176. Set_Version_Custom_Settings server "$serverver-hotfix"
  177. echo 'var updatestatus = "'"$serverver-hotfix"'";' > "$SCRIPT_WEB_DIR/detect_update.js"
  178. fi
  179. fi
  180. if [ "$doupdate" = "false" ]; then
  181. echo 'var updatestatus = "None";' > "$SCRIPT_WEB_DIR/detect_update.js"
  182. fi
  183. echo "$doupdate,$localver,$serverver"
  184. }
  185.  
  186. Update_Version(){
  187. if [ -z "$1" ]; then
  188. updatecheckresult="$(Update_Check)"
  189. isupdate="$(echo "$updatecheckresult" | cut -f1 -d',')"
  190. localver="$(echo "$updatecheckresult" | cut -f2 -d',')"
  191. serverver="$(echo "$updatecheckresult" | cut -f3 -d',')"
  192.  
  193. if [ "$isupdate" = "version" ]; then
  194. Print_Output true "New version of $SCRIPT_NAME available - $serverver" "$PASS"
  195. elif [ "$isupdate" = "md5" ]; then
  196. Print_Output true "MD5 hash of $SCRIPT_NAME does not match - hotfix available - $serverver" "$PASS"
  197. fi
  198.  
  199. if [ "$isupdate" != "false" ]; then
  200. printf "\\n${BOLD}Do you want to continue with the update? (y/n)${CLEARFORMAT} "
  201. read -r confirm
  202. case "$confirm" in
  203. y|Y)
  204. printf "\\n"
  205. Update_File shared-jy.tar.gz
  206. Update_File "$ARCH.tar.gz"
  207. Update_File spdstats_www.asp
  208.  
  209. /usr/sbin/curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" -o "/jffs/scripts/$SCRIPT_NAME_LOWER" && Print_Output true "$SCRIPT_NAME successfully updated"
  210. chmod 0755 "/jffs/scripts/$SCRIPT_NAME_LOWER"
  211. Set_Version_Custom_Settings local "$serverver"
  212. Set_Version_Custom_Settings server "$serverver"
  213. Clear_Lock
  214. PressEnter
  215. exec "$0"
  216. exit 0
  217. ;;
  218. *)
  219. printf "\\n"
  220. Clear_Lock
  221. return 1
  222. ;;
  223. esac
  224.  
  225. else
  226. Print_Output true "No updates available - latest is $localver" "$WARN"
  227. Clear_Lock
  228. fi
  229. fi
  230.  
  231. if [ "$1" = "force" ]; then
  232. serverver=$(/usr/sbin/curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" | grep "SCRIPT_VERSION=" | grep -m1 -oE 'v[0-9]{1,2}([.][0-9]{1,2})([.][0-9]{1,2})')
  233. Print_Output true "Downloading latest version ($serverver) of $SCRIPT_NAME" "$PASS"
  234. Update_File shared-jy.tar.gz
  235. Update_File "$ARCH.tar.gz"
  236. Update_File spdstats_www.asp
  237. /usr/sbin/curl -fsL --retry 3 "$SCRIPT_REPO/$SCRIPT_NAME_LOWER.sh" -o "/jffs/scripts/$SCRIPT_NAME_LOWER" && Print_Output true "$SCRIPT_NAME successfully updated"
  238. chmod 0755 "/jffs/scripts/$SCRIPT_NAME_LOWER"
  239. Set_Version_Custom_Settings local "$serverver"
  240. Set_Version_Custom_Settings server "$serverver"
  241. Clear_Lock
  242. if [ -z "$2" ]; then
  243. PressEnter
  244. exec "$0"
  245. elif [ "$2" = "unattended" ]; then
  246. exec "$0" postupdate
  247. fi
  248. exit 0
  249. fi
  250. }
  251.  
  252. Update_File(){
  253. if [ "$1" = "$ARCH.tar.gz" ]; then
  254. tmpfile="/tmp/$1"
  255. Download_File "$SCRIPT_REPO/$1" "$tmpfile"
  256. tar -xzf "$tmpfile" -C "/tmp"
  257. rm -f "$tmpfile"
  258. localmd5="$(md5sum "$OOKLA_DIR/speedtest" | awk '{print $1}')"
  259. tmpmd5="$(md5sum /tmp/speedtest | awk '{print $1}')"
  260. if [ "$localmd5" != "$tmpmd5" ]; then
  261. rm -f "$OOKLA_DIR"/*
  262. Download_File "$SCRIPT_REPO/$1" "$OOKLA_DIR/$1"
  263. tar -xzf "$OOKLA_DIR/$1" -C "$OOKLA_DIR"
  264. rm -f "$OOKLA_DIR/$1"
  265. chmod 0755 "$OOKLA_DIR/speedtest"
  266. Print_Output true "New version of Speedtest CLI downloaded to $OOKLA_DIR/speedtest" "$PASS"
  267. fi
  268. rm -f "/tmp/speedtest*"
  269. elif [ "$1" = "spdstats_www.asp" ]; then
  270. tmpfile="/tmp/$1"
  271. Download_File "$SCRIPT_REPO/$1" "$tmpfile"
  272. if ! diff -q "$tmpfile" "$SCRIPT_DIR/$1" >/dev/null 2>&1; then
  273. if [ -f "$SCRIPT_DIR/$1" ]; then
  274. Get_WebUI_Page "$SCRIPT_DIR/$1"
  275. sed -i "\\~$MyPage~d" /tmp/menuTree.js
  276. rm -f "$SCRIPT_WEBPAGE_DIR/$MyPage" 2>/dev/null
  277. fi
  278. Download_File "$SCRIPT_REPO/$1" "$SCRIPT_DIR/$1"
  279. Print_Output true "New version of $1 downloaded" "$PASS"
  280. Mount_WebUI
  281. fi
  282. rm -f "$tmpfile"
  283. elif [ "$1" = "shared-jy.tar.gz" ]; then
  284. if [ ! -f "$SHARED_DIR/$1.md5" ]; then
  285. Download_File "$SHARED_REPO/$1" "$SHARED_DIR/$1"
  286. Download_File "$SHARED_REPO/$1.md5" "$SHARED_DIR/$1.md5"
  287. tar -xzf "$SHARED_DIR/$1" -C "$SHARED_DIR"
  288. rm -f "$SHARED_DIR/$1"
  289. Print_Output true "New version of $1 downloaded" "$PASS"
  290. else
  291. localmd5="$(cat "$SHARED_DIR/$1.md5")"
  292. remotemd5="$(curl -fsL --retry 3 "$SHARED_REPO/$1.md5")"
  293. if [ "$localmd5" != "$remotemd5" ]; then
  294. Download_File "$SHARED_REPO/$1" "$SHARED_DIR/$1"
  295. Download_File "$SHARED_REPO/$1.md5" "$SHARED_DIR/$1.md5"
  296. tar -xzf "$SHARED_DIR/$1" -C "$SHARED_DIR"
  297. rm -f "$SHARED_DIR/$1"
  298. Print_Output true "New version of $1 downloaded" "$PASS"
  299. fi
  300. fi
  301. else
  302. return 1
  303. fi
  304. }
  305.  
  306. Validate_Bandwidth(){
  307. if echo "$1" | /bin/grep -oq "^[0-9]*\.\?[0-9]*$"; then
  308. return 0
  309. else
  310. return 1
  311. fi
  312. }
  313.  
  314. Validate_Number(){
  315. if [ "$1" -eq "$1" ] 2>/dev/null; then
  316. return 0
  317. else
  318. return 1
  319. fi
  320. }
  321.  
  322.  
  323. Create_Dirs(){
  324. if [ ! -d "$SCRIPT_DIR" ]; then
  325. mkdir -p "$SCRIPT_DIR"
  326. fi
  327.  
  328. if [ ! -d "$SCRIPT_STORAGE_DIR" ]; then
  329. mkdir -p "$SCRIPT_STORAGE_DIR"
  330. fi
  331.  
  332. if [ ! -d "$CSV_OUTPUT_DIR" ]; then
  333. mkdir -p "$CSV_OUTPUT_DIR"
  334. fi
  335.  
  336. if [ ! -d "$OOKLA_DIR" ]; then
  337. mkdir -p "$OOKLA_DIR"
  338. fi
  339.  
  340. if [ ! -d "$OOKLA_LICENSE_DIR" ]; then
  341. mkdir -p "$OOKLA_LICENSE_DIR"
  342. fi
  343.  
  344. if [ ! -d "$OOKLA_HOME_DIR" ]; then
  345. mkdir -p "$OOKLA_HOME_DIR"
  346. fi
  347.  
  348. if [ ! -d "$SHARED_DIR" ]; then
  349. mkdir -p "$SHARED_DIR"
  350. fi
  351.  
  352. if [ ! -d "$SCRIPT_WEBPAGE_DIR" ]; then
  353. mkdir -p "$SCRIPT_WEBPAGE_DIR"
  354. fi
  355.  
  356. if [ ! -d "$SCRIPT_WEB_DIR" ]; then
  357. mkdir -p "$SCRIPT_WEB_DIR"
  358. fi
  359. }
  360.  
  361. Create_Symlinks(){
  362. printf "WAN\\n" > "$SCRIPT_INTERFACES"
  363.  
  364. for index in 1 2 3 4 5; do
  365. comment=""
  366. if [ ! -f "/sys/class/net/tun1$index/operstate" ] || [ "$(cat "/sys/class/net/tun1$index/operstate")" = "down" ]; then
  367. comment=" #excluded - interface not up#"
  368. fi
  369. if [ "$index" -lt 5 ]; then
  370. printf "VPNC%s%s\\n" "$index" "$comment" >> "$SCRIPT_INTERFACES"
  371. else
  372. printf "VPNC%s%s\\n" "$index" "$comment" >> "$SCRIPT_INTERFACES"
  373. fi
  374. done
  375.  
  376. if [ "$1" = "force" ]; then
  377. rm -f "$SCRIPT_INTERFACES_USER"
  378. fi
  379.  
  380. if [ ! -f "$SCRIPT_INTERFACES_USER" ]; then
  381. touch "$SCRIPT_INTERFACES_USER"
  382. fi
  383.  
  384. while IFS='' read -r line || [ -n "$line" ]; do
  385. if [ "$(grep -c "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" "$SCRIPT_INTERFACES_USER")" -eq 0 ]; then
  386. printf "%s\\n" "$line" >> "$SCRIPT_INTERFACES_USER"
  387. fi
  388. done < "$SCRIPT_INTERFACES"
  389.  
  390. interfacecount="$(wc -l < "$SCRIPT_INTERFACES_USER")"
  391. COUNTER=1
  392. until [ $COUNTER -gt "$interfacecount" ]; do
  393. Set_Interface_State "$COUNTER"
  394. COUNTER=$((COUNTER + 1))
  395. done
  396.  
  397. rm -rf "${SCRIPT_WEB_DIR:?}/"* 2>/dev/null
  398.  
  399. ln -s /tmp/spd-stats.txt "$SCRIPT_WEB_DIR/spd-stats.htm" 2>/dev/null
  400. ln -s /tmp/spd-result.txt "$SCRIPT_WEB_DIR/spd-result.htm" 2>/dev/null
  401. ln -s /tmp/detect_spdtest.js "$SCRIPT_WEB_DIR/detect_spdtest.js" 2>/dev/null
  402. ln -s /tmp/spdmerlin-binary "$SCRIPT_WEB_DIR/spd-binary.htm" 2>/dev/null
  403. ln -s "$SCRIPT_STORAGE_DIR/.autobwoutfile" "$SCRIPT_WEB_DIR/autobwoutfile.htm" 2>/dev/null
  404.  
  405. ln -s "$SCRIPT_CONF" "$SCRIPT_WEB_DIR/config.htm" 2>/dev/null
  406. ln -s "$SCRIPT_INTERFACES_USER" "$SCRIPT_WEB_DIR/interfaces_user.htm" 2>/dev/null
  407. ln -s "$SCRIPT_STORAGE_DIR/spdtitletext.js" "$SCRIPT_WEB_DIR/spdtitletext.js" 2>/dev/null
  408.  
  409. FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5"
  410. for IFACE_NAME in $FULL_IFACELIST; do
  411. ln -s "$SCRIPT_STORAGE_DIR/lastx_${IFACE_NAME}.csv" "$SCRIPT_WEB_DIR/lastx_${IFACE_NAME}.htm"
  412. done
  413.  
  414. ln -s "$CSV_OUTPUT_DIR" "$SCRIPT_WEB_DIR/csv" 2>/dev/null
  415.  
  416. if [ ! -d "$SHARED_WEB_DIR" ]; then
  417. ln -s "$SHARED_DIR" "$SHARED_WEB_DIR" 2>/dev/null
  418. fi
  419. }
  420.  
  421. Conf_FromSettings(){
  422. SETTINGSFILE="/jffs/addons/custom_settings.txt"
  423. TMPFILE="/tmp/spdmerlin_settings.txt"
  424. if [ -f "$SETTINGSFILE" ]; then
  425. if [ "$(grep "spdmerlin_" $SETTINGSFILE | grep -v "version" -c)" -gt 0 ]; then
  426. Print_Output true "Updated settings from WebUI found, merging into $SCRIPT_CONF" "$PASS"
  427. cp -a "$SCRIPT_CONF" "$SCRIPT_CONF.bak"
  428. grep "spdmerlin_" "$SETTINGSFILE" | grep -v "version" > "$TMPFILE"
  429. sed -i "s/spdmerlin_//g;s/ /=/g" "$TMPFILE"
  430. while IFS='' read -r line || [ -n "$line" ]; do
  431. SETTINGNAME="$(echo "$line" | cut -f1 -d'=' | awk '{ print toupper($1) }')"
  432. SETTINGVALUE="$(echo "$line" | cut -f2- -d'=' | sed "s/=/ /g")"
  433. sed -i "s~$SETTINGNAME=.*~$SETTINGNAME=$SETTINGVALUE~" "$SCRIPT_CONF"
  434. done < "$TMPFILE"
  435. grep 'spdmerlin_version' "$SETTINGSFILE" > "$TMPFILE"
  436. sed -i "\\~spdmerlin_~d" "$SETTINGSFILE"
  437. mv "$SETTINGSFILE" "$SETTINGSFILE.bak"
  438. cat "$SETTINGSFILE.bak" "$TMPFILE" > "$SETTINGSFILE"
  439. rm -f "$TMPFILE"
  440. rm -f "$SETTINGSFILE.bak"
  441.  
  442. ScriptStorageLocation "$(ScriptStorageLocation check)"
  443. Create_Symlinks
  444.  
  445. if AutomaticMode check; then
  446. Auto_Cron delete 2>/dev/null
  447. Auto_Cron create 2>/dev/null
  448. else
  449. Auto_Cron delete 2>/dev/null
  450. fi
  451.  
  452. if [ "$(AutoBWEnable check)" = "true" ]; then
  453. if [ "$(ExcludeFromQoS check)" = "false" ]; then
  454. Print_Output true "Enabling Exclude from QoS (required for AutoBW)"
  455. ExcludeFromQoS enable
  456. fi
  457. fi
  458.  
  459. Generate_CSVs
  460.  
  461. Print_Output true "Merge of updated settings from WebUI completed successfully" "$PASS"
  462. else
  463. Print_Output true "No updated settings from WebUI found, no merge into $SCRIPT_CONF necessary" "$PASS"
  464. fi
  465. fi
  466. }
  467.  
  468. Interfaces_FromSettings(){
  469. SETTINGSFILE="/jffs/addons/custom_settings.txt"
  470. if [ -f "$SETTINGSFILE" ]; then
  471. if grep -q "spdmerlin_ifaces_enabled" "$SETTINGSFILE"; then
  472. Print_Output true "Updated interfaces from WebUI found, merging into $SCRIPT_INTERFACES_USER" "$PASS"
  473. cp -a "$SCRIPT_INTERFACES_USER" "$SCRIPT_INTERFACES_USER.bak"
  474. SETTINGVALUE="$(grep "spdmerlin_ifaces_enabled" "$SETTINGSFILE" | cut -f2 -d' ')"
  475. sed -i "\\~spdmerlin_ifaces_enabled~d" "$SETTINGSFILE"
  476.  
  477. printf "WAN #excluded#\\n" > "$SCRIPT_INTERFACES"
  478.  
  479. for index in 1 2 3 4 5; do
  480. comment=" #excluded#"
  481. if [ ! -f "/sys/class/net/tun1$index/operstate" ] || [ "$(cat "/sys/class/net/tun1$index/operstate")" = "down" ]; then
  482. comment=" #excluded - interface not up#"
  483. fi
  484. printf "VPNC%s%s\\n" "$index" "$comment" >> "$SCRIPT_INTERFACES"
  485. done
  486.  
  487. echo "" > "$SCRIPT_INTERFACES_USER"
  488.  
  489. while IFS='' read -r line || [ -n "$line" ]; do
  490. if [ "$(grep -c "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" "$SCRIPT_INTERFACES_USER")" -eq 0 ]; then
  491. printf "%s\\n" "$line" >> "$SCRIPT_INTERFACES_USER"
  492. fi
  493. done < "$SCRIPT_INTERFACES"
  494.  
  495. interfacecount="$(wc -l < "$SCRIPT_INTERFACES_USER")"
  496. COUNTER=1
  497. until [ $COUNTER -gt "$interfacecount" ]; do
  498. Set_Interface_State "$COUNTER"
  499. COUNTER=$((COUNTER + 1))
  500. done
  501.  
  502. for iface in $(echo "$SETTINGVALUE" | sed "s/,/ /g"); do
  503. ifacelinenumber="$(grep -n "$iface" "$SCRIPT_INTERFACES_USER" | cut -f1 -d':')"
  504. interfaceline="$(sed "$ifacelinenumber!d" "$SCRIPT_INTERFACES_USER" | awk '{$1=$1};1')"
  505.  
  506. if echo "$interfaceline" | grep -q "#excluded" ; then
  507. IFACE_LOWER="$(Get_Interface_From_Name "$(echo "$interfaceline" | cut -f1 -d"#" | sed 's/ *$//')" | tr "A-Z" "a-z")"
  508. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  509. sed -i "${ifacelinenumber}s/ #excluded#/ #excluded - interface not up#/" "$SCRIPT_INTERFACES_USER"
  510. else
  511. sed -i "${ifacelinenumber}s/ #excluded - interface not up#//" "$SCRIPT_INTERFACES_USER"
  512. sed -i "${ifacelinenumber}s/ #excluded#//" "$SCRIPT_INTERFACES_USER"
  513. fi
  514. else
  515. IFACE_LOWER="$(Get_Interface_From_Name "$(echo "$interfaceline" | cut -f1 -d"#" | sed 's/ *$//')" | tr "A-Z" "a-z")"
  516. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  517. sed -i "$ifacelinenumber"'s/$/ #excluded - interface not up#/' "$SCRIPT_INTERFACES_USER"
  518. fi
  519. fi
  520. done
  521.  
  522. awk 'NF' "$SCRIPT_INTERFACES_USER" > /tmp/spd-interfaces
  523. mv /tmp/spd-interfaces "$SCRIPT_INTERFACES_USER"
  524.  
  525. Print_Output true "Merge of updated interfaces from WebUI completed successfully" "$PASS"
  526. else
  527. Print_Output true "No updated interfaces from WebUI found, no merge into $SCRIPT_INTERFACES_USER necessary" "$PASS"
  528. fi
  529. fi
  530. }
  531.  
  532. Conf_Exists(){
  533. if [ -f "$SCRIPT_CONF" ]; then
  534. dos2unix "$SCRIPT_CONF"
  535. chmod 0644 "$SCRIPT_CONF"
  536. sed -i -e 's/"//g' "$SCRIPT_CONF"
  537. if grep -q "SCHEDULESTART" "$SCRIPT_CONF"; then
  538. {
  539. echo "SCHDAYS=*";
  540. echo "SCHHOURS=*";
  541. echo "SCHMINS=12,42";
  542. } >> "$SCRIPT_CONF"
  543. sed -i '/SCHEDULESTART/d;/SCHEDULEEND/d;/MINUTE/d;/TESTFREQUENCY/d' "$SCRIPT_CONF"
  544. if AutomaticMode check; then
  545. Auto_Cron delete 2>/dev/null
  546. Auto_Cron create 2>/dev/null
  547. else
  548. Auto_Cron delete 2>/dev/null
  549. fi
  550. fi
  551. if ! grep -q "AUTOBW_AVERAGE_CALC" "$SCRIPT_CONF"; then
  552. echo "AUTOBW_AVERAGE_CALC=10" >> "$SCRIPT_CONF"
  553. fi
  554. if grep -q "OUTPUTDATAMODE" "$SCRIPT_CONF"; then
  555. sed -i '/OUTPUTDATAMODE/d;' "$SCRIPT_CONF"
  556. fi
  557. if ! grep -q "DAYSTOKEEP" "$SCRIPT_CONF"; then
  558. echo "DAYSTOKEEP=30" >> "$SCRIPT_CONF"
  559. fi
  560. if ! grep -q "LASTXRESULTS" "$SCRIPT_CONF"; then
  561. echo "LASTXRESULTS=10" >> "$SCRIPT_CONF"
  562. fi
  563. if ! grep -q "SPEEDTESTBINARY" "$SCRIPT_CONF"; then
  564. if [ -f /usr/sbin/ookla ]; then
  565. echo "SPEEDTESTBINARY=builtin" >> "$SCRIPT_CONF"
  566. else
  567. echo "SPEEDTESTBINARY=external" >> "$SCRIPT_CONF"
  568. fi
  569. fi
  570. return 0
  571. else
  572. { echo "PREFERREDSERVER_WAN=0|None configured"; echo "USEPREFERRED_WAN=false"; echo "AUTOMATED=true" ; echo "OUTPUTTIMEMODE=unix"; echo "STORAGELOCATION=jffs"; } >> "$SCRIPT_CONF"
  573. for index in 1 2 3 4 5; do
  574. { echo "PREFERREDSERVER_VPNC$index=0|None configured"; echo "USEPREFERRED_VPNC$index=false"; } >> "$SCRIPT_CONF"
  575. done
  576. { echo "AUTOBW_ENABLED=false"; echo "AUTOBW_SF_DOWN=95"; echo "AUTOBW_SF_UP=95"; echo "AUTOBW_ULIMIT_DOWN=0"; echo "AUTOBW_LLIMIT_DOWN=0"; echo "AUTOBW_ULIMIT_UP=0"; echo "AUTOBW_LLIMIT_UP=0"; echo "AUTOBW_THRESHOLD_UP=10"; echo "AUTOBW_THRESHOLD_DOWN=10"; echo "AUTOBW_AVERAGE_CALC=10"; echo "STORERESULTURL=true"; echo "EXCLUDEFROMQOS=true"; echo "SCHDAYS=*"; echo "SCHHOURS=*"; echo "SCHMINS=12,42"; echo "DAYSTOKEEP=30"; echo "LASTXRESULTS=10";} >> "$SCRIPT_CONF"
  577. if [ -f /usr/sbin/ookla ]; then
  578. echo "SPEEDTESTBINARY=builtin" >> "$SCRIPT_CONF"
  579. else
  580. echo "SPEEDTESTBINARY=external" >> "$SCRIPT_CONF"
  581. fi
  582. return 1
  583. fi
  584. }
  585.  
  586. Auto_ServiceEvent(){
  587. case $1 in
  588. create)
  589. if [ -f /jffs/scripts/service-event ]; then
  590. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)
  591. STARTUPLINECOUNTEX=$(grep -cx 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME_LOWER"'"; then { /jffs/scripts/'"$SCRIPT_NAME_LOWER"' service_event "$@" & }; fi # '"$SCRIPT_NAME" /jffs/scripts/service-event)
  592.  
  593. if [ "$STARTUPLINECOUNT" -gt 1 ] || { [ "$STARTUPLINECOUNTEX" -eq 0 ] && [ "$STARTUPLINECOUNT" -gt 0 ]; }; then
  594. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/service-event
  595. fi
  596.  
  597. if [ "$STARTUPLINECOUNTEX" -eq 0 ]; then
  598. echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME_LOWER"'"; then { /jffs/scripts/'"$SCRIPT_NAME_LOWER"' service_event "$@" & }; fi # '"$SCRIPT_NAME" >> /jffs/scripts/service-event
  599. fi
  600. else
  601. echo "#!/bin/sh" > /jffs/scripts/service-event
  602. echo "" >> /jffs/scripts/service-event
  603. echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME_LOWER"'"; then { /jffs/scripts/'"$SCRIPT_NAME_LOWER"' service_event "$@" & }; fi # '"$SCRIPT_NAME" >> /jffs/scripts/service-event
  604. chmod 0755 /jffs/scripts/service-event
  605. fi
  606. ;;
  607. delete)
  608. if [ -f /jffs/scripts/service-event ]; then
  609. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/service-event)
  610.  
  611. if [ "$STARTUPLINECOUNT" -gt 0 ]; then
  612. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/service-event
  613. fi
  614. fi
  615. ;;
  616. esac
  617. }
  618.  
  619. Auto_Startup(){
  620. case $1 in
  621. create)
  622. if [ -f /jffs/scripts/services-start ]; then
  623. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)
  624.  
  625. if [ "$STARTUPLINECOUNT" -gt 0 ]; then
  626. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start
  627. fi
  628. fi
  629.  
  630. if [ -f /jffs/scripts/post-mount ]; then
  631. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)
  632. STARTUPLINECOUNTEX=$(grep -cx "/jffs/scripts/$SCRIPT_NAME_LOWER startup"' "$@" & # '"$SCRIPT_NAME" /jffs/scripts/post-mount)
  633.  
  634. if [ "$STARTUPLINECOUNT" -gt 1 ] || { [ "$STARTUPLINECOUNTEX" -eq 0 ] && [ "$STARTUPLINECOUNT" -gt 0 ]; }; then
  635. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/post-mount
  636. fi
  637.  
  638. if [ "$STARTUPLINECOUNTEX" -eq 0 ]; then
  639. echo "/jffs/scripts/$SCRIPT_NAME_LOWER startup"' "$@" & # '"$SCRIPT_NAME" >> /jffs/scripts/post-mount
  640. fi
  641. else
  642. echo "#!/bin/sh" > /jffs/scripts/post-mount
  643. echo "" >> /jffs/scripts/post-mount
  644. echo "/jffs/scripts/$SCRIPT_NAME_LOWER startup"' "$@" & # '"$SCRIPT_NAME" >> /jffs/scripts/post-mount
  645. chmod 0755 /jffs/scripts/post-mount
  646. fi
  647. ;;
  648. delete)
  649. if [ -f /jffs/scripts/services-start ]; then
  650. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/services-start)
  651.  
  652. if [ "$STARTUPLINECOUNT" -gt 0 ]; then
  653. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/services-start
  654. fi
  655. fi
  656.  
  657. if [ -f /jffs/scripts/post-mount ]; then
  658. STARTUPLINECOUNT=$(grep -c '# '"$SCRIPT_NAME" /jffs/scripts/post-mount)
  659.  
  660. if [ "$STARTUPLINECOUNT" -gt 0 ]; then
  661. sed -i -e '/# '"$SCRIPT_NAME"'/d' /jffs/scripts/post-mount
  662. fi
  663. fi
  664. ;;
  665. esac
  666. }
  667.  
  668. Auto_Cron(){
  669. case $1 in
  670. create)
  671. STARTUPLINECOUNT=$(cru l | grep -c "$SCRIPT_NAME")
  672.  
  673. if [ "$STARTUPLINECOUNT" -eq 0 ]; then
  674. CRU_DAYNUMBERS="$(grep "SCHDAYS" "$SCRIPT_CONF" | cut -f2 -d"=" | sed 's/Sun/0/;s/Mon/1/;s/Tues/2/;s/Wed/3/;s/Thurs/4/;s/Fri/5/;s/Sat/6/;')"
  675. CRU_HOURS="$(grep "SCHHOURS" "$SCRIPT_CONF" | cut -f2 -d"=")"
  676. CRU_MINUTES="$(grep "SCHMINS" "$SCRIPT_CONF" | cut -f2 -d"=")"
  677. cru a "$SCRIPT_NAME" "$CRU_MINUTES $CRU_HOURS * * $CRU_DAYNUMBERS /jffs/scripts/$SCRIPT_NAME_LOWER generate"
  678. fi
  679. ;;
  680. delete)
  681. STARTUPLINECOUNT=$(cru l | grep -c "$SCRIPT_NAME")
  682.  
  683. if [ "$STARTUPLINECOUNT" -gt 0 ]; then
  684. cru d "$SCRIPT_NAME"
  685. fi
  686. ;;
  687. esac
  688. }
  689.  
  690. Get_Interface_From_Name(){
  691. IFACE=""
  692. case "$1" in
  693. WAN)
  694. if [ "$(nvram get sw_mode)" -ne 1 ]; then
  695. IFACE="br0"
  696. elif [ "$(nvram get wan0_proto)" = "pppoe" ] || [ "$(nvram get wan0_proto)" = "pptp" ] || [ "$(nvram get wan0_proto)" = "l2tp" ]; then
  697. IFACE="ppp0"
  698. else
  699. IFACE="$(nvram get wan0_ifname)"
  700. fi
  701. ;;
  702. VPNC1)
  703. IFACE="tun11"
  704. ;;
  705. VPNC2)
  706. IFACE="tun12"
  707. ;;
  708. VPNC3)
  709. IFACE="tun13"
  710. ;;
  711. VPNC4)
  712. IFACE="tun14"
  713. ;;
  714. VPNC5)
  715. IFACE="tun15"
  716. ;;
  717. esac
  718.  
  719. echo "$IFACE"
  720. }
  721.  
  722. Set_Interface_State(){
  723. interfaceline="$(sed "$1!d" "$SCRIPT_INTERFACES_USER" | awk '{$1=$1};1')"
  724. if echo "$interfaceline" | grep -q "VPN" ; then
  725. if echo "$interfaceline" | grep -q "#excluded" ; then
  726. IFACE_LOWER="$(Get_Interface_From_Name "$(echo "$interfaceline" | cut -f1 -d"#" | sed 's/ *$//')" | tr "A-Z" "a-z")"
  727. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  728. sed -i "$1"'s/ #excluded#/ #excluded - interface not up#/' "$SCRIPT_INTERFACES_USER"
  729. else
  730. sed -i "$1"'s/ #excluded - interface not up#/ #excluded#/' "$SCRIPT_INTERFACES_USER"
  731. fi
  732. fi
  733. fi
  734. }
  735.  
  736. Generate_Interface_List(){
  737. ScriptHeader
  738. goback="false"
  739. printf "Retrieving list of interfaces...\\n\\n"
  740. interfacecount="$(wc -l < "$SCRIPT_INTERFACES_USER")"
  741. COUNTER=1
  742. until [ $COUNTER -gt "$interfacecount" ]; do
  743. Set_Interface_State "$COUNTER"
  744. interfaceline="$(sed "$COUNTER!d" "$SCRIPT_INTERFACES_USER" | awk '{$1=$1};1')"
  745. printf "%s) %s\\n" "$COUNTER" "$interfaceline"
  746. COUNTER=$((COUNTER + 1))
  747. done
  748.  
  749. printf "\\ne) Go back\\n"
  750.  
  751. while true; do
  752. printf "\\n${BOLD}Please select a chart to toggle inclusion in %s (1-%s):${CLEARFORMAT} " "$SCRIPT_NAME" "$interfacecount"
  753. read -r interface
  754.  
  755. if [ "$interface" = "e" ]; then
  756. goback="true"
  757. break
  758. elif ! Validate_Number "$interface"; then
  759. printf "\\n\\e[31mPlease enter a valid number (1-%s)${CLEARFORMAT}\\n" "$interfacecount"
  760. else
  761. if [ "$interface" -lt 1 ] || [ "$interface" -gt "$interfacecount" ]; then
  762. printf "\\n\\e[31mPlease enter a number between 1 and %s${CLEARFORMAT}\\n" "$interfacecount"
  763. else
  764. interfaceline="$(sed "$interface!d" "$SCRIPT_INTERFACES_USER" | awk '{$1=$1};1')"
  765. if echo "$interfaceline" | grep -q "#excluded" ; then
  766. IFACE_LOWER="$(Get_Interface_From_Name "$(echo "$interfaceline" | cut -f1 -d"#" | sed 's/ *$//')" | tr "A-Z" "a-z")"
  767. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  768. sed -i "$interface"'s/ #excluded#/ #excluded - interface not up#/' "$SCRIPT_INTERFACES_USER"
  769. else
  770. sed -i "$interface"'s/ #excluded - interface not up#//' "$SCRIPT_INTERFACES_USER"
  771. sed -i "$interface"'s/ #excluded#//' "$SCRIPT_INTERFACES_USER"
  772. fi
  773. else
  774. IFACE_LOWER="$(Get_Interface_From_Name "$(echo "$interfaceline" | cut -f1 -d"#" | sed 's/ *$//')" | tr "A-Z" "a-z")"
  775. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  776. sed -i "$interface"'s/$/ #excluded - interface not up#/' "$SCRIPT_INTERFACES_USER"
  777. else
  778. sed -i "$interface"'s/$/ #excluded#/' "$SCRIPT_INTERFACES_USER"
  779. fi
  780. fi
  781.  
  782. sed -i 's/ *$//' "$SCRIPT_INTERFACES_USER"
  783. printf "\\n"
  784. break
  785. fi
  786. fi
  787. done
  788.  
  789. if [ "$goback" != "true" ]; then
  790. Generate_Interface_List
  791. fi
  792. }
  793.  
  794. Download_File(){
  795. /usr/sbin/curl -fsL --retry 3 "$1" -o "$2"
  796. }
  797.  
  798. Get_WebUI_Page(){
  799. MyPage="none"
  800. for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20; do
  801. page="/www/user/user$i.asp"
  802. if [ -f "$page" ] && [ "$(md5sum < "$1")" = "$(md5sum < "$page")" ]; then
  803. MyPage="user$i.asp"
  804. return
  805. elif [ "$MyPage" = "none" ] && [ ! -f "$page" ]; then
  806. MyPage="user$i.asp"
  807. fi
  808. done
  809. }
  810.  
  811. ### function based on @dave14305's FlexQoS webconfigpage function ###
  812. Get_WebUI_URL(){
  813. urlpage=""
  814. urlproto=""
  815. urldomain=""
  816. urlport=""
  817.  
  818. urlpage="$(sed -nE "/$SCRIPT_NAME/ s/.*url\: \"(user[0-9]+\.asp)\".*/\1/p" /tmp/menuTree.js)"
  819. if [ "$(nvram get http_enable)" -eq 1 ]; then
  820. urlproto="https"
  821. else
  822. urlproto="http"
  823. fi
  824. if [ -n "$(nvram get lan_domain)" ]; then
  825. urldomain="$(nvram get lan_hostname).$(nvram get lan_domain)"
  826. else
  827. urldomain="$(nvram get lan_ipaddr)"
  828. fi
  829. if [ "$(nvram get ${urlproto}_lanport)" -eq 80 ] || [ "$(nvram get ${urlproto}_lanport)" -eq 443 ]; then
  830. urlport=""
  831. else
  832. urlport=":$(nvram get ${urlproto}_lanport)"
  833. fi
  834.  
  835. if echo "$urlpage" | grep -qE "user[0-9]+\.asp"; then
  836. echo "${urlproto}://${urldomain}${urlport}/${urlpage}" | tr "A-Z" "a-z"
  837. else
  838. echo "WebUI page not found"
  839. fi
  840. }
  841. ### ###
  842.  
  843. ### locking mechanism code credit to Martineau (@MartineauUK) ###
  844. Mount_WebUI(){
  845. Print_Output true "Mounting WebUI tab for $SCRIPT_NAME" "$PASS"
  846. LOCKFILE=/tmp/addonwebui.lock
  847. FD=386
  848. eval exec "$FD>$LOCKFILE"
  849. flock -x "$FD"
  850. Get_WebUI_Page "$SCRIPT_DIR/spdstats_www.asp"
  851. if [ "$MyPage" = "none" ]; then
  852. Print_Output true "Unable to mount $SCRIPT_NAME WebUI page, exiting" "$CRIT"
  853. flock -u "$FD"
  854. return 1
  855. fi
  856. cp -f "$SCRIPT_DIR/spdstats_www.asp" "$SCRIPT_WEBPAGE_DIR/$MyPage"
  857. echo "$SCRIPT_NAME" > "$SCRIPT_WEBPAGE_DIR/$(echo $MyPage | cut -f1 -d'.').title"
  858.  
  859. if [ "$(uname -o)" = "ASUSWRT-Merlin" ]; then
  860. if [ ! -f /tmp/index_style.css ]; then
  861. cp -f /www/index_style.css /tmp/
  862. fi
  863.  
  864. if ! grep -q '.menu_Addons' /tmp/index_style.css ; then
  865. echo ".menu_Addons { background: url(ext/shared-jy/addons.png); }" >> /tmp/index_style.css
  866. fi
  867.  
  868. umount /www/index_style.css 2>/dev/null
  869. mount -o bind /tmp/index_style.css /www/index_style.css
  870.  
  871. if [ ! -f /tmp/menuTree.js ]; then
  872. cp -f /www/require/modules/menuTree.js /tmp/
  873. fi
  874.  
  875. sed -i "\\~$MyPage~d" /tmp/menuTree.js
  876.  
  877. if ! grep -q 'menuName: "Addons"' /tmp/menuTree.js ; then
  878. lineinsbefore="$(( $(grep -n "exclude:" /tmp/menuTree.js | cut -f1 -d':') - 1))"
  879. sed -i "$lineinsbefore"'i,\n{\nmenuName: "Addons",\nindex: "menu_Addons",\ntab: [\n{url: "javascript:var helpwindow=window.open('"'"'/ext/shared-jy/redirect.htm'"'"')", tabName: "Help & Support"},\n{url: "NULL", tabName: "__INHERIT__"}\n]\n}' /tmp/menuTree.js
  880. fi
  881.  
  882. sed -i "/url: \"javascript:var helpwindow=window.open('\/ext\/shared-jy\/redirect.htm'/i {url: \"$MyPage\", tabName: \"$SCRIPT_NAME\"}," /tmp/menuTree.js
  883.  
  884. umount /www/require/modules/menuTree.js 2>/dev/null
  885. mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
  886. fi
  887. flock -u "$FD"
  888. Print_Output true "Mounted $SCRIPT_NAME WebUI page as $MyPage" "$PASS"
  889. }
  890.  
  891. AutomaticMode(){
  892. case "$1" in
  893. enable)
  894. sed -i 's/^AUTOMATED=.*$/AUTOMATED=true/' "$SCRIPT_CONF"
  895. Auto_Cron create 2>/dev/null
  896. ;;
  897. disable)
  898. sed -i 's/^AUTOMATED=.*$/AUTOMATED=false/' "$SCRIPT_CONF"
  899. Auto_Cron delete 2>/dev/null
  900. ;;
  901. check)
  902. AUTOMATED=$(grep "AUTOMATED" "$SCRIPT_CONF" | cut -f2 -d"=")
  903. if [ "$AUTOMATED" = "true" ]; then return 0; else return 1; fi
  904. ;;
  905. esac
  906. }
  907.  
  908. TestSchedule(){
  909. case "$1" in
  910. update)
  911. sed -i 's/^SCHDAYS=.*$/SCHDAYS='"$(echo "$2" | sed 's/0/Sun/;s/1/Mon/;s/2/Tues/;s/3/Wed/;s/4/Thurs/;s/5/Fri/;s/6/Sat/;')"'/' "$SCRIPT_CONF"
  912. sed -i 's~^SCHHOURS=.*$~SCHHOURS='"$3"'~' "$SCRIPT_CONF"
  913. sed -i 's~^SCHMINS=.*$~SCHMINS='"$4"'~' "$SCRIPT_CONF"
  914. Auto_Cron delete 2>/dev/null
  915. Auto_Cron create 2>/dev/null
  916. ;;
  917. check)
  918. SCHDAYS=$(grep "SCHDAYS" "$SCRIPT_CONF" | cut -f2 -d"=")
  919. SCHHOURS=$(grep "SCHHOURS" "$SCRIPT_CONF" | cut -f2 -d"=")
  920. SCHMINS=$(grep "SCHMINS" "$SCRIPT_CONF" | cut -f2 -d"=")
  921. echo "$SCHDAYS|$SCHHOURS|$SCHMINS"
  922. ;;
  923. esac
  924. }
  925.  
  926. ScriptStorageLocation(){
  927. case "$1" in
  928. usb)
  929. sed -i 's/^STORAGELOCATION=.*$/STORAGELOCATION=usb/' "$SCRIPT_CONF"
  930. mkdir -p "/opt/share/$SCRIPT_NAME_LOWER.d/"
  931. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/csv" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  932. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/.interfaces" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  933. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/.interfaces_user" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  934. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/config" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  935. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/config.bak" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  936. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/spdtitletext.js" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  937. mv "/jffs/addons/$SCRIPT_NAME_LOWER.d/spdstats.db" "/opt/share/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  938. SCRIPT_CONF="/opt/share/$SCRIPT_NAME_LOWER.d/config"
  939. ScriptStorageLocation load
  940. ;;
  941. jffs)
  942. sed -i 's/^STORAGELOCATION=.*$/STORAGELOCATION=jffs/' "$SCRIPT_CONF"
  943. mkdir -p "/jffs/addons/$SCRIPT_NAME_LOWER.d/"
  944. mv "/opt/share/$SCRIPT_NAME_LOWER.d/csv" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  945. mv "/opt/share/$SCRIPT_NAME_LOWER.d/.interfaces" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  946. mv "/opt/share/$SCRIPT_NAME_LOWER.d/.interfaces_user" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  947. mv "/opt/share/$SCRIPT_NAME_LOWER.d/config" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  948. mv "/opt/share/$SCRIPT_NAME_LOWER.d/config.bak" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  949. mv "/opt/share/$SCRIPT_NAME_LOWER.d/spdtitletext.js" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  950. mv "/opt/share/$SCRIPT_NAME_LOWER.d/spdstats.db" "/jffs/addons/$SCRIPT_NAME_LOWER.d/" 2>/dev/null
  951. SCRIPT_CONF="/jffs/addons/$SCRIPT_NAME_LOWER.d/config"
  952. ScriptStorageLocation load
  953. ;;
  954. check)
  955. STORAGELOCATION=$(grep "STORAGELOCATION" "$SCRIPT_CONF" | cut -f2 -d"=")
  956. echo "$STORAGELOCATION"
  957. ;;
  958. load)
  959. STORAGELOCATION=$(grep "STORAGELOCATION" "$SCRIPT_CONF" | cut -f2 -d"=")
  960. if [ "$STORAGELOCATION" = "usb" ]; then
  961. SCRIPT_STORAGE_DIR="/opt/share/$SCRIPT_NAME_LOWER.d"
  962. elif [ "$STORAGELOCATION" = "jffs" ]; then
  963. SCRIPT_STORAGE_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d"
  964. fi
  965.  
  966. SCRIPT_INTERFACES="$SCRIPT_STORAGE_DIR/.interfaces"
  967. SCRIPT_INTERFACES_USER="$SCRIPT_STORAGE_DIR/.interfaces_user"
  968. CSV_OUTPUT_DIR="$SCRIPT_STORAGE_DIR/csv"
  969. ;;
  970. esac
  971. }
  972.  
  973. OutputTimeMode(){
  974. case "$1" in
  975. unix)
  976. sed -i 's/^OUTPUTTIMEMODE=.*$/OUTPUTTIMEMODE=unix/' "$SCRIPT_CONF"
  977. Generate_CSVs
  978. ;;
  979. non-unix)
  980. sed -i 's/^OUTPUTTIMEMODE=.*$/OUTPUTTIMEMODE=non-unix/' "$SCRIPT_CONF"
  981. Generate_CSVs
  982. ;;
  983. check)
  984. OUTPUTTIMEMODE=$(grep "OUTPUTTIMEMODE" "$SCRIPT_CONF" | cut -f2 -d"=")
  985. echo "$OUTPUTTIMEMODE"
  986. ;;
  987. esac
  988. }
  989.  
  990. SpeedtestBinary(){
  991. case "$1" in
  992. builtin)
  993. sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=builtin/' "$SCRIPT_CONF"
  994. ;;
  995. external)
  996. sed -i 's/^SPEEDTESTBINARY=.*$/SPEEDTESTBINARY=external/' "$SCRIPT_CONF"
  997. ;;
  998. check)
  999. SPEEDTESTBINARY=$(grep "SPEEDTESTBINARY" "$SCRIPT_CONF" | cut -f2 -d"=")
  1000. echo "$SPEEDTESTBINARY"
  1001. ;;
  1002. esac
  1003. }
  1004.  
  1005. DaysToKeep(){
  1006. case "$1" in
  1007. update)
  1008. daystokeep=30
  1009. exitmenu=""
  1010. ScriptHeader
  1011. while true; do
  1012. printf "\\n${BOLD}Please enter the desired number of days\\nto keep data for (30-365 days):${CLEARFORMAT} "
  1013. read -r daystokeep_choice
  1014.  
  1015. if [ "$daystokeep_choice" = "e" ]; then
  1016. exitmenu="exit"
  1017. break
  1018. elif ! Validate_Number "$daystokeep_choice"; then
  1019. printf "\\n${ERR}Please enter a valid number (30-365)${CLEARFORMAT}\\n"
  1020. elif [ "$daystokeep_choice" -lt 30 ] || [ "$daystokeep_choice" -gt 365 ]; then
  1021. printf "\\n${ERR}Please enter a number between 30 and 365${CLEARFORMAT}\\n"
  1022. else
  1023. daystokeep="$daystokeep_choice"
  1024. printf "\\n"
  1025. break
  1026. fi
  1027. done
  1028.  
  1029. if [ "$exitmenu" != "exit" ]; then
  1030. sed -i 's/^DAYSTOKEEP=.*$/DAYSTOKEEP='"$daystokeep"'/' "$SCRIPT_CONF"
  1031. return 0
  1032. else
  1033. printf "\\n"
  1034. return 1
  1035. fi
  1036. ;;
  1037. check)
  1038. DAYSTOKEEP=$(grep "DAYSTOKEEP" "$SCRIPT_CONF" | cut -f2 -d"=")
  1039. echo "$DAYSTOKEEP"
  1040. ;;
  1041. esac
  1042. }
  1043.  
  1044. LastXResults(){
  1045. case "$1" in
  1046. update)
  1047. lastxresults=10
  1048. exitmenu=""
  1049. ScriptHeader
  1050. while true; do
  1051. printf "\\n${BOLD}Please enter the desired number of results\\nto display in the WebUI (1-100):${CLEARFORMAT} "
  1052. read -r lastx_choice
  1053.  
  1054. if [ "$lastx_choice" = "e" ]; then
  1055. exitmenu="exit"
  1056. break
  1057. elif ! Validate_Number "$lastx_choice"; then
  1058. printf "\\n${ERR}Please enter a valid number (1-100)${CLEARFORMAT}\\n"
  1059. elif [ "$lastx_choice" -lt 1 ] || [ "$lastx_choice" -gt 100 ]; then
  1060. printf "\\n${ERR}Please enter a number between 1 and 100${CLEARFORMAT}\\n"
  1061. else
  1062. lastxresults="$lastx_choice"
  1063. printf "\\n"
  1064. break
  1065. fi
  1066. done
  1067.  
  1068. if [ "$exitmenu" != "exit" ]; then
  1069. sed -i 's/^LASTXRESULTS=.*$/LASTXRESULTS='"$lastxresults"'/' "$SCRIPT_CONF"
  1070.  
  1071. IFACELIST=""
  1072.  
  1073. while IFS='' read -r line || [ -n "$line" ]; do
  1074. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1075. done < "$SCRIPT_INTERFACES_USER"
  1076. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1077.  
  1078. if [ "$IFACELIST" != "" ]; then
  1079. for IFACE_NAME in $IFACELIST; do
  1080. Generate_LastXResults "$IFACE_NAME"
  1081. done
  1082. fi
  1083. return 0
  1084. else
  1085. printf "\\n"
  1086. return 1
  1087. fi
  1088. ;;
  1089. check)
  1090. LASTXRESULTS=$(grep "LASTXRESULTS" "$SCRIPT_CONF" | cut -f2 -d"=")
  1091. echo "$LASTXRESULTS"
  1092. ;;
  1093. esac
  1094. }
  1095.  
  1096. StoreResultURL(){
  1097. case "$1" in
  1098. enable)
  1099. sed -i 's/^STORERESULTURL=.*$/STORERESULTURL=true/' "$SCRIPT_CONF"
  1100. ;;
  1101. disable)
  1102. sed -i 's/^STORERESULTURL=.*$/STORERESULTURL=false/' "$SCRIPT_CONF"
  1103. ;;
  1104. check)
  1105. STORERESULTURL=$(grep "STORERESULTURL" "$SCRIPT_CONF" | cut -f2 -d"=")
  1106. echo "$STORERESULTURL"
  1107. ;;
  1108. esac
  1109. }
  1110.  
  1111. ExcludeFromQoS(){
  1112. case "$1" in
  1113. enable)
  1114. sed -i 's/^EXCLUDEFROMQOS=.*$/EXCLUDEFROMQOS=true/' "$SCRIPT_CONF"
  1115. ;;
  1116. disable)
  1117. sed -i 's/^EXCLUDEFROMQOS=.*$/EXCLUDEFROMQOS=false/' "$SCRIPT_CONF"
  1118. ;;
  1119. check)
  1120. EXCLUDEFROMQOS=$(grep "EXCLUDEFROMQOS" "$SCRIPT_CONF" | cut -f2 -d"=")
  1121. echo "$EXCLUDEFROMQOS"
  1122. ;;
  1123. esac
  1124. }
  1125.  
  1126. AutoBWEnable(){
  1127. case "$1" in
  1128. enable)
  1129. sed -i 's/^AUTOBW_ENABLED=.*$/AUTOBW_ENABLED=true/' "$SCRIPT_CONF"
  1130. ;;
  1131. disable)
  1132. sed -i 's/^AUTOBW_ENABLED=.*$/AUTOBW_ENABLED=false/' "$SCRIPT_CONF"
  1133. ;;
  1134. check)
  1135. AUTOBW_ENABLED=$(grep "AUTOBW_ENABLED" "$SCRIPT_CONF" | cut -f2 -d"=")
  1136. echo "$AUTOBW_ENABLED"
  1137. ;;
  1138. esac
  1139. }
  1140.  
  1141. AutoBWConf(){
  1142. case "$1" in
  1143. update)
  1144. sed -i 's/^AUTOBW_'"$2"'_'"$3"'=.*$/AUTOBW_'"$2"'_'"$3"'='"$4"'/' "$SCRIPT_CONF"
  1145. ;;
  1146. check)
  1147. grep "AUTOBW_${2}_$3" "$SCRIPT_CONF" | cut -f2 -d"="
  1148. ;;
  1149. esac
  1150. }
  1151.  
  1152. #$1 fieldname $2 tablename $3 frequency (hours) $4 length (days) $5 outputfile $6 outputfrequency $7 interfacename $8 sqlfile $9 timestamp
  1153. WriteSql_ToFile(){
  1154. timenow="$9"
  1155. maxcount="$(echo "$3" "$4" | awk '{printf ((24*$2)/$1)}')"
  1156.  
  1157. if ! echo "$5" | grep -q "day"; then
  1158. {
  1159. echo ".mode csv"
  1160. echo ".headers off"
  1161. echo ".output ${5}_${6}_${7}.tmp"
  1162. echo "SELECT '$1' Metric,Min(strftime('%s',datetime(strftime('%Y-%m-%d %H:00:00',datetime([Timestamp],'unixepoch'))))) Time,IFNULL(printf('%f',Avg($1)),'NaN') Value FROM $2 WHERE ([Timestamp] >= strftime('%s',datetime($timenow,'unixepoch','-$maxcount hour'))) GROUP BY strftime('%m',datetime([Timestamp],'unixepoch')),strftime('%d',datetime([Timestamp],'unixepoch')),strftime('%H',datetime([Timestamp],'unixepoch')) ORDER BY [Timestamp] DESC;"
  1163. } > "$8"
  1164. else
  1165. {
  1166. echo ".mode csv"
  1167. echo ".headers off"
  1168. echo ".output ${5}_${6}_${7}.tmp"
  1169. echo "SELECT '$1' Metric,Max(strftime('%s',datetime([Timestamp],'unixepoch','localtime','start of day','utc'))) Time,IFNULL(printf('%f',Avg($1)),'NaN') Value FROM $2 WHERE ([Timestamp] > strftime('%s',datetime($timenow,'unixepoch','localtime','start of day','utc','+1 day','-$maxcount day'))) GROUP BY strftime('%m',datetime([Timestamp],'unixepoch','localtime')),strftime('%d',datetime([Timestamp],'unixepoch','localtime')) ORDER BY [Timestamp] DESC;"
  1170. } > "$8"
  1171. fi
  1172. }
  1173.  
  1174. WriteStats_ToJS(){
  1175. echo "function $3(){" >> "$2"
  1176. html='document.getElementById("'"$4"'").innerHTML="'
  1177. while IFS='' read -r line || [ -n "$line" ]; do
  1178. html="${html}${line}\\r\\n"
  1179. done < "$1"
  1180. html="$html"'"'
  1181. printf "%s\\r\\n}\\r\\n" "$html" >> "$2"
  1182. }
  1183.  
  1184. GenerateServerList(){
  1185. if [ ! -f /opt/bin/jq ]; then
  1186. opkg update
  1187. opkg install jq
  1188. fi
  1189. promptforservername="$2"
  1190. printf "Generating list of closest servers for %s...\\n\\n" "$1"
  1191. CONFIG_STRING=""
  1192. LICENSE_STRING="--accept-license --accept-gdpr"
  1193. SPEEDTEST_BINARY=""
  1194. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  1195. SPEEDTEST_BINARY=/usr/sbin/ookla
  1196. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  1197. SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
  1198. fi
  1199. if [ "$SPEEDTEST_BINARY" = /usr/sbin/ookla ]; then
  1200. CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
  1201. LICENSE_STRING=""
  1202. fi
  1203. serverlist="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$1")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
  1204. if [ -z "$serverlist" ]; then
  1205. Print_Output true "Error retrieving server list for for $1" "$CRIT"
  1206. serverno="exit"
  1207. return 1
  1208. fi
  1209. servercount="$(echo "$serverlist" | jq '.servers | length')"
  1210. COUNTER=1
  1211. until [ $COUNTER -gt "$servercount" ]; do
  1212. serverdetails="$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .id')|$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .name + " (" + .location + ", " + .country + ")"')"
  1213.  
  1214. if [ "$COUNTER" -lt 10 ]; then
  1215. printf "%s) %s\\n" "$COUNTER" "$serverdetails"
  1216. elif [ "$COUNTER" -ge 10 ]; then
  1217. printf "%s) %s\\n" "$COUNTER" "$serverdetails"
  1218. fi
  1219. COUNTER=$((COUNTER + 1))
  1220. done
  1221.  
  1222. printf "\\ne) Go back\\n"
  1223.  
  1224. while true; do
  1225. printf "\\n${BOLD}Please select a server from the list above (1-%s):${CLEARFORMAT}\\n" "$servercount"
  1226. printf "\\n${BOLD}Or press c to enter a known server ID${CLEARFORMAT}\\n"
  1227. printf "${BOLD}Enter answer:${CLEARFORMAT} "
  1228. read -r server
  1229.  
  1230. if [ "$server" = "e" ]; then
  1231. serverno="exit"
  1232. break
  1233. elif [ "$server" = "c" ]; then
  1234. while true; do
  1235. printf "\\n${BOLD}Please enter server ID (WARNING: this is not validated) or e to go back${CLEARFORMAT} "
  1236. read -r customserver
  1237. if [ "$customserver" = "e" ]; then
  1238. break
  1239. elif ! Validate_Number "$customserver"; then
  1240. printf "\\n\\e[31mPlease enter a valid number${CLEARFORMAT}\\n"
  1241. else
  1242. serverno="$customserver"
  1243. if [ "$promptforservername" != "no" ]; then
  1244. while true; do
  1245. printf "\\n${BOLD}Would you like to enter a name for this server? (default: Custom) (y/n)?${CLEARFORMAT} "
  1246. read -r servername_select
  1247.  
  1248. if [ "$servername_select" = "n" ] || [ "$servername_select" = "N" ]; then
  1249. servername="Custom"
  1250. break
  1251. elif [ "$servername_select" = "y" ] || [ "$servername_select" = "Y" ]; then
  1252. printf "\\n${BOLD}Please enter the name for this server:${CLEARFORMAT} "
  1253. read -r servername
  1254. printf "\\n${BOLD}%s${CLEARFORMAT}\\n" "$servername"
  1255. printf "\\n${BOLD}Is that correct (y/n)?${CLEARFORMAT} "
  1256. read -r servername_confirm
  1257. if [ "$servername_confirm" = "y" ] || [ "$servername_confirm" = "Y" ]; then
  1258. break
  1259. else
  1260. printf "\\n\\e[31mPlease enter y or n${CLEARFORMAT}\\n"
  1261. fi
  1262. else
  1263. printf "\\n\\e[31mPlease enter y or n${CLEARFORMAT}\\n"
  1264. fi
  1265. done
  1266. else
  1267. servername="Custom"
  1268. fi
  1269.  
  1270. printf "\\n"
  1271. return 0
  1272. fi
  1273. done
  1274. elif ! Validate_Number "$server"; then
  1275. printf "\\n\\e[31mPlease enter a valid number (1-%s)${CLEARFORMAT}\\n" "$servercount"
  1276. else
  1277. if [ "$server" -lt 1 ] || [ "$server" -gt "$servercount" ]; then
  1278. printf "\\n\\e[31mPlease enter a number between 1 and %s${CLEARFORMAT}\\n" "$servercount"
  1279. else
  1280. serverno="$(echo "$serverlist" | jq -r --argjson index "$((server-1))" '.servers[$index] | .id')"
  1281. servername="$(echo "$serverlist" | jq -r --argjson index "$((server-1))" '.servers[$index] | .name + " (" + .location + ", " + .country + ")"')"
  1282. printf "\\n"
  1283. break
  1284. fi
  1285. fi
  1286. done
  1287. }
  1288.  
  1289. GenerateServerList_WebUI(){
  1290. serverlistfile="$2"
  1291. rm -f "/tmp/$serverlistfile.txt"
  1292. rm -f "$SCRIPT_WEB_DIR/$serverlistfile.htm"
  1293. SPEEDTEST_BINARY=""
  1294. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  1295. SPEEDTEST_BINARY=/usr/sbin/ookla
  1296. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  1297. SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
  1298. fi
  1299. CONFIG_STRING=""
  1300. LICENSE_STRING="--accept-license --accept-gdpr"
  1301. if [ "$SPEEDTEST_BINARY" = /usr/sbin/ookla ]; then
  1302. CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
  1303. LICENSE_STRING=""
  1304. fi
  1305.  
  1306. spdifacename="$1"
  1307.  
  1308. if [ ! -f /opt/bin/jq ]; then
  1309. opkg update
  1310. opkg install jq
  1311. fi
  1312.  
  1313. if [ "$spdifacename" = "ALL" ]; then
  1314. while IFS='' read -r line || [ -n "$line" ]; do
  1315. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  1316. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1317. fi
  1318. done < "$SCRIPT_INTERFACES_USER"
  1319. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1320.  
  1321. for IFACE_NAME in $IFACELIST; do
  1322. serverlist="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$IFACE_NAME")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
  1323. servercount="$(echo "$serverlist" | jq '.servers | length')"
  1324. COUNTER=1
  1325. until [ $COUNTER -gt "$servercount" ]; do
  1326. printf "%s|%s\\n" "$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .id')" "$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .name + " (" + .location + ", " + .country + ")"')" >> "/tmp/$serverlistfile.tmp"
  1327. COUNTER=$((COUNTER + 1))
  1328. done
  1329. printf "-----\\n" >> "/tmp/$serverlistfile.tmp"
  1330. done
  1331. else
  1332. serverlist="$("$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$(Get_Interface_From_Name "$spdifacename")" --servers --format="json" $LICENSE_STRING)" 2>/dev/null
  1333. servercount="$(echo "$serverlist" | jq '.servers | length')"
  1334. COUNTER=1
  1335. until [ $COUNTER -gt "$servercount" ]; do
  1336. printf "%s|%s\\n" "$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .id')" "$(echo "$serverlist" | jq -r --argjson index "$((COUNTER-1))" '.servers[$index] | .name + " (" + .location + ", " + .country + ")"')" >> "/tmp/$serverlistfile.tmp"
  1337. COUNTER=$((COUNTER + 1))
  1338. done
  1339. fi
  1340. sleep 1
  1341. mv "/tmp/$serverlistfile.tmp" "/tmp/$serverlistfile.txt"
  1342. ln -s "/tmp/$serverlistfile.txt" "$SCRIPT_WEB_DIR/$serverlistfile.htm" 2>/dev/null
  1343. }
  1344.  
  1345. PreferredServer(){
  1346. case "$1" in
  1347. update)
  1348. GenerateServerList "$2"
  1349. if [ "$serverno" != "exit" ]; then
  1350. sed -i 's/^PREFERREDSERVER_'"$2"'=.*$/PREFERREDSERVER_'"$2"'='"$serverno|$servername"'/' "$SCRIPT_CONF"
  1351. else
  1352. return 1
  1353. fi
  1354. ;;
  1355. enable)
  1356. sed -i 's/^USEPREFERRED_'"$2"'=.*$/USEPREFERRED_'"$2"'=true/' "$SCRIPT_CONF"
  1357. ;;
  1358. disable)
  1359. sed -i 's/^USEPREFERRED_'"$2"'=.*$/USEPREFERRED_'"$2"'=false/' "$SCRIPT_CONF"
  1360. ;;
  1361. check)
  1362. USEPREFERRED=$(grep "USEPREFERRED_$2" "$SCRIPT_CONF" | cut -f2 -d"=")
  1363. if [ "$USEPREFERRED" = "true" ]; then return 0; else return 1; fi
  1364. ;;
  1365. list)
  1366. PREFERREDSERVER=$(grep "PREFERREDSERVER_$2" "$SCRIPT_CONF" | cut -f2 -d"=")
  1367. echo "$PREFERREDSERVER"
  1368. ;;
  1369. esac
  1370. }
  1371.  
  1372. Run_Speedtest(){
  1373. if [ ! -f /opt/bin/xargs ]; then
  1374. Print_Output true "Installing findutils from Entware"
  1375. opkg update
  1376. opkg install findutils
  1377. fi
  1378. if [ -n "$PPID" ]; then
  1379. ps | grep -v grep | grep -v $$ | grep -v "$PPID" | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
  1380. else
  1381. ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
  1382. fi
  1383. Create_Dirs
  1384. Conf_Exists
  1385. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  1386. printf "/usr/sbin/ookla" > /tmp/spdmerlin-binary
  1387. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  1388. printf "%s" "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
  1389. fi
  1390. Auto_Startup create 2>/dev/null
  1391. if AutomaticMode check; then Auto_Cron create 2>/dev/null; else Auto_Cron delete 2>/dev/null; fi
  1392. Auto_ServiceEvent create 2>/dev/null
  1393. Shortcut_Script create
  1394. ScriptStorageLocation load
  1395. Create_Symlinks
  1396.  
  1397. mode="$1"
  1398. specificiface="$2"
  1399. speedtestserverno=""
  1400. speedtestservername=""
  1401.  
  1402. CONFIG_STRING=""
  1403. LICENSE_STRING="--accept-license --accept-gdpr"
  1404. PROC_NAME="speedtest"
  1405. SPEEDTEST_BINARY=""
  1406. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  1407. SPEEDTEST_BINARY=/usr/sbin/ookla
  1408. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  1409. SPEEDTEST_BINARY="$OOKLA_DIR/speedtest"
  1410. fi
  1411. if [ "$SPEEDTEST_BINARY" = /usr/sbin/ookla ]; then
  1412. CONFIG_STRING="-c http://www.speedtest.net/api/embed/vz0azjarf5enop8a/config"
  1413. LICENSE_STRING=""
  1414. PROC_NAME="ookla"
  1415. fi
  1416.  
  1417. echo 'var spdteststatus = "InProgress";' > /tmp/detect_spdtest.js
  1418.  
  1419. tmpfile=/tmp/spd-stats.txt
  1420. resultfile=/tmp/spd-result.txt
  1421. rm -f "$resultfile"
  1422. rm -f "$tmpfile"
  1423.  
  1424. if [ -n "$(pidof "$PROC_NAME")" ]; then
  1425. killall -q "$PROC_NAME"
  1426. fi
  1427.  
  1428. if Check_Swap ; then
  1429. IFACELIST=""
  1430. if [ -z "$specificiface" ]; then
  1431. while IFS='' read -r line || [ -n "$line" ]; do
  1432. if [ "$(echo "$line" | grep -c "#")" -eq 0 ]; then
  1433. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1434. fi
  1435. done < "$SCRIPT_INTERFACES_USER"
  1436. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1437. elif [ "$specificiface" = "All" ]; then
  1438. while IFS='' read -r line || [ -n "$line" ]; do
  1439. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  1440. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1441. fi
  1442. done < "$SCRIPT_INTERFACES_USER"
  1443. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1444. else
  1445. IFACELIST="$specificiface"
  1446. fi
  1447.  
  1448. if [ "$IFACELIST" != "" ]; then
  1449. stoppedqos="false"
  1450. if [ "$(ExcludeFromQoS check)" = "true" ]; then
  1451. if [ "$(nvram get qos_enable)" -eq 1 ] && [ "$(nvram get qos_type)" -eq 1 ]; then
  1452. for ACTION in -D -A ; do
  1453. for proto in tcp udp; do
  1454. iptables "$ACTION" OUTPUT -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1455. iptables "$ACTION" OUTPUT -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1456. iptables -t mangle "$ACTION" OUTPUT -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1457. iptables -t mangle "$ACTION" POSTROUTING -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1458. iptables -t mangle "$ACTION" OUTPUT -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1459. iptables -t mangle "$ACTION" POSTROUTING -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1460. done
  1461. stoppedqos="true"
  1462. done
  1463. elif [ "$(nvram get qos_enable)" -eq 1 ] && [ "$(nvram get qos_type)" -ne 1 ] && [ -f /tmp/qos ]; then
  1464. /tmp/qos stop >/dev/null 2>&1
  1465. stoppedqos="true"
  1466. elif [ "$(nvram get qos_enable)" -eq 0 ] && [ -f /jffs/addons/cake-qos/cake-qos ]; then
  1467. /jffs/addons/cake-qos/cake-qos stop >/dev/null 2>&1
  1468. stoppedqos="true"
  1469. fi
  1470. fi
  1471.  
  1472. applyautobw="false"
  1473.  
  1474. if [ "$mode" = "schedule" ] && [ "$(AutoBWEnable check)" = "true" ]; then
  1475. applyautobw="true"
  1476. fi
  1477.  
  1478. for IFACE_NAME in $IFACELIST; do
  1479. IFACE="$(Get_Interface_From_Name "$IFACE_NAME")"
  1480. IFACE_LOWER="$(echo "$IFACE" | tr "A-Z" "a-z")"
  1481. if [ ! -f "/sys/class/net/$IFACE_LOWER/operstate" ] || [ "$(cat "/sys/class/net/$IFACE_LOWER/operstate")" = "down" ]; then
  1482. Print_Output true "$IFACE not up, please check. Skipping speedtest for $IFACE_NAME" "$WARN"
  1483. continue
  1484. else
  1485. if [ "$mode" = "webui_user" ]; then
  1486. mode="user"
  1487. elif [ "$mode" = "webui_auto" ]; then
  1488. mode="auto"
  1489. elif [ "$mode" = "webui_onetime" ]; then
  1490. mode="user"
  1491. fi
  1492.  
  1493. if [ "$mode" = "schedule" ]; then
  1494. if PreferredServer check "$IFACE_NAME"; then
  1495. speedtestserverno="$(PreferredServer list "$IFACE_NAME" | cut -f1 -d"|")"
  1496. speedtestservername="$(PreferredServer list "$IFACE_NAME" | cut -f2 -d"|")"
  1497. else
  1498. mode="auto"
  1499. fi
  1500. elif [ "$mode" = "onetime" ]; then
  1501. GenerateServerList "$IFACE_NAME" no
  1502. if [ "$serverno" != "exit" ]; then
  1503. speedtestserverno="$serverno"
  1504. speedtestservername="$servername"
  1505. else
  1506. Clear_Lock
  1507. return 1
  1508. fi
  1509. elif [ "$mode" = "user" ]; then
  1510. speedtestserverno="$(PreferredServer list "$IFACE_NAME" | cut -f1 -d"|")"
  1511. speedtestservername="$(PreferredServer list "$IFACE_NAME" | cut -f2 -d"|")"
  1512. fi
  1513.  
  1514. echo 'var spdteststatus = "InProgress_'"$IFACE_NAME"'";' > /tmp/detect_spdtest.js
  1515. printf "" > "$tmpfile"
  1516.  
  1517. if [ "$mode" = "auto" ]; then
  1518. Print_Output true "Starting speedtest using auto-selected server for $IFACE_NAME interface" "$PASS"
  1519. "$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile" &
  1520. sleep 2
  1521. speedtestcount=0
  1522. while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedtestcount" -lt 120 ]; do
  1523. speedtestcount="$((speedtestcount + 1))"
  1524. sleep 1
  1525. done
  1526. if [ "$speedtestcount" -ge 120 ]; then
  1527. Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
  1528. killall -q "$PROC_NAME"
  1529. continue
  1530. fi
  1531. else
  1532. if [ "$speedtestserverno" -ne 0 ]; then
  1533. Print_Output true "Starting speedtest using $speedtestservername for $IFACE_NAME interface" "$PASS"
  1534. "$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE" --server-id="$speedtestserverno" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile" &
  1535. sleep 2
  1536. speedtestcount=0
  1537. while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedtestcount" -lt 120 ]; do
  1538. speedtestcount="$((speedtestcount + 1))"
  1539. sleep 1
  1540. done
  1541. if [ "$speedtestcount" -ge 120 ]; then
  1542. Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
  1543. killall -q "$PROC_NAME"
  1544. continue
  1545. fi
  1546. else
  1547. Print_Output true "Starting speedtest using using auto-selected server for $IFACE_NAME interface" "$PASS"
  1548. "$SPEEDTEST_BINARY" $CONFIG_STRING --interface="$IFACE" --format="human-readable" --unit="Mbps" -p $LICENSE_STRING | tee "$tmpfile" &
  1549. sleep 2
  1550. speedtestcount=0
  1551. while [ -n "$(pidof "$PROC_NAME")" ] && [ "$speedtestcount" -lt 120 ]; do
  1552. speedtestcount="$((speedtestcount + 1))"
  1553. sleep 1
  1554. done
  1555. if [ "$speedtestcount" -ge 120 ]; then
  1556. Print_Output true "Speedtest for $IFACE_NAME hung (> 2 mins), killing process" "$CRIT"
  1557. killall -q "$PROC_NAME"
  1558. continue
  1559. fi
  1560. fi
  1561. fi
  1562.  
  1563. if [ ! -f "$tmpfile" ] || [ -z "$(cat "$tmpfile")" ] || [ "$(grep -c FAILED $tmpfile)" -gt 0 ]; then
  1564. Print_Output true "Error running speedtest for $IFACE_NAME" "$CRIT"
  1565. continue
  1566. fi
  1567.  
  1568. ScriptStorageLocation load
  1569.  
  1570. TZ=$(cat /etc/TZ)
  1571. export TZ
  1572.  
  1573. timenow=$(date +"%s")
  1574. timenowfriendly=$(date +"%c")
  1575.  
  1576. ## New if-then-else block added to with ookla output when buffer bloat has been added to the human readable output
  1577. BUFFBLOAT=$(grep "Idle Latency:" "$tmpfile")
  1578. if [ -n "$BUFFBLOAT" ]; then
  1579. # Parse human readable output when buffer bloat data is included.
  1580. download="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $2}')"
  1581. upload="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $2}')"
  1582. latency="$(grep "Idle Latency:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $3}')"
  1583. jitter="$(grep "Idle Latency:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $6}' | tr -d 'ms,')"
  1584. pktloss="$(grep "Packet Loss:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $3}' | tr -d '%')"
  1585. resulturl="$(grep "Result URL:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $3}')"
  1586. datadownload="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $6}')"
  1587. dataupload="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $6}')"
  1588.  
  1589. datadownloadunit="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print substr($7,1,length($7)-1)}')"
  1590. datauploadunit="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print substr($7,1,length($7)-1)}')"
  1591.  
  1592. servername="$(grep "Server:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | cut -f1 -d'(' | cut -f2 -d':' | awk '{$1=$1;print}')"
  1593. serverid="$(grep "Server:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | cut -f2 -d'(' | awk '{print $2}' | tr -d ')')"
  1594. else
  1595.  
  1596. download="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $2}')"
  1597. upload="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $2}')"
  1598. latency="$(grep "Latency:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $2}')"
  1599. jitter="$(grep "Latency:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $4}' | tr -d '(')"
  1600. pktloss="$(grep "Packet Loss:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $3}' | tr -d '%')"
  1601. resulturl="$(grep "Result URL:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $3}')"
  1602. datadownload="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $6}')"
  1603. dataupload="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print $6}')"
  1604.  
  1605. datadownloadunit="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print substr($7,1,length($7)-1)}')"
  1606. datauploadunit="$(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{print substr($7,1,length($7)-1)}')"
  1607.  
  1608. servername="$(grep "Server:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | cut -f1 -d'(' | cut -f2 -d':' | awk '{$1=$1;print}')"
  1609. serverid="$(grep "Server:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | cut -f2 -d'(' | awk '{print $3}' | tr -d ')')"
  1610. fi
  1611.  
  1612. ! Validate_Bandwidth "$download" && download=0;
  1613. ! Validate_Bandwidth "$upload" && upload=0;
  1614. ! Validate_Bandwidth "$latency" && latency="null";
  1615. ! Validate_Bandwidth "$jitter" && jitter="null";
  1616. ! Validate_Bandwidth "$pktloss" && pktloss="null";
  1617. ! Validate_Bandwidth "$datadownload" && datadownload=0;
  1618. ! Validate_Bandwidth "$dataupload" && dataupload=0;
  1619.  
  1620. if [ "$datadownloadunit" = "GB" ]; then
  1621. datadownload="$(echo "$datadownload" | awk '{printf ($1*1024)}')"
  1622. fi
  1623.  
  1624. if [ "$datauploadunit" = "GB" ]; then
  1625. dataupload="$(echo "$dataupload" | awk '{printf ($1*1024)}')"
  1626. fi
  1627.  
  1628. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  1629. curllatency="$latency"
  1630. if [ "$curllatency" = "null" ]; then
  1631. curllatency=0
  1632. fi
  1633.  
  1634. curlresult=$(curl -fsL -d "recommendedserverid=$serverid" \
  1635. -d "ping=$(echo "$curllatency" | awk '{printf("%.0f\n", $1);}')" \
  1636. -d "screenresolution=" \
  1637. -d "promo=" \
  1638. -d "download=$(echo "$download" | awk '{printf("%.0f\n", $1*1000);}')" \
  1639. -d "screendpi=" \
  1640. -d "upload=$(echo "$upload" | awk '{printf("%.0f\n", $1*1000);}')" \
  1641. -d "testmethod=http" \
  1642. -d "hash=$(printf "$(echo "$curllatency" | awk '{printf("%.0f\n", $1);}')-$(echo "$upload" | awk '{printf("%.0f\n", $1*1000);}')-$(echo "$download" | awk '{printf("%.0f\n", $1*1000);}')-297aae72" | md5sum | cut -f1 -d' ')" \
  1643. -d "touchscreen=none" \
  1644. -d "startmode=pingselect" \
  1645. -d "accuracy=1" \
  1646. -d "bytesreceived=$(echo "$datadownload" | awk '{printf("%.0f\n", $1*1024);}')" \
  1647. -d "bytessent=$(echo "$dataupload" | awk '{printf("%.0f\n", $1*1024);}')" \
  1648. -d "serverid=$serverid" \
  1649. -H "Referer: http://c.speedtest.net/flash/speedtest.swf" https://www.speedtest.net/api/api.php)
  1650.  
  1651. resulturl="https://www.speedtest.net/result/$(echo "$curlresult" | cut -f2 -d'&' | cut -f2 -d'=')"
  1652. printf " Result URL: %s\\n" "$resulturl" | tee -a "$tmpfile"
  1653. fi
  1654.  
  1655. echo "CREATE TABLE IF NOT EXISTS [spdstats_$IFACE_NAME] ([StatID] INTEGER PRIMARY KEY NOT NULL,[Timestamp] NUMERIC NOT NULL,[Download] REAL NOT NULL,[Upload] REAL NOT NULL,[Latency] REAL,[Jitter] REAL,[PktLoss] REAL,[ResultURL] TEXT,[DataDownload] REAL NOT NULL,[DataUpload] REAL NOT NULL,[ServerID] TEXT,[ServerName] TEXT);" > /tmp/spd-stats.sql
  1656. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1657.  
  1658. STORERESULTURL="$(StoreResultURL check)"
  1659.  
  1660. if [ "$STORERESULTURL" = "true" ]; then
  1661. echo "INSERT INTO spdstats_$IFACE_NAME ([Timestamp],[Download],[Upload],[Latency],[Jitter],[PktLoss],[ResultURL],[DataDownload],[DataUpload],[ServerID],[ServerName]) values($timenow,$download,$upload,$latency,$jitter,$pktloss,'$resulturl',$datadownload,$dataupload,$serverid,'$servername');" > /tmp/spd-stats.sql
  1662. elif [ "$STORERESULTURL" = "false" ]; then
  1663. echo "INSERT INTO spdstats_$IFACE_NAME ([Timestamp],[Download],[Upload],[Latency],[Jitter],[PktLoss],[ResultURL],[DataDownload],[DataUpload],[ServerID],[ServerName]) values($timenow,$download,$upload,$latency,$jitter,$pktloss,'',$datadownload,$dataupload,$serverid,'$servername');" > /tmp/spd-stats.sql
  1664. fi
  1665. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1666.  
  1667. {
  1668. echo "DELETE FROM [spdstats_$IFACE_NAME] WHERE [Timestamp] < strftime('%s',datetime($timenow,'unixepoch','-$(DaysToKeep check) day'));"
  1669. echo "PRAGMA analysis_limit=0;"
  1670. echo "PRAGMA cache_size=-20000;"
  1671. echo "ANALYZE spdstats_$IFACE_NAME;"
  1672. } > /tmp/spd-stats.sql
  1673. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql >/dev/null 2>&1
  1674. rm -f /tmp/spd-stats.sql
  1675.  
  1676. spdtestresult="$(grep "Download:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};'| awk '{$1=$1};1') - $(grep "Upload:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};'| awk '{$1=$1};1')"
  1677. spdtestresult2="$(grep "Latency:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{$1=$1};1') - $(grep "Packet Loss:" "$tmpfile" | awk 'BEGIN { FS = "\r" } ;{print $NF};' | awk '{$1=$1};1')"
  1678.  
  1679. printf "\\n"
  1680. Print_Output true "Speedtest results - $spdtestresult" "$PASS"
  1681. Print_Output true "Connection quality - $spdtestresult2" "$PASS"
  1682.  
  1683. {
  1684. printf "Speedtest result for %s\\n" "$IFACE_NAME"
  1685. printf "\\nBandwidth - %s\\n" "$spdtestresult"
  1686. printf "Quality - %s\\n\\n" "$spdtestresult2"
  1687. grep "Result URL" "$tmpfile" | awk '{$1=$1};1'
  1688. printf "\\n\\n\\n"
  1689. } >> "$resultfile"
  1690. #extStats
  1691. extStats="/jffs/addons/extstats.d/mod_spdstats.sh"
  1692. if [ -f "$extStats" ]; then
  1693. sh "$extStats" ext "$download" "$upload"
  1694. fi
  1695. fi
  1696. done
  1697.  
  1698. if [ "$stoppedqos" = "true" ]; then
  1699. if [ "$(nvram get qos_enable)" -eq 1 ] && [ "$(nvram get qos_type)" -eq 1 ]; then
  1700. for proto in tcp udp; do
  1701. iptables -D OUTPUT -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1702. iptables -D OUTPUT -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1703. iptables -t mangle -D OUTPUT -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1704. iptables -t mangle -D POSTROUTING -p "$proto" -o "$(Get_Interface_From_Name WAN)" -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1705. iptables -t mangle -D OUTPUT -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1706. iptables -t mangle -D POSTROUTING -p "$proto" -o tun1+ -j MARK --set-xmark 0x80000000/0xC0000000 2>/dev/null
  1707. done
  1708. elif [ "$(nvram get qos_enable)" -eq 1 ] && [ "$(nvram get qos_type)" -ne 1 ] && [ -f /tmp/qos ]; then
  1709. /tmp/qos start >/dev/null 2>&1
  1710. elif [ "$(nvram get qos_enable)" -eq 0 ] && [ -f /jffs/addons/cake-qos/cake-qos ]; then
  1711. /jffs/addons/cake-qos/cake-qos start >/dev/null 2>&1
  1712. fi
  1713. fi
  1714.  
  1715. echo 'var spdteststatus = "GenerateCSV";' > /tmp/detect_spdtest.js
  1716. Print_Output true "Retrieving data for WebUI charts" "$PASS"
  1717. Generate_CSVs
  1718.  
  1719. echo "Stats last updated: $timenowfriendly" > /tmp/spdstatstitle.txt
  1720. rm -f "$SCRIPT_STORAGE_DIR/spdtitletext.js"
  1721. WriteStats_ToJS /tmp/spdstatstitle.txt "$SCRIPT_STORAGE_DIR/spdtitletext.js" SetSPDStatsTitle statstitle
  1722.  
  1723. if [ "$applyautobw" = "true" ]; then
  1724. Menu_AutoBW_Update
  1725. fi
  1726.  
  1727. rm -f "$tmpfile"
  1728. rm -f /tmp/spdstatstitle.txt
  1729.  
  1730. echo 'var spdteststatus = "Done";' > /tmp/detect_spdtest.js
  1731.  
  1732. Clear_Lock
  1733. else
  1734. echo 'var spdteststatus = "Error";' > /tmp/detect_spdtest.js
  1735. Print_Output true "No interfaces enabled, exiting" "$CRIT"
  1736. Clear_Lock
  1737. return 1
  1738. fi
  1739. Clear_Lock
  1740. else
  1741. echo 'var spdteststatus = "NoSwap";' > /tmp/detect_spdtest.js
  1742. Print_Output true "Swap file not active, exiting" "$CRIT"
  1743. Clear_Lock
  1744. return 1
  1745. fi
  1746. }
  1747.  
  1748. Run_Speedtest_WebUI(){
  1749. spdteststring="$(echo "$1" | sed "s/${SCRIPT_NAME_LOWER}spdtest_//;s/%/ /g")";
  1750. spdtestmode="webui_$(echo "$spdteststring" | cut -f1 -d'_')";
  1751. spdifacename="$(echo "$spdteststring" | cut -f2 -d'_')";
  1752.  
  1753. cp -a "$SCRIPT_CONF" "$SCRIPT_CONF.bak"
  1754.  
  1755. if [ "$spdtestmode" = "webui_onetime" ]; then
  1756. spdtestserverlist="$(echo "$spdteststring" | cut -f3 -d'_')";
  1757. if [ "$spdifacename" = "All" ]; then
  1758. while IFS='' read -r line || [ -n "$line" ]; do
  1759. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  1760. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1761. fi
  1762. done < "$SCRIPT_INTERFACES_USER"
  1763. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1764.  
  1765. COUNT=1
  1766. for IFACE_NAME in $IFACELIST; do
  1767. spdtestserver="$(grep -m1 "$(echo "$spdtestserverlist" | cut -f"$COUNT" -d'+')" /tmp/spdmerlin_manual_serverlist.txt)"
  1768. sed -i 's/^PREFERREDSERVER_'"$IFACE_NAME"'=.*$/PREFERREDSERVER_'"$IFACE_NAME"'='"$spdtestserver"'/' "$SCRIPT_CONF"
  1769. COUNT=$((COUNT+1))
  1770. done
  1771. else
  1772. spdtestserver="$(grep -m1 "$spdtestserverlist" /tmp/spdmerlin_manual_serverlist.txt)"
  1773. sed -i 's/^PREFERREDSERVER_'"$spdifacename"'=.*$/PREFERREDSERVER_'"$spdifacename"'='"$spdtestserver"'/' "$SCRIPT_CONF"
  1774. fi
  1775. fi
  1776. sleep 1
  1777. Run_Speedtest "$spdtestmode" "$spdifacename"
  1778. cp -a "$SCRIPT_CONF.bak" "$SCRIPT_CONF"
  1779. }
  1780.  
  1781. Process_Upgrade(){
  1782. if [ ! -f "$OOKLA_DIR/speedtest" ]; then
  1783. Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz"
  1784. tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR"
  1785. rm -f "$OOKLA_DIR/$ARCH.tar.gz"
  1786. chmod 0755 "$OOKLA_DIR/speedtest"
  1787. fi
  1788. rm -f "$SCRIPT_STORAGE_DIR/spdjs.js"
  1789. rm -f "$SCRIPT_STORAGE_DIR/.tableupgraded"*
  1790. if [ ! -f "$SCRIPT_STORAGE_DIR/spdtitletext.js" ]; then
  1791. {
  1792. echo 'function SetSPDStatsTitle(){';
  1793. echo 'document.getElementById("statstitle").innerHTML="Stats last updated: Not yet updated\r\n";';
  1794. echo "}";
  1795. } > "$SCRIPT_STORAGE_DIR/spdtitletext.js"
  1796. fi
  1797.  
  1798. if [ "$(AutoBWEnable check)" = "true" ]; then
  1799. if [ "$(ExcludeFromQoS check)" = "false" ]; then
  1800. Print_Output false "Enabling Exclude from QoS (required for AutoBW)"
  1801. ExcludeFromQoS enable
  1802. fi
  1803. fi
  1804.  
  1805. FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5"
  1806. for IFACE_NAME in $FULL_IFACELIST; do
  1807. echo "CREATE TABLE IF NOT EXISTS [spdstats_$IFACE_NAME] ([StatID] INTEGER PRIMARY KEY NOT NULL,[Timestamp] NUMERIC NOT NULL,[Download] REAL NOT NULL,[Upload] REAL NOT NULL,[Latency] REAL,[Jitter] REAL,[PktLoss] REAL,[ResultURL] TEXT,[DataDownload] REAL NOT NULL,[DataUpload] REAL NOT NULL,[ServerID] TEXT,[ServerName] TEXT);" > /tmp/spdstats-upgrade.sql
  1808. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1809. done
  1810.  
  1811. if [ ! -f "$SCRIPT_STORAGE_DIR/.databaseupgraded" ]; then
  1812. renice 15 $$
  1813. Print_Output true "Upgrading database..." "$PASS"
  1814. FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5"
  1815. for IFACE_NAME in $FULL_IFACELIST; do
  1816. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_download ON spdstats_${IFACE_NAME} (Timestamp,Download);" > /tmp/spdstats-upgrade.sql
  1817. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1818. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_upload ON spdstats_${IFACE_NAME} (Timestamp,Upload);" > /tmp/spdstats-upgrade.sql
  1819. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1820. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_latency ON spdstats_${IFACE_NAME} (Timestamp,Latency);" > /tmp/spdstats-upgrade.sql
  1821. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1822. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_jitter ON spdstats_${IFACE_NAME} (Timestamp,Jitter);" > /tmp/spdstats-upgrade.sql
  1823. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1824. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_pktloss ON spdstats_${IFACE_NAME} (Timestamp,PktLoss);" > /tmp/spdstats-upgrade.sql
  1825. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1826. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_resulturl ON spdstats_${IFACE_NAME} (Timestamp,ResultURL collate nocase);" > /tmp/spdstats-upgrade.sql
  1827. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1828. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_datadownload ON spdstats_${IFACE_NAME} (Timestamp,DataDownload);" > /tmp/spdstats-upgrade.sql
  1829. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1830. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_datadownload ON spdstats_${IFACE_NAME} (Timestamp,DataUpload);" > /tmp/spdstats-upgrade.sql
  1831. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1832. echo "ALTER TABLE spdstats_${IFACE_NAME} ADD COLUMN [ServerID] TEXT" > /tmp/spdstats-upgrade.sql
  1833. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql >/dev/null 2>&1
  1834. echo "ALTER TABLE spdstats_${IFACE_NAME} ADD COLUMN [ServerName] TEXT" > /tmp/spdstats-upgrade.sql
  1835. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql >/dev/null 2>&1
  1836. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_serverid ON spdstats_${IFACE_NAME} (Timestamp,ServerID);" > /tmp/spdstats-upgrade.sql
  1837. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1838. echo "PRAGMA cache_size=-20000; CREATE INDEX IF NOT EXISTS idx_${IFACE_NAME}_servername ON spdstats_${IFACE_NAME} (Timestamp,ServerName collate nocase);" > /tmp/spdstats-upgrade.sql
  1839. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spdstats-upgrade.sql
  1840. Generate_LastXResults "$IFACE_NAME"
  1841. done
  1842. touch "$SCRIPT_STORAGE_DIR/.databaseupgraded"
  1843. Generate_CSVs
  1844. Print_Output true "Database ready, continuing..." "$PASS"
  1845. renice 0 $$
  1846. fi
  1847. rm -f /tmp/spdstats-upgrade.sql
  1848. }
  1849.  
  1850. #$1 iface name
  1851. Generate_LastXResults(){
  1852. FULL_IFACELIST="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5"
  1853. for IFACE_NAME in $FULL_IFACELIST; do
  1854. rm -f "$SCRIPT_STORAGE_DIR/lastx_${IFACE_NAME}.htm"
  1855. done
  1856. {
  1857. echo ".mode csv"
  1858. echo ".output /tmp/spd-lastx.csv"
  1859. } > /tmp/spd-lastx.sql
  1860. echo "SELECT [Timestamp],[Download],[Upload],[Latency],[Jitter],[PktLoss],[DataDownload],[DataUpload],[ResultURL],[ServerID],[ServerName] FROM spdstats_$1 ORDER BY [Timestamp] DESC LIMIT $(LastXResults check);" >> /tmp/spd-lastx.sql
  1861. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-lastx.sql
  1862. rm -f /tmp/spd-lastx.sql
  1863. sed -i 's/,,/,null,/g;s/"//g;' /tmp/spd-lastx.csv
  1864. mv /tmp/spd-lastx.csv "$SCRIPT_STORAGE_DIR/lastx_$1.csv"
  1865. }
  1866.  
  1867. Generate_CSVs(){
  1868. Process_Upgrade
  1869. renice 15 $$
  1870.  
  1871. OUTPUTTIMEMODE="$(OutputTimeMode check)"
  1872. STORERESULTURL="$(StoreResultURL check)"
  1873. IFACELIST=""
  1874.  
  1875. while IFS='' read -r line || [ -n "$line" ]; do
  1876. IFACELIST="$IFACELIST $(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  1877. done < "$SCRIPT_INTERFACES_USER"
  1878. IFACELIST="$(echo "$IFACELIST" | cut -c2-)"
  1879.  
  1880. if [ "$IFACELIST" != "" ]; then
  1881. for IFACE_NAME in $IFACELIST; do
  1882. IFACE="$(Get_Interface_From_Name "$IFACE_NAME")"
  1883.  
  1884. TZ=$(cat /etc/TZ)
  1885. export TZ
  1886.  
  1887. timenow=$(date +"%s")
  1888. timenowfriendly=$(date +"%c")
  1889.  
  1890. metriclist="Download Upload Latency Jitter PktLoss" # DataDownload DataUpload"
  1891.  
  1892. for metric in $metriclist; do
  1893. {
  1894. echo ".mode csv"
  1895. echo ".headers off"
  1896. echo ".output $CSV_OUTPUT_DIR/${metric}_raw_daily_$IFACE_NAME.tmp"
  1897. echo "SELECT '$metric' Metric,[Timestamp] Time,[$metric] Value FROM spdstats_$IFACE_NAME WHERE ([Timestamp] >= strftime('%s',datetime($timenow,'unixepoch','-1 day'))) ORDER BY [Timestamp] DESC;"
  1898. } > /tmp/spd-stats.sql
  1899. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1900.  
  1901. {
  1902. echo ".mode csv"
  1903. echo ".headers off"
  1904. echo ".output $CSV_OUTPUT_DIR/${metric}_raw_weekly_$IFACE_NAME.tmp"
  1905. echo "SELECT '$metric' Metric,[Timestamp] Time,[$metric] Value FROM spdstats_$IFACE_NAME WHERE ([Timestamp] >= strftime('%s',datetime($timenow,'unixepoch','-7 day'))) ORDER BY [Timestamp] DESC;"
  1906. } > /tmp/spd-stats.sql
  1907. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1908.  
  1909. {
  1910. echo ".mode csv"
  1911. echo ".headers off"
  1912. echo ".output $CSV_OUTPUT_DIR/${metric}_raw_monthly_$IFACE_NAME.tmp"
  1913. echo "SELECT '$metric' Metric,[Timestamp] Time,[$metric] Value FROM spdstats_$IFACE_NAME WHERE ([Timestamp] >= strftime('%s',datetime($timenow,'unixepoch','-30 day'))) ORDER BY [Timestamp] DESC;"
  1914. } > /tmp/spd-stats.sql
  1915. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1916.  
  1917. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 1 1 "$CSV_OUTPUT_DIR/${metric}_hour" daily "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1918. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1919.  
  1920. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 1 7 "$CSV_OUTPUT_DIR/${metric}_hour" weekly "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1921. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1922.  
  1923. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 1 30 "$CSV_OUTPUT_DIR/${metric}_hour" monthly "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1924. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1925.  
  1926. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 24 1 "$CSV_OUTPUT_DIR/${metric}_day" daily "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1927. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1928.  
  1929. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 24 7 "$CSV_OUTPUT_DIR/${metric}_day" weekly "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1930. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1931.  
  1932. WriteSql_ToFile "$metric" "spdstats_$IFACE_NAME" 24 30 "$CSV_OUTPUT_DIR/${metric}_day" monthly "$IFACE_NAME" /tmp/spd-stats.sql "$timenow"
  1933. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  1934. done
  1935.  
  1936. periodfilelist="raw hour day"
  1937.  
  1938. for periodfile in $periodfilelist; do
  1939. cat "$CSV_OUTPUT_DIR/Download_${periodfile}_daily_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Upload_${periodfile}_daily_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Combined_${periodfile}_daily_${IFACE_NAME}.htm" 2> /dev/null
  1940. cat "$CSV_OUTPUT_DIR/Download_${periodfile}_weekly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Upload_${periodfile}_weekly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Combined_${periodfile}_weekly_${IFACE_NAME}.htm" 2> /dev/null
  1941. cat "$CSV_OUTPUT_DIR/Download_${periodfile}_monthly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Upload_${periodfile}_monthly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Combined_${periodfile}_monthly_${IFACE_NAME}.htm" 2> /dev/null
  1942.  
  1943. cat "$CSV_OUTPUT_DIR/Latency_${periodfile}_daily_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Jitter_${periodfile}_daily_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/PktLoss_${periodfile}_daily_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Quality_${periodfile}_daily_${IFACE_NAME}.htm" 2> /dev/null
  1944. cat "$CSV_OUTPUT_DIR/Latency_${periodfile}_weekly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Jitter_${periodfile}_weekly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/PktLoss_${periodfile}_weekly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Quality_${periodfile}_weekly_${IFACE_NAME}.htm" 2> /dev/null
  1945. cat "$CSV_OUTPUT_DIR/Latency_${periodfile}_monthly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/Jitter_${periodfile}_monthly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/PktLoss_${periodfile}_monthly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/Quality_${periodfile}_monthly_${IFACE_NAME}.htm" 2> /dev/null
  1946.  
  1947. #cat "$CSV_OUTPUT_DIR/DataDownload_${periodfile}_daily_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/DataUpload_${periodfile}_daily_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/DataUsage_${periodfile}_daily_${IFACE_NAME}.htm" 2> /dev/null
  1948. #cat "$CSV_OUTPUT_DIR/DataDownload_${periodfile}_weekly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/DataUpload_${periodfile}_weekly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/DataUsage_${periodfile}_weekly_${IFACE_NAME}.htm" 2> /dev/null
  1949. #cat "$CSV_OUTPUT_DIR/DataDownload_${periodfile}_monthly_${IFACE_NAME}.tmp" "$CSV_OUTPUT_DIR/DataUpload_${periodfile}_monthly_${IFACE_NAME}.tmp" > "$CSV_OUTPUT_DIR/DataUsage_${periodfile}_monthly_${IFACE_NAME}.htm" 2> /dev/null
  1950. done
  1951.  
  1952. csvlist="Combined Quality" # DataUsage"
  1953. for csvfile in $csvlist; do
  1954. rm -f "$CSV_OUTPUT_DIR/${csvfile}daily_${IFACE_NAME}.htm"
  1955. rm -f "$CSV_OUTPUT_DIR/${csvfile}weekly_${IFACE_NAME}.htm"
  1956. rm -f "$CSV_OUTPUT_DIR/${csvfile}monthly_${IFACE_NAME}.htm"
  1957. for periodfile in $periodfilelist; do
  1958. sed -i '1i Metric,Time,Value' "$CSV_OUTPUT_DIR/${csvfile}_${periodfile}_daily_${IFACE_NAME}.htm"
  1959. sed -i '1i Metric,Time,Value' "$CSV_OUTPUT_DIR/${csvfile}_${periodfile}_weekly_${IFACE_NAME}.htm"
  1960. sed -i '1i Metric,Time,Value' "$CSV_OUTPUT_DIR/${csvfile}_${periodfile}_monthly_${IFACE_NAME}.htm"
  1961. done
  1962. done
  1963.  
  1964. INCLUDEURL=""
  1965. if [ "$STORERESULTURL" = "true" ]; then
  1966. INCLUDEURL=",[ResultURL]"
  1967. fi
  1968.  
  1969. {
  1970. echo ".mode csv"
  1971. echo ".headers on"
  1972. echo ".output $CSV_OUTPUT_DIR/CompleteResults_${IFACE_NAME}.htm"
  1973. echo "SELECT [Timestamp],[Download],[Upload],[Latency],[Jitter],[PktLoss]$INCLUDEURL,[DataDownload],[DataUpload],[ServerID],[ServerName] FROM spdstats_$IFACE_NAME WHERE ([Timestamp] >= strftime('%s',datetime($timenow,'unixepoch','-$(DaysToKeep check) day'))) ORDER BY [Timestamp] DESC;"
  1974. } > /tmp/spd-complete.sql
  1975. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-complete.sql
  1976. rm -f /tmp/spd-complete.sql
  1977.  
  1978. rm -f "$CSV_OUTPUT_DIR/Download"*
  1979. rm -f "$CSV_OUTPUT_DIR/Upload"*
  1980. rm -f "$CSV_OUTPUT_DIR/Latency"*
  1981. rm -f "$CSV_OUTPUT_DIR/Jitter"*
  1982. rm -f "$CSV_OUTPUT_DIR/PktLoss"*
  1983. rm -f "$CSV_OUTPUT_DIR/DataDownload"*
  1984. rm -f "$CSV_OUTPUT_DIR/DataUpload"*
  1985.  
  1986. Generate_LastXResults "$IFACE_NAME"
  1987. rm -f /tmp/spd-stats.sql
  1988. done
  1989.  
  1990. dos2unix "$CSV_OUTPUT_DIR/"*.htm
  1991.  
  1992. tmpoutputdir="/tmp/${SCRIPT_NAME_LOWER}results"
  1993. mkdir -p "$tmpoutputdir"
  1994. mv "$CSV_OUTPUT_DIR/CompleteResults"*.htm "$tmpoutputdir/."
  1995.  
  1996. if [ "$OUTPUTTIMEMODE" = "unix" ]; then
  1997. find "$tmpoutputdir/" -name '*.htm' -exec sh -c 'i="$1"; mv -- "$i" "${i%.htm}.csv"' _ {} \;
  1998. elif [ "$OUTPUTTIMEMODE" = "non-unix" ]; then
  1999. for i in "$tmpoutputdir/"*".htm"; do
  2000. awk -F"," 'NR==1 {OFS=","; print} NR>1 {OFS=","; $1=strftime("%Y-%m-%d %H:%M:%S", $1); print }' "$i" > "$i.out"
  2001. done
  2002.  
  2003. find "$tmpoutputdir/" -name '*.htm.out' -exec sh -c 'i="$1"; mv -- "$i" "${i%.htm.out}.csv"' _ {} \;
  2004. rm -f "$tmpoutputdir/"*.htm
  2005. fi
  2006.  
  2007. if [ ! -f /opt/bin/7za ]; then
  2008. opkg update
  2009. opkg install p7zip
  2010. fi
  2011. /opt/bin/7za a -y -bsp0 -bso0 -tzip "/tmp/${SCRIPT_NAME_LOWER}data.zip" "$tmpoutputdir/*"
  2012. mv "/tmp/${SCRIPT_NAME_LOWER}data.zip" "$CSV_OUTPUT_DIR"
  2013. rm -rf "$tmpoutputdir"
  2014. fi
  2015. renice 0 $$
  2016. }
  2017.  
  2018. Reset_DB(){
  2019. SIZEAVAIL="$(df -P -k "$SCRIPT_STORAGE_DIR" | awk '{print $4}' | tail -n 1)"
  2020. SIZEDB="$(ls -l "$SCRIPT_STORAGE_DIR/spdstats.db" | awk '{print $5}')"
  2021. if [ "$SIZEDB" -gt "$((SIZEAVAIL*1024))" ]; then
  2022. Print_Output true "Database size exceeds available space. $(ls -lh "$SCRIPT_STORAGE_DIR/spdstats.db" | awk '{print $5}')B is required to create backup." "$ERR"
  2023. return 1
  2024. else
  2025. Print_Output true "Sufficient free space to back up database, proceeding..." "$PASS"
  2026. if ! cp -a "$SCRIPT_STORAGE_DIR/spdstats.db" "$SCRIPT_STORAGE_DIR/spdstats.db.bak"; then
  2027. Print_Output true "Database backup failed, please check storage device" "$WARN"
  2028. fi
  2029.  
  2030. tablelist="WAN VPNC1 VPNC2 VPNC3 VPNC4 VPNC5"
  2031. for dbtable in $tablelist; do
  2032. echo "DELETE FROM [spdstats_$dbtable];" > /tmp/spd-stats.sql
  2033. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-stats.sql
  2034. rm -f /tmp/spd-stats.sql
  2035. done
  2036.  
  2037. Print_Output true "Database reset complete" "$WARN"
  2038. fi
  2039. }
  2040.  
  2041. Shortcut_Script(){
  2042. case $1 in
  2043. create)
  2044. if [ -d "/opt/bin" ] && [ ! -f "/opt/bin/$SCRIPT_NAME_LOWER" ] && [ -f "/jffs/scripts/$SCRIPT_NAME_LOWER" ]; then
  2045. ln -s "/jffs/scripts/$SCRIPT_NAME_LOWER" /opt/bin
  2046. chmod 0755 "/opt/bin/$SCRIPT_NAME_LOWER"
  2047. fi
  2048. ;;
  2049. delete)
  2050. if [ -f "/opt/bin/$SCRIPT_NAME_LOWER" ]; then
  2051. rm -f "/opt/bin/$SCRIPT_NAME_LOWER"
  2052. fi
  2053. ;;
  2054. esac
  2055. }
  2056.  
  2057. PressEnter(){
  2058. while true; do
  2059. printf "Press enter to continue..."
  2060. read -r key
  2061. case "$key" in
  2062. *)
  2063. break
  2064. ;;
  2065. esac
  2066. done
  2067. return 0
  2068. }
  2069.  
  2070. ScriptHeader(){
  2071. clear
  2072.  
  2073. printf "\\n"
  2074. printf "${BOLD}####################################################################${CLEARFORMAT}\\n"
  2075. printf "${BOLD}## _ __ __ _ _ ##${CLEARFORMAT}\\n"
  2076. printf "${BOLD}## | || \/ | | |(_) ##${CLEARFORMAT}\\n"
  2077. printf "${BOLD}## ___ _ __ __| || \ / | ___ _ __ | | _ _ __ ##${CLEARFORMAT}\\n"
  2078. printf "${BOLD}## / __|| '_ \ / _ || |\/| | / _ \| '__|| || || '_ \ ##${CLEARFORMAT}\\n"
  2079. printf "${BOLD}## \__ \| |_) || (_| || | | || __/| | | || || | | | ##${CLEARFORMAT}\\n"
  2080. printf "${BOLD}## |___/| .__/ \__,_||_| |_| \___||_| |_||_||_| |_| ##${CLEARFORMAT}\\n"
  2081. printf "${BOLD}## | | ##${CLEARFORMAT}\\n"
  2082. printf "${BOLD}## |_| ##${CLEARFORMAT}\\n"
  2083. printf "${BOLD}## ##${CLEARFORMAT}\\n"
  2084. printf "${BOLD}## %s on %-11s ##${CLEARFORMAT}\\n" "$SCRIPT_VERSION" "$ROUTER_MODEL"
  2085. printf "${BOLD}## ##${CLEARFORMAT}\\n"
  2086. printf "${BOLD}## https://github.com/jackyaz/spdMerlin ##${CLEARFORMAT}\\n"
  2087. printf "${BOLD}## ##${CLEARFORMAT}\\n"
  2088. printf "${BOLD}####################################################################${CLEARFORMAT}\\n"
  2089. printf "\\n"
  2090. }
  2091.  
  2092. MainMenu(){
  2093. AUTOMATIC_ENABLED=""
  2094. EXCLUDEFROMQOS_MENU=""
  2095. if AutomaticMode check; then AUTOMATIC_ENABLED="${PASS}Enabled"; else AUTOMATIC_ENABLED="${ERR}Disabled"; fi
  2096. TEST_SCHEDULE="$(TestSchedule check)"
  2097. if [ "$(echo "$TEST_SCHEDULE" | cut -f2 -d'|' | grep -c "/")" -gt 0 ] && [ "$(echo "$TEST_SCHEDULE" | cut -f3 -d'|')" -eq 0 ]; then
  2098. TEST_SCHEDULE_MENU="Every $(echo "$TEST_SCHEDULE" | cut -f2 -d'|' | cut -f2 -d'/') hours"
  2099. elif [ "$(echo "$TEST_SCHEDULE" | cut -f3 -d'|' | grep -c "/")" -gt 0 ] && [ "$(echo "$TEST_SCHEDULE" | cut -f2 -d'|')" = "*" ]; then
  2100. TEST_SCHEDULE_MENU="Every $(echo "$TEST_SCHEDULE" | cut -f3 -d'|' | cut -f2 -d'/') minutes"
  2101. else
  2102. TEST_SCHEDULE_MENU="Hours: $(echo "$TEST_SCHEDULE" | cut -f2 -d'|') - Minutes: $(echo "$TEST_SCHEDULE" | cut -f3 -d'|')"
  2103. fi
  2104.  
  2105. if [ "$(echo "$TEST_SCHEDULE" | cut -f1 -d'|')" = "*" ]; then
  2106. TEST_SCHEDULE_MENU2="Days of week: All"
  2107. else
  2108. TEST_SCHEDULE_MENU2="Days of week: $(echo "$TEST_SCHEDULE" | cut -f1 -d'|')"
  2109. fi
  2110. STORERESULTURL_MENU=""
  2111. if [ "$(StoreResultURL check)" = "true" ]; then
  2112. STORERESULTURL_MENU="Enabled"
  2113. else
  2114. STORERESULTURL_MENU="Disabled"
  2115. fi
  2116.  
  2117. printf "WebUI for %s is available at:\\n${SETTING}%s${CLEARFORMAT}\\n\\n" "$SCRIPT_NAME" "$(Get_WebUI_URL)"
  2118. if [ "$(ExcludeFromQoS check)" = "true" ]; then EXCLUDEFROMQOS_MENU="excluded from"; else EXCLUDEFROMQOS_MENU="included in"; fi
  2119.  
  2120. printf "1. Run a speedtest now\\n\\n"
  2121. printf "2. Choose a preferred server for an interface\\n\\n"
  2122. printf "3. Toggle automatic speedtests\\n Currently: ${BOLD}${AUTOMATIC_ENABLED}%s${CLEARFORMAT}\\n\\n"
  2123. printf "4. Configure schedule for automatic speedtests\\n ${SETTING}%s\\n %s${CLEARFORMAT}\\n\\n" "$TEST_SCHEDULE_MENU" "$TEST_SCHEDULE_MENU2"
  2124. printf "5. Toggle time output mode\\n Currently ${SETTING}%s${CLEARFORMAT} time values will be used for CSV exports\\n\\n" "$(OutputTimeMode check)"
  2125. printf "6. Toggle storage of speedtest result URLs\\n Currently: ${SETTING}%s${CLEARFORMAT}\\n\\n" "$STORERESULTURL_MENU"
  2126. printf "7. Set number of speedtest results to show in WebUI\\n Currently: ${SETTING}%s results will be shown${CLEARFORMAT}\\n\\n" "$(LastXResults check)"
  2127. printf "8. Set number of days data to keep in database\\n Currently: ${SETTING}%s days data will be kept${CLEARFORMAT}\\n\\n" "$(DaysToKeep check)"
  2128. printf "9. Toggle between built-in Ookla speedtest and speedtest-cli\\n Currently: ${SETTING}%s${CLEARFORMAT} will be used for speedtests${CLEARFORMAT}\\n\\n" "$(SpeedtestBinary check)"
  2129. printf "c. Customise list of interfaces for automatic speedtests\\n"
  2130. printf "r. Reset list of interfaces for automatic speedtests to default\\n\\n"
  2131. printf "s. Toggle storage location for stats and config\\n Current location is ${SETTING}%s${CLEARFORMAT} \\n\\n" "$(ScriptStorageLocation check)"
  2132. printf "q. Toggle exclusion of %s speedtests from QoS\\n Currently %s speedtests are ${SETTING}%s${CLEARFORMAT} QoS\\n\\n" "$SCRIPT_NAME" "$SCRIPT_NAME" "$EXCLUDEFROMQOS_MENU"
  2133. printf "a. AutoBW\\n\\n"
  2134. printf "u. Check for updates\\n"
  2135. printf "uf. Update %s with latest version (force update)\\n\\n" "$SCRIPT_NAME"
  2136. printf "rt. Reset %s database / delete all data\\n\\n" "$SCRIPT_NAME"
  2137. printf "e. Exit %s\\n\\n" "$SCRIPT_NAME"
  2138. printf "z. Uninstall %s\\n" "$SCRIPT_NAME"
  2139. printf "\\n"
  2140. printf "${BOLD}####################################################################${CLEARFORMAT}\\n"
  2141. printf "\\n"
  2142.  
  2143. while true; do
  2144. printf "Choose an option: "
  2145. read -r menu
  2146. case "$menu" in
  2147. 1)
  2148. printf "\\n"
  2149. Menu_RunSpeedtest
  2150. PressEnter
  2151. break
  2152. ;;
  2153. 2)
  2154. printf "\\n"
  2155. Menu_ConfigurePreferred
  2156. PressEnter
  2157. break
  2158. ;;
  2159. 3)
  2160. printf "\\n"
  2161. if AutomaticMode check; then
  2162. AutomaticMode disable
  2163. else
  2164. AutomaticMode enable
  2165. fi
  2166. break
  2167. ;;
  2168. 4)
  2169. printf "\\n"
  2170. Menu_EditSchedule
  2171. PressEnter
  2172. break
  2173. ;;
  2174. 5)
  2175. printf "\\n"
  2176. if [ "$(OutputTimeMode check)" = "unix" ]; then
  2177. OutputTimeMode non-unix
  2178. elif [ "$(OutputTimeMode check)" = "non-unix" ]; then
  2179. OutputTimeMode unix
  2180. fi
  2181. break
  2182. ;;
  2183. 6)
  2184. printf "\\n"
  2185. if [ "$(StoreResultURL check)" = "true" ]; then
  2186. StoreResultURL disable
  2187. elif [ "$(StoreResultURL check)" = "false" ]; then
  2188. StoreResultURL enable
  2189. fi
  2190. break
  2191. ;;
  2192. 7)
  2193. printf "\\n"
  2194. LastXResults update
  2195. PressEnter
  2196. break
  2197. ;;
  2198. 8)
  2199. printf "\\n"
  2200. DaysToKeep update
  2201. PressEnter
  2202. break
  2203. ;;
  2204. 9)
  2205. printf "\\n"
  2206. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  2207. SpeedtestBinary external
  2208. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  2209. SpeedtestBinary builtin
  2210. fi
  2211. break
  2212. ;;
  2213. c)
  2214. Generate_Interface_List
  2215. printf "\\n"
  2216. Create_Symlinks
  2217. printf "\\n"
  2218. PressEnter
  2219. break
  2220. ;;
  2221. r)
  2222. Create_Symlinks force
  2223. printf "\\n"
  2224. PressEnter
  2225. break
  2226. ;;
  2227. s)
  2228. printf "\\n"
  2229. if [ "$(ScriptStorageLocation check)" = "jffs" ]; then
  2230. ScriptStorageLocation usb
  2231. Create_Symlinks
  2232. elif [ "$(ScriptStorageLocation check)" = "usb" ]; then
  2233. ScriptStorageLocation jffs
  2234. Create_Symlinks
  2235. fi
  2236. break
  2237. ;;
  2238. q)
  2239. printf "\\n"
  2240. if [ "$(ExcludeFromQoS check)" = "true" ]; then
  2241. if [ "$(AutoBWEnable check)" = "true" ]; then
  2242. Print_Output false "Cannot disable Exclude from QoS when AutoBW is enabled" "$WARN"
  2243. PressEnter
  2244. elif [ "$(AutoBWEnable check)" = "false" ]; then
  2245. ExcludeFromQoS disable
  2246. fi
  2247. elif [ "$(ExcludeFromQoS check)" = "false" ]; then
  2248. ExcludeFromQoS enable
  2249. fi
  2250. break
  2251. ;;
  2252. a)
  2253. printf "\\n"
  2254. Menu_AutoBW
  2255. break
  2256. ;;
  2257. u)
  2258. printf "\\n"
  2259. if Check_Lock menu; then
  2260. Update_Version
  2261. Clear_Lock
  2262. fi
  2263. PressEnter
  2264. break
  2265. ;;
  2266. uf)
  2267. printf "\\n"
  2268. if Check_Lock menu; then
  2269. Update_Version force
  2270. Clear_Lock
  2271. fi
  2272. PressEnter
  2273. break
  2274. ;;
  2275. rt)
  2276. printf "\\n"
  2277. if Check_Lock menu; then
  2278. Menu_ResetDB
  2279. Clear_Lock
  2280. fi
  2281. PressEnter
  2282. break
  2283. ;;
  2284. e)
  2285. ScriptHeader
  2286. printf "\\n${BOLD}Thanks for using %s!${CLEARFORMAT}\\n\\n\\n" "$SCRIPT_NAME"
  2287. exit 0
  2288. ;;
  2289. z)
  2290. while true; do
  2291. printf "\\n${BOLD}Are you sure you want to uninstall %s? (y/n)${CLEARFORMAT} " "$SCRIPT_NAME"
  2292. read -r confirm
  2293. case "$confirm" in
  2294. y|Y)
  2295. Menu_Uninstall
  2296. exit 0
  2297. ;;
  2298. *)
  2299. break
  2300. ;;
  2301. esac
  2302. done
  2303. ;;
  2304. *)
  2305. printf "\\nPlease choose a valid option\\n\\n"
  2306. ;;
  2307. esac
  2308. done
  2309.  
  2310. ScriptHeader
  2311. MainMenu
  2312. }
  2313.  
  2314. Check_Requirements(){
  2315. CHECKSFAILED="false"
  2316.  
  2317. if [ "$(nvram get jffs2_scripts)" -ne 1 ]; then
  2318. nvram set jffs2_scripts=1
  2319. nvram commit
  2320. Print_Output true "Custom JFFS Scripts enabled" "$WARN"
  2321. fi
  2322.  
  2323. if ! Check_Swap; then
  2324. Print_Output false "No Swap file detected!" "$ERR"
  2325. CHECKSFAILED="true"
  2326. fi
  2327.  
  2328. if [ ! -f /opt/bin/opkg ]; then
  2329. Print_Output false "Entware not detected!" "$ERR"
  2330. CHECKSFAILED="true"
  2331. fi
  2332.  
  2333. if ! Firmware_Version_Check; then
  2334. Print_Output false "Unsupported firmware version detected" "$ERR"
  2335. Print_Output false "$SCRIPT_NAME requires Merlin 384.15/384.13_4 or Fork 43E5 (or later)" "$ERR"
  2336. CHECKSFAILED="true"
  2337. fi
  2338.  
  2339. if [ "$CHECKSFAILED" = "false" ]; then
  2340. Print_Output false "Installing required packages from Entware" "$PASS"
  2341. opkg update
  2342. opkg install sqlite3-cli
  2343. opkg install jq
  2344. opkg install p7zip
  2345. opkg install findutils
  2346. return 0
  2347. else
  2348. return 1
  2349. fi
  2350. }
  2351.  
  2352. Menu_Install(){
  2353. ScriptHeader
  2354. Print_Output true "Welcome to $SCRIPT_NAME $SCRIPT_VERSION, a script by JackYaz"
  2355. sleep 1
  2356.  
  2357. Print_Output true "By installing $SCRIPT_NAME you are agreeing to Ookla's license: $SCRIPT_REPO/speedtest-cli-license" "$WARN"
  2358.  
  2359. printf "\\n${BOLD}Do you wish to continue? (y/n)${CLEARFORMAT} " "$SCRIPT_NAME"
  2360. read -r confirm
  2361. case "$confirm" in
  2362. y|Y)
  2363. :
  2364. ;;
  2365. *)
  2366. Print_Output true "You did not agree to Ookla's license, removing $SCRIPT_NAME" "$CRIT"
  2367. Clear_Lock
  2368. rm -f "/jffs/scripts/$SCRIPT_NAME_LOWER" 2>/dev/null
  2369. exit 1
  2370. ;;
  2371. esac
  2372.  
  2373. Print_Output true "Checking your router meets the requirements for $SCRIPT_NAME"
  2374.  
  2375. if ! Check_Requirements; then
  2376. Print_Output true "Requirements for $SCRIPT_NAME not met, please see above for the reason(s)" "$CRIT"
  2377. PressEnter
  2378. Clear_Lock
  2379. rm -f "/jffs/scripts/$SCRIPT_NAME_LOWER" 2>/dev/null
  2380. exit 1
  2381. fi
  2382.  
  2383. Create_Dirs
  2384. Conf_Exists
  2385. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  2386. printf "/usr/sbin/ookla" > /tmp/spdmerlin-binary
  2387. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  2388. printf "%s" "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
  2389. fi
  2390. Set_Version_Custom_Settings local "$SCRIPT_VERSION"
  2391. Set_Version_Custom_Settings server "$SCRIPT_VERSION"
  2392. ScriptStorageLocation load
  2393. Create_Symlinks
  2394.  
  2395. Download_File "$SCRIPT_REPO/$ARCH.tar.gz" "$OOKLA_DIR/$ARCH.tar.gz"
  2396. tar -xzf "$OOKLA_DIR/$ARCH.tar.gz" -C "$OOKLA_DIR"
  2397. rm -f "$OOKLA_DIR/$ARCH.tar.gz"
  2398. chmod 0755 "$OOKLA_DIR/speedtest"
  2399.  
  2400. Update_File spdstats_www.asp
  2401. Update_File shared-jy.tar.gz
  2402.  
  2403. Auto_Startup create 2>/dev/null
  2404. Auto_Cron create 2>/dev/null
  2405. Auto_ServiceEvent create 2>/dev/null
  2406. Shortcut_Script create
  2407.  
  2408. Process_Upgrade
  2409.  
  2410. Run_Speedtest auto WAN
  2411.  
  2412. Clear_Lock
  2413.  
  2414. ScriptHeader
  2415. MainMenu
  2416. }
  2417.  
  2418. Menu_Startup(){
  2419. if [ -z "$1" ]; then
  2420. Print_Output true "Missing argument for startup, not starting $SCRIPT_NAME" "$WARN"
  2421. exit 1
  2422. elif [ "$1" != "force" ]; then
  2423. if [ ! -f "$1/entware/bin/opkg" ]; then
  2424. Print_Output true "$1 does not contain Entware, not starting $SCRIPT_NAME" "$WARN"
  2425. exit 1
  2426. else
  2427. Print_Output true "$1 contains Entware, starting $SCRIPT_NAME" "$WARN"
  2428. fi
  2429. fi
  2430.  
  2431. NTP_Ready
  2432.  
  2433. Check_Lock
  2434.  
  2435. if [ "$1" != "force" ]; then
  2436. sleep 8
  2437. fi
  2438.  
  2439. Create_Dirs
  2440. Conf_Exists
  2441. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  2442. printf "/usr/sbin/ookla" > /tmp/spdmerlin-binary
  2443. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  2444. printf "%s" "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
  2445. fi
  2446. ScriptStorageLocation load
  2447. Create_Symlinks
  2448. Auto_Startup create 2>/dev/null
  2449. if AutomaticMode check; then Auto_Cron create 2>/dev/null; else Auto_Cron delete 2>/dev/null; fi
  2450. Auto_ServiceEvent create 2>/dev/null
  2451. Shortcut_Script create
  2452. Mount_WebUI
  2453.  
  2454. Clear_Lock
  2455. }
  2456.  
  2457. Menu_RunSpeedtest(){
  2458. exitmenu=""
  2459. validselection=""
  2460. useiface=""
  2461. usepreferred=""
  2462. ScriptHeader
  2463. while true; do
  2464. printf "Choose an interface to speedtest:\\n\\n"
  2465. printf "1. All\\n"
  2466. COUNTER="2"
  2467. while IFS='' read -r line || [ -n "$line" ]; do
  2468. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  2469. printf "%s. %s\\n" "$COUNTER" "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  2470. COUNTER=$((COUNTER+1))
  2471. fi
  2472. done < "$SCRIPT_INTERFACES_USER"
  2473. printf "\\nChoose an option: "
  2474. read -r iface_choice
  2475.  
  2476. if [ "$iface_choice" = "e" ]; then
  2477. exitmenu="exit"
  2478. break
  2479. elif ! Validate_Number "$iface_choice"; then
  2480. printf "\\n\\e[31mPlease enter a valid number (1-%s)${CLEARFORMAT}\\n" "$((COUNTER-1))"
  2481. validselection="false"
  2482. else
  2483. if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$((COUNTER-1))" ]; then
  2484. printf "\\n\\e[31mPlease enter a number between 1 and %s${CLEARFORMAT}\\n" "$((COUNTER-1))"
  2485. validselection="false"
  2486. else
  2487. if [ "$iface_choice" -gt "1" ]; then
  2488. useiface="$(grep -v "interface not up" "$SCRIPT_INTERFACES_USER" | sed -n $((iface_choice-1))p | cut -f1 -d"#" | sed 's/ *$//')"
  2489. else
  2490. useiface="All"
  2491. fi
  2492. validselection="true"
  2493. fi
  2494. fi
  2495.  
  2496. printf "\\n"
  2497.  
  2498. if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ]; then
  2499. while true; do
  2500. printf "What mode would you like to use?\\n\\n"
  2501. printf "1. Auto-select\\n"
  2502. printf "2. Preferred server\\n"
  2503. printf "3. Choose a server\\n"
  2504. printf "\\nChoose an option: "
  2505. read -r usepref_choice
  2506.  
  2507. if [ "$usepref_choice" = "e" ]; then
  2508. exitmenu="exit"
  2509. break
  2510. elif ! Validate_Number "$usepref_choice"; then
  2511. printf "\\n\\e[31mPlease enter a valid number (1-%s)${CLEARFORMAT}\\n" "$COUNTER"
  2512. validselection="false"
  2513. else
  2514. if [ "$usepref_choice" -lt 0 ] || [ "$usepref_choice" -gt "3" ]; then
  2515. printf "\\n\\e[31mPlease enter a number between 1 and %s${CLEARFORMAT}\\n" "$COUNTER"
  2516. validselection="false"
  2517. else
  2518. case "$usepref_choice" in
  2519. 1)
  2520. usepreferred="auto"
  2521. ;;
  2522. 2)
  2523. usepreferred="user"
  2524. ;;
  2525. 3)
  2526. usepreferred="onetime"
  2527. ;;
  2528. esac
  2529. validselection="true"
  2530. printf "\\n"
  2531. break
  2532. fi
  2533. fi
  2534. done
  2535. fi
  2536. if [ "$exitmenu" != "exit" ] && [ "$validselection" != "false" ]; then
  2537. if Check_Lock menu; then
  2538. Run_Speedtest "$usepreferred" "$useiface"
  2539. Clear_Lock
  2540. fi
  2541. elif [ "$exitmenu" = "exit" ]; then
  2542. break
  2543. fi
  2544. printf "\\n"
  2545. PressEnter
  2546. ScriptHeader
  2547. done
  2548.  
  2549. if [ "$exitmenu" != "exit" ]; then
  2550. return 0
  2551. else
  2552. printf "\\n"
  2553. return 1
  2554. fi
  2555. }
  2556.  
  2557. Menu_ConfigurePreferred(){
  2558. exitmenu=""
  2559. prefiface=""
  2560. ScriptHeader
  2561. while true; do
  2562. printf "Choose an interface to configure server preference for:\\n\\n"
  2563. printf "1. All (on/off only)\\n\\n"
  2564. COUNTER="2"
  2565. while IFS='' read -r line || [ -n "$line" ]; do
  2566. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  2567. pref_enabled=""
  2568. if PreferredServer check "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"; then pref_enabled="On"; else pref_enabled="Off"; fi
  2569. printf "%s. %s\\n" "$COUNTER" "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  2570. printf " Preferred: %s - Server: %s\\n\\n" "$pref_enabled" "$(PreferredServer list "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')" | cut -f2 -d"|")"
  2571. COUNTER=$((COUNTER+1))
  2572. fi
  2573. done < "$SCRIPT_INTERFACES_USER"
  2574. while true; do
  2575. printf "\\nChoose an option: "
  2576. read -r iface_choice
  2577.  
  2578. if [ "$iface_choice" = "e" ]; then
  2579. exitmenu="exit"
  2580. break
  2581. elif ! Validate_Number "$iface_choice"; then
  2582. printf "\\n\\e[31mPlease enter a valid number (1-%s)${CLEARFORMAT}\\n" "$((COUNTER-1))"
  2583. else
  2584. if [ "$iface_choice" -lt 1 ] || [ "$iface_choice" -gt "$((COUNTER-1))" ]; then
  2585. printf "\\n\\e[31mPlease enter a number between 1 and %s${CLEARFORMAT}\\n" "$((COUNTER-1))"
  2586. else
  2587. if [ "$iface_choice" -gt "1" ]; then
  2588. prefiface="$(grep -v "interface not up" "$SCRIPT_INTERFACES_USER" | sed -n $((iface_choice-1))p | cut -f1 -d"#" | sed 's/ *$//')"
  2589. break
  2590. else
  2591. prefiface="All"
  2592. break
  2593. fi
  2594. fi
  2595. fi
  2596. done
  2597.  
  2598. printf "\\n"
  2599.  
  2600. if [ "$exitmenu" != "exit" ]; then
  2601. if [ "$prefiface" = "All" ]; then
  2602. while true; do
  2603. printf "What would you like to do?\\n\\n"
  2604. printf "1. Turn on preferred servers\\n"
  2605. printf "2. Turn off preferred servers\\n"
  2606. printf "\\nChoose an option: "
  2607. read -r usepref_choice
  2608.  
  2609. if [ "$usepref_choice" = "e" ]; then
  2610. break
  2611. elif ! Validate_Number "$usepref_choice"; then
  2612. printf "\\n\\e[31mPlease enter a valid number (1-2)${CLEARFORMAT}\\n"
  2613. else
  2614. if [ "$usepref_choice" -lt 1 ] || [ "$usepref_choice" -gt 2 ]; then
  2615. printf "\\n\\e[31mPlease enter a number between 1 and 2${CLEARFORMAT}\\n\\n"
  2616. else
  2617. prefenabledisable=""
  2618. if [ "$usepref_choice" -eq 1 ]; then
  2619. prefenabledisable="enable"
  2620. else
  2621. prefenabledisable="disable"
  2622. fi
  2623. while IFS='' read -r line || [ -n "$line" ]; do
  2624. if [ "$(echo "$line" | grep -c "interface not up")" -eq 0 ]; then
  2625. PreferredServer "$prefenabledisable" "$(echo "$line" | cut -f1 -d"#" | sed 's/ *$//')"
  2626. fi
  2627. done < "$SCRIPT_INTERFACES_USER"
  2628. printf "\\n"
  2629. break
  2630. fi
  2631. fi
  2632. done
  2633. else
  2634. while true; do
  2635. pref_enabled=""
  2636. if PreferredServer check "$prefiface"; then pref_enabled="On"; else pref_enabled="Off"; fi
  2637. printf "What would you like to do?\\n\\n"
  2638. printf "1. Toggle preferred server on/off - currently: %s\\n" "$pref_enabled"
  2639. printf "2. Set preferred server - currently: %s\\n" "$(PreferredServer list "$prefiface" | cut -f2 -d"|")"
  2640. printf "\\nChoose an option: "
  2641. read -r ifpref_choice
  2642.  
  2643. if [ "$ifpref_choice" = "e" ]; then
  2644. break
  2645. elif ! Validate_Number "$ifpref_choice"; then
  2646. printf "\\n\\e[31mPlease enter a valid number (1-2)${CLEARFORMAT}\\n"
  2647. else
  2648. if [ "$ifpref_choice" -lt 1 ] || [ "$ifpref_choice" -gt 2 ]; then
  2649. printf "\\n\\e[31mPlease enter a number between 1 and 2${CLEARFORMAT}\\n"
  2650. else
  2651. if [ "$ifpref_choice" -eq 1 ]; then
  2652. printf "\\n"
  2653. if PreferredServer check "$prefiface"; then
  2654. PreferredServer disable "$prefiface"
  2655. else
  2656. PreferredServer enable "$prefiface"
  2657. fi
  2658. break
  2659. elif [ "$ifpref_choice" -eq 2 ]; then
  2660. printf "\\n"
  2661. PreferredServer "update" "$prefiface"
  2662. break
  2663. fi
  2664. fi
  2665. fi
  2666. done
  2667. fi
  2668. fi
  2669. if [ "$exitmenu" = "exit" ]; then
  2670. break
  2671. fi
  2672. printf "\\n"
  2673. PressEnter
  2674. ScriptHeader
  2675. done
  2676.  
  2677. if [ "$exitmenu" != "exit" ]; then
  2678. return 0
  2679. else
  2680. printf "\\n"
  2681. return 1
  2682. fi
  2683. }
  2684.  
  2685. Menu_EditSchedule(){
  2686. exitmenu=""
  2687. formattype=""
  2688. crudays=""
  2689. crudaysvalidated=""
  2690. cruhours=""
  2691. crumins=""
  2692.  
  2693. while true; do
  2694. printf "\\n${BOLD}Please choose which day(s) to run speedtest (0-6 - 0 = Sunday, * for every day, or comma separated days):${CLEARFORMAT} "
  2695. read -r day_choice
  2696.  
  2697. if [ "$day_choice" = "e" ]; then
  2698. exitmenu="exit"
  2699. break
  2700. elif [ "$day_choice" = "*" ]; then
  2701. crudays="$day_choice"
  2702. printf "\\n"
  2703. break
  2704. elif [ -z "$day_choice" ]; then
  2705. printf "\\n\\e[31mPlease enter a valid number (0-6) or comma separated values${CLEARFORMAT}\\n"
  2706. else
  2707. crudaystmp="$(echo "$day_choice" | sed "s/,/ /g")"
  2708. crudaysvalidated="true"
  2709. for i in $crudaystmp; do
  2710. if echo "$i" | grep -q "-"; then
  2711. if [ "$i" = "-" ]; then
  2712. printf "\\n\\e[31mPlease enter a valid number (0-6)${CLEARFORMAT}\\n"
  2713. crudaysvalidated="false"
  2714. break
  2715. fi
  2716. crudaystmp2="$(echo "$i" | sed "s/-/ /")"
  2717. for i2 in $crudaystmp2; do
  2718. if ! Validate_Number "$i2"; then
  2719. printf "\\n\\e[31mPlease enter a valid number (0-6)${CLEARFORMAT}\\n"
  2720. crudaysvalidated="false"
  2721. break
  2722. elif [ "$i2" -lt 0 ] || [ "$i2" -gt 6 ]; then
  2723. printf "\\n\\e[31mPlease enter a number between 0 and 6${CLEARFORMAT}\\n"
  2724. crudaysvalidated="false"
  2725. break
  2726. fi
  2727. done
  2728. elif ! Validate_Number "$i"; then
  2729. printf "\\n\\e[31mPlease enter a valid number (0-6) or comma separated values${CLEARFORMAT}\\n"
  2730. crudaysvalidated="false"
  2731. break
  2732. else
  2733. if [ "$i" -lt 0 ] || [ "$i" -gt 6 ]; then
  2734. printf "\\n\\e[31mPlease enter a number between 0 and 6 or comma separated values${CLEARFORMAT}\\n"
  2735. crudaysvalidated="false"
  2736. break
  2737. fi
  2738. fi
  2739. done
  2740. if [ "$crudaysvalidated" = "true" ]; then
  2741. crudays="$day_choice"
  2742. printf "\\n"
  2743. break
  2744. fi
  2745. fi
  2746. done
  2747.  
  2748. if [ "$exitmenu" != "exit" ]; then
  2749. while true; do
  2750. printf "\\n${BOLD}Please choose the format to specify the hour/minute(s) to run speedtest:${CLEARFORMAT}\\n"
  2751. printf " 1. Every X hours/minutes\\n"
  2752. printf " 2. Custom\\n\\n"
  2753. printf "Choose an option: "
  2754. read -r formatmenu
  2755.  
  2756. case "$formatmenu" in
  2757. 1)
  2758. formattype="everyx"
  2759. printf "\\n"
  2760. break
  2761. ;;
  2762. 2)
  2763. formattype="custom"
  2764. printf "\\n"
  2765. break
  2766. ;;
  2767. e)
  2768. exitmenu="exit"
  2769. break
  2770. ;;
  2771. *)
  2772. printf "\\n\\e[31mPlease enter a valid choice (1-2)${CLEARFORMAT}\\n"
  2773. ;;
  2774. esac
  2775. done
  2776. fi
  2777.  
  2778. if [ "$exitmenu" != "exit" ]; then
  2779. if [ "$formattype" = "everyx" ]; then
  2780. while true; do
  2781. printf "\\n${BOLD}Please choose whether to specify every X hours or every X minutes to run speedtest:${CLEARFORMAT}\\n"
  2782. printf " 1. Hours\\n"
  2783. printf " 2. Minutes\\n\\n"
  2784. printf "Choose an option: "
  2785. read -r formatmenu
  2786.  
  2787. case "$formatmenu" in
  2788. 1)
  2789. formattype="hours"
  2790. printf "\\n"
  2791. break
  2792. ;;
  2793. 2)
  2794. formattype="mins"
  2795. printf "\\n"
  2796. break
  2797. ;;
  2798. e)
  2799. exitmenu="exit"
  2800. break
  2801. ;;
  2802. *)
  2803. printf "\\n\\e[31mPlease enter a valid choice (1-2)${CLEARFORMAT}\\n"
  2804. ;;
  2805. esac
  2806. done
  2807. fi
  2808. fi
  2809.  
  2810. if [ "$exitmenu" != "exit" ]; then
  2811. if [ "$formattype" = "hours" ]; then
  2812. while true; do
  2813. printf "\\n${BOLD}Please choose how often to run speedtest (every X hours, where X is 1-24):${CLEARFORMAT} "
  2814. read -r hour_choice
  2815.  
  2816. if [ "$hour_choice" = "e" ]; then
  2817. exitmenu="exit"
  2818. break
  2819. elif ! Validate_Number "$hour_choice"; then
  2820. printf "\\n\\e[31mPlease enter a valid number (1-24)${CLEARFORMAT}\\n"
  2821. elif [ "$hour_choice" -lt 1 ] || [ "$hour_choice" -gt 24 ]; then
  2822. printf "\\n\\e[31mPlease enter a number between 1 and 24${CLEARFORMAT}\\n"
  2823. elif [ "$hour_choice" -eq 24 ]; then
  2824. cruhours=0
  2825. crumins=0
  2826. printf "\\n"
  2827. break
  2828. else
  2829. cruhours="*/$hour_choice"
  2830. crumins=0
  2831. printf "\\n"
  2832. break
  2833. fi
  2834. done
  2835. elif [ "$formattype" = "mins" ]; then
  2836. while true; do
  2837. printf "\\n${BOLD}Please choose how often to run speedtest (every X minutes, where X is 1-30):${CLEARFORMAT} "
  2838. read -r min_choice
  2839.  
  2840. if [ "$min_choice" = "e" ]; then
  2841. exitmenu="exit"
  2842. break
  2843. elif ! Validate_Number "$min_choice"; then
  2844. printf "\\n\\e[31mPlease enter a valid number (1-30)${CLEARFORMAT}\\n"
  2845. elif [ "$min_choice" -lt 1 ] || [ "$min_choice" -gt 30 ]; then
  2846. printf "\\n\\e[31mPlease enter a number between 1 and 30${CLEARFORMAT}\\n"
  2847. else
  2848. crumins="*/$min_choice"
  2849. cruhours="*"
  2850. printf "\\n"
  2851. break
  2852. fi
  2853. done
  2854. fi
  2855. fi
  2856.  
  2857. if [ "$exitmenu" != "exit" ]; then
  2858. if [ "$formattype" = "custom" ]; then
  2859. while true; do
  2860. printf "\\n${BOLD}Please choose which hour(s) to run speedtest (0-23, * for every hour, or comma separated hours):${CLEARFORMAT} "
  2861. read -r hour_choice
  2862.  
  2863. if [ "$hour_choice" = "e" ]; then
  2864. exitmenu="exit"
  2865. break
  2866. elif [ "$hour_choice" = "*" ]; then
  2867. cruhours="$hour_choice"
  2868. printf "\\n"
  2869. break
  2870. else
  2871. cruhourstmp="$(echo "$hour_choice" | sed "s/,/ /g")"
  2872. cruhoursvalidated="true"
  2873. for i in $cruhourstmp; do
  2874. if echo "$i" | grep -q "-"; then
  2875. if [ "$i" = "-" ]; then
  2876. printf "\\n\\e[31mPlease enter a valid number (0-23)${CLEARFORMAT}\\n"
  2877. cruhoursvalidated="false"
  2878. break
  2879. fi
  2880. cruhourstmp2="$(echo "$i" | sed "s/-/ /")"
  2881. for i2 in $cruhourstmp2; do
  2882. if ! Validate_Number "$i2"; then
  2883. printf "\\n\\e[31mPlease enter a valid number (0-23)${CLEARFORMAT}\\n"
  2884. cruhoursvalidated="false"
  2885. break
  2886. elif [ "$i2" -lt 0 ] || [ "$i2" -gt 23 ]; then
  2887. printf "\\n\\e[31mPlease enter a number between 0 and 23${CLEARFORMAT}\\n"
  2888. cruhoursvalidated="false"
  2889. break
  2890. fi
  2891. done
  2892. elif echo "$i" | grep -q "/"; then
  2893. cruhourstmp3="$(echo "$i" | sed "s/\*\///")"
  2894. if ! Validate_Number "$cruhourstmp3"; then
  2895. printf "\\n\\e[31mPlease enter a valid number (0-23)${CLEARFORMAT}\\n"
  2896. cruhoursvalidated="false"
  2897. break
  2898. elif [ "$cruhourstmp3" -lt 0 ] || [ "$cruhourstmp3" -gt 23 ]; then
  2899. printf "\\n\\e[31mPlease enter a number between 0 and 23${CLEARFORMAT}\\n"
  2900. cruhoursvalidated="false"
  2901. break
  2902. fi
  2903. elif ! Validate_Number "$i"; then
  2904. printf "\\n\\e[31mPlease enter a valid number (0-23) or comma separated values${CLEARFORMAT}\\n"
  2905. cruhoursvalidated="false"
  2906. break
  2907. elif [ "$i" -lt 0 ] || [ "$i" -gt 23 ]; then
  2908. printf "\\n\\e[31mPlease enter a number between 0 and 23 or comma separated values${CLEARFORMAT}\\n"
  2909. cruhoursvalidated="false"
  2910. break
  2911. fi
  2912. done
  2913. if [ "$cruhoursvalidated" = "true" ]; then
  2914. if echo "$hour_choice" | grep -q "-"; then
  2915. cruhours1="$(echo "$hour_choice" | cut -f1 -d'-')"
  2916. cruhours2="$(echo "$hour_choice" | cut -f2 -d'-')"
  2917. if [ "$cruhours1" -lt "$cruhours2" ]; then
  2918. cruhours="$hour_choice"
  2919. elif [ "$cruhours2" -lt "$cruhours1" ]; then
  2920. cruhours="$cruhours1-23,0-$cruhours2"
  2921. fi
  2922. else
  2923. cruhours="$hour_choice"
  2924. fi
  2925. printf "\\n"
  2926. break
  2927. fi
  2928. fi
  2929. done
  2930. fi
  2931. fi
  2932.  
  2933. if [ "$exitmenu" != "exit" ]; then
  2934. if [ "$formattype" = "custom" ]; then
  2935. while true; do
  2936. printf "\\n${BOLD}Please choose which minutes(s) to run speedtest (0-59, * for every minute, or comma separated minutes):${CLEARFORMAT} "
  2937. read -r min_choice
  2938.  
  2939. if [ "$min_choice" = "e" ]; then
  2940. exitmenu="exit"
  2941. break
  2942. elif [ "$min_choice" = "*" ]; then
  2943. crumins="$min_choice"
  2944. printf "\\n"
  2945. break
  2946. else
  2947. cruminstmp="$(echo "$min_choice" | sed "s/,/ /g")"
  2948. cruminsvalidated="true"
  2949. for i in $cruminstmp; do
  2950. if echo "$i" | grep -q "-"; then
  2951. if [ "$i" = "-" ]; then
  2952. printf "\\n\\e[31mPlease enter a valid number (0-23)${CLEARFORMAT}\\n"
  2953. cruminsvalidated="false"
  2954. break
  2955. fi
  2956. cruminstmp2="$(echo "$i" | sed "s/-/ /")"
  2957. for i2 in $cruminstmp2; do
  2958. if ! Validate_Number "$i2"; then
  2959. printf "\\n\\e[31mPlease enter a valid number (0-59)${CLEARFORMAT}\\n"
  2960. cruminsvalidated="false"
  2961. break
  2962. elif [ "$i2" -lt 0 ] || [ "$i2" -gt 59 ]; then
  2963. printf "\\n\\e[31mPlease enter a number between 0 and 59${CLEARFORMAT}\\n"
  2964. cruminsvalidated="false"
  2965. break
  2966. fi
  2967. done
  2968. elif echo "$i" | grep -q "/"; then
  2969. cruminstmp3="$(echo "$i" | sed "s/\*\///")"
  2970. if ! Validate_Number "$cruminstmp3"; then
  2971. printf "\\n\\e[31mPlease enter a valid number (0-30)${CLEARFORMAT}\\n"
  2972. cruminsvalidated="false"
  2973. break
  2974. elif [ "$cruminstmp3" -lt 0 ] || [ "$cruminstmp3" -gt 30 ]; then
  2975. printf "\\n\\e[31mPlease enter a number between 0 and 30${CLEARFORMAT}\\n"
  2976. cruminsvalidated="false"
  2977. break
  2978. fi
  2979. elif ! Validate_Number "$i"; then
  2980. printf "\\n\\e[31mPlease enter a valid number (0-59) or comma separated values${CLEARFORMAT}\\n"
  2981. cruminsvalidated="false"
  2982. break
  2983. elif [ "$i" -lt 0 ] || [ "$i" -gt 59 ]; then
  2984. printf "\\n\\e[31mPlease enter a number between 0 and 59 or comma separated values${CLEARFORMAT}\\n"
  2985. cruminsvalidated="false"
  2986. break
  2987. fi
  2988. done
  2989.  
  2990. if [ "$cruminsvalidated" = "true" ]; then
  2991. if echo "$min_choice" | grep -q "-"; then
  2992. crumins1="$(echo "$min_choice" | cut -f1 -d'-')"
  2993. crumins2="$(echo "$min_choice" | cut -f2 -d'-')"
  2994. if [ "$crumins1" -lt "$crumins2" ]; then
  2995. crumins="$min_choice"
  2996. elif [ "$crumins2" -lt "$crumins1" ]; then
  2997. crumins="$crumins1-59,0-$crumins2"
  2998. fi
  2999. else
  3000. crumins="$min_choice"
  3001. fi
  3002. printf "\\n"
  3003. break
  3004. fi
  3005. fi
  3006. done
  3007. fi
  3008. fi
  3009.  
  3010. if [ "$exitmenu" != "exit" ]; then
  3011. TestSchedule update "$crudays" "$cruhours" "$crumins"
  3012. return 0
  3013. else
  3014. return 1
  3015. fi
  3016. }
  3017.  
  3018. Menu_ResetDB(){
  3019. printf "${BOLD}\\e[33mWARNING: This will reset the %s database by deleting all database records.\\n" "$SCRIPT_NAME"
  3020. printf "A backup of the database will be created if you change your mind.${CLEARFORMAT}\\n"
  3021. printf "\\n${BOLD}Do you want to continue? (y/n)${CLEARFORMAT} "
  3022. read -r confirm
  3023. case "$confirm" in
  3024. y|Y)
  3025. printf "\\n"
  3026. Reset_DB
  3027. ;;
  3028. *)
  3029. printf "\\n${BOLD}\\e[33mDatabase reset cancelled${CLEARFORMAT}\\n\\n"
  3030. ;;
  3031. esac
  3032. }
  3033.  
  3034. Menu_AutoBW(){
  3035. while true; do
  3036. ScriptHeader
  3037.  
  3038. AUTOBW_MENU=""
  3039.  
  3040. if [ "$(AutoBWEnable check)" = "true" ]; then
  3041. AUTOBW_MENU="Enabled"
  3042. elif [ "$(AutoBWEnable check)" = "false" ]; then
  3043. AUTOBW_MENU="Disabled"
  3044. fi
  3045.  
  3046. printf "1. Update QoS bandwidth values now\\n\\n"
  3047. printf "2. Configure number of speedtests used to calculate average bandwidth\\n Currently bandwidth is calculated using the avergae of the last ${SETTING}%s${CLEARFORMAT} speedtest(s)\\n\\n" "$(AutoBWConf check AVERAGE CALC)"
  3048. printf "3. Configure scale factor\\n Download: ${SETTING}%s%%${CLEARFORMAT} - Upload: ${SETTING}%s%%${CLEARFORMAT}\\n\\n" "$(AutoBWConf check SF DOWN)" "$(AutoBWConf check SF UP)"
  3049. printf "4. Configure bandwidth limits\\n Upper Limit Download: ${SETTING}%s Mbps${CLEARFORMAT} - Upload: ${SETTING}%s Mbps${CLEARFORMAT}\\n Lower Limit Download: ${SETTING}%s Mbps${CLEARFORMAT} - Upload: ${SETTING}%s Mbps${CLEARFORMAT}\\n\\n" "$(AutoBWConf check ULIMIT DOWN)" "$(AutoBWConf check ULIMIT UP)" "$(AutoBWConf check LLIMIT DOWN)" "$(AutoBWConf check LLIMIT UP)"
  3050. printf "5. Configure threshold for updating QoS bandwidth values\\n Download: ${SETTING}%s%%${CLEARFORMAT} - Upload: ${SETTING}%s%%${CLEARFORMAT}\\n\\n" "$(AutoBWConf check THRESHOLD DOWN)" "$(AutoBWConf check THRESHOLD UP)"
  3051. printf "6. Toggle AutoBW on/off\\n Currently: ${SETTING}%s${CLEARFORMAT}\\n\\n" "$AUTOBW_MENU"
  3052. printf "e. Go back\\n\\n"
  3053. printf "${BOLD}####################################################################${CLEARFORMAT}\\n"
  3054. printf "\\n"
  3055.  
  3056. printf "Choose an option: "
  3057. read -r autobwmenu
  3058. case "$autobwmenu" in
  3059. 1)
  3060. printf "\\n"
  3061. Menu_AutoBW_Update
  3062. PressEnter
  3063. ;;
  3064. 2)
  3065. while true; do
  3066. ScriptHeader
  3067. exitmenu=""
  3068. avgnum=""
  3069. while true; do
  3070. printf "\\n"
  3071. printf "Enter number of speedtests to use to calculate avg bandwidth (1-30): "
  3072. read -r avgnumvalue
  3073. if [ "$avgnumvalue" = "e" ]; then
  3074. exitmenu="exit"
  3075. break
  3076. elif ! Validate_Number "$avgnumvalue"; then
  3077. printf "\\n\\e[31mPlease enter a valid number (1-30)${CLEARFORMAT}\\n"
  3078. else
  3079. if [ "$avgnumvalue" -lt 1 ] || [ "$avgnumvalue" -gt 30 ]; then
  3080. printf "\\n\\e[31mPlease enter a number between 1 and 30${CLEARFORMAT}\\n"
  3081. else
  3082. avgnum="$avgnumvalue"
  3083. break
  3084. fi
  3085. fi
  3086. done
  3087. if [ "$exitmenu" != "exit" ]; then
  3088. AutoBWConf update AVERAGE CALC "$avgnum"
  3089. break
  3090. fi
  3091. if [ "$exitmenu" = "exit" ]; then
  3092. break
  3093. fi
  3094. done
  3095. printf "\\n"
  3096. PressEnter
  3097. ;;
  3098. 3)
  3099. while true; do
  3100. ScriptHeader
  3101. exitmenu=""
  3102. updown=""
  3103. sfvalue=""
  3104. printf "\\n"
  3105. printf "Select a scale factor to set\\n"
  3106. printf "1. Download\\n"
  3107. printf "2. Upload\\n\\n"
  3108. while true; do
  3109. printf "Choose an option: "
  3110. read -r autobwsfchoice
  3111. if [ "$autobwsfchoice" = "e" ]; then
  3112. exitmenu="exit"
  3113. break
  3114. elif ! Validate_Number "$autobwsfchoice"; then
  3115. printf "\\n\\e[31mPlease enter a valid number (1-2)${CLEARFORMAT}\\n\\n"
  3116. else
  3117. if [ "$autobwsfchoice" -lt 1 ] || [ "$autobwsfchoice" -gt 2 ]; then
  3118. printf "\\n\\e[31mPlease enter a number between 1 and 2${CLEARFORMAT}\\n\\n"
  3119. else
  3120. if [ "$autobwsfchoice" -eq 1 ]; then
  3121. updown="DOWN"
  3122. break
  3123. elif [ "$autobwsfchoice" -eq 2 ]; then
  3124. updown="UP"
  3125. break
  3126. fi
  3127. fi
  3128. fi
  3129. done
  3130. if [ "$exitmenu" != "exit" ]; then
  3131. while true; do
  3132. printf "\\n"
  3133. printf "Enter percentage to scale bandwidth by (1-100): "
  3134. read -r autobwsfvalue
  3135. if [ "$autobwsfvalue" = "e" ]; then
  3136. exitmenu="exit"
  3137. break
  3138. elif ! Validate_Number "$autobwsfvalue"; then
  3139. printf "\\n\\e[31mPlease enter a valid number (1-100)${CLEARFORMAT}\\n"
  3140. else
  3141. if [ "$autobwsfvalue" -lt 1 ] || [ "$autobwsfvalue" -gt 100 ]; then
  3142. printf "\\n\\e[31mPlease enter a number between 1 and 100${CLEARFORMAT}\\n"
  3143. else
  3144. sfvalue="$autobwsfvalue"
  3145. break
  3146. fi
  3147. fi
  3148. done
  3149. fi
  3150. if [ "$exitmenu" != "exit" ]; then
  3151. AutoBWConf update SF "$updown" "$sfvalue"
  3152. break
  3153. fi
  3154.  
  3155. if [ "$exitmenu" = "exit" ]; then
  3156. break
  3157. fi
  3158. done
  3159.  
  3160. printf "\\n"
  3161. PressEnter
  3162. ;;
  3163. 4)
  3164. while true; do
  3165. ScriptHeader
  3166. exitmenu=""
  3167. updown=""
  3168. limithighlow=""
  3169. limitvalue=""
  3170. printf "\\n"
  3171. printf "Select a bandwidth to set limit for\\n"
  3172. printf "1. Download\\n"
  3173. printf "2. Upload\\n\\n"
  3174. while true; do
  3175. printf "Choose an option: "
  3176. read -r autobwchoice
  3177. if [ "$autobwchoice" = "e" ]; then
  3178. exitmenu="exit"
  3179. break
  3180. elif ! Validate_Number "$autobwchoice"; then
  3181. printf "\\n\\e[31mPlease enter a valid number (1-2)${CLEARFORMAT}\\n\\n"
  3182. else
  3183. if [ "$autobwchoice" -lt 1 ] || [ "$autobwchoice" -gt 2 ]; then
  3184. printf "\\n\\e[31mPlease enter a number between 1 and 2${CLEARFORMAT}\\n\\n"
  3185. else
  3186. if [ "$autobwchoice" -eq 1 ]; then
  3187. updown="DOWN"
  3188. break
  3189. elif [ "$autobwchoice" -eq 2 ]; then
  3190. updown="UP"
  3191. break
  3192. fi
  3193. fi
  3194. fi
  3195. done
  3196. if [ "$exitmenu" != "exit" ]; then
  3197. while true; do
  3198. printf "\\n"
  3199. printf "Select a limit to set\\n"
  3200. printf "1. Upper\\n"
  3201. printf "2. Lower\\n\\n"
  3202. printf "Choose an option: "
  3203. read -r autobwlimit
  3204. if [ "$autobwlimit" = "e" ]; then
  3205. exitmenu="exit"
  3206. break
  3207. elif ! Validate_Number "$autobwlimit"; then
  3208. printf "\\n\\e[31mPlease enter a valid number (1-100)${CLEARFORMAT}\\n"
  3209. else
  3210. if [ "$autobwlimit" -lt 1 ] || [ "$autobwlimit" -gt 100 ]; then
  3211. printf "\\n\\e[31mPlease enter a number between 1 and 100${CLEARFORMAT}\\n"
  3212. else
  3213. if [ "$autobwlimit" -eq 1 ]; then
  3214. limithighlow="ULIMIT"
  3215. elif [ "$autobwlimit" -eq 2 ]; then
  3216. limithighlow="LLIMIT"
  3217. fi
  3218. fi
  3219. fi
  3220.  
  3221. if [ "$exitmenu" != "exit" ]; then
  3222. while true; do
  3223. printf "\\n"
  3224. printf "Enter value to set limit to (0 = unlimited for upper): "
  3225. read -r autobwlimvalue
  3226. if [ "$autobwlimvalue" = "e" ]; then
  3227. exitmenu="exit"
  3228. break
  3229. elif ! Validate_Number "$autobwlimvalue"; then
  3230. printf "\\n\\e[31mPlease enter a valid number (1-100)${CLEARFORMAT}\\n"
  3231. else
  3232. limitvalue="$autobwlimvalue"
  3233. break
  3234. fi
  3235. done
  3236. if [ "$exitmenu" != "exit" ]; then
  3237. AutoBWConf update "$limithighlow" "$updown" "$limitvalue"
  3238. exitmenu="exit"
  3239. break
  3240. fi
  3241. fi
  3242. done
  3243. if [ "$exitmenu" = "exit" ]; then
  3244. break
  3245. fi
  3246. fi
  3247. done
  3248.  
  3249. printf "\\n"
  3250. PressEnter
  3251. ;;
  3252. 5)
  3253. while true; do
  3254. ScriptHeader
  3255. exitmenu=""
  3256. updown=""
  3257. thvalue=""
  3258. printf "\\n"
  3259. printf "Select a threshold to set\\n"
  3260. printf "1. Download\\n"
  3261. printf "2. Upload\\n\\n"
  3262. while true; do
  3263. printf "Choose an option: "
  3264. read -r autobwthchoice
  3265. if [ "$autobwthchoice" = "e" ]; then
  3266. exitmenu="exit"
  3267. break
  3268. elif ! Validate_Number "$autobwthchoice"; then
  3269. printf "\\n\\e[31mPlease enter a valid number (1-2)${CLEARFORMAT}\\n\\n"
  3270. else
  3271. if [ "$autobwthchoice" -lt 1 ] || [ "$autobwthchoice" -gt 2 ]; then
  3272. printf "\\n\\e[31mPlease enter a number between 1 and 2${CLEARFORMAT}\\n\\n"
  3273. else
  3274. if [ "$autobwthchoice" -eq 1 ]; then
  3275. updown="DOWN"
  3276. break
  3277. elif [ "$autobwthchoice" -eq 2 ]; then
  3278. updown="UP"
  3279. break
  3280. fi
  3281. fi
  3282. fi
  3283. done
  3284.  
  3285. if [ "$exitmenu" != "exit" ]; then
  3286. while true; do
  3287. printf "\\n"
  3288. printf "Enter percentage to use for result threshold: "
  3289. read -r autobwthvalue
  3290. if [ "$autobwthvalue" = "e" ]; then
  3291. exitmenu="exit"
  3292. break
  3293. elif ! Validate_Number "$autobwthvalue"; then
  3294. printf "\\n\\e[31mPlease enter a valid number (0-100)${CLEARFORMAT}\\n"
  3295. else
  3296. if [ "$autobwthvalue" -lt 0 ] || [ "$autobwthvalue" -gt 100 ]; then
  3297. printf "\\n\\e[31mPlease enter a number between 0 and 100${CLEARFORMAT}\\n"
  3298. else
  3299. thvalue="$autobwthvalue"
  3300. break
  3301. fi
  3302. fi
  3303. done
  3304. fi
  3305.  
  3306. if [ "$exitmenu" != "exit" ]; then
  3307. AutoBWConf update THRESHOLD "$updown" "$thvalue"
  3308. break
  3309. fi
  3310.  
  3311. if [ "$exitmenu" = "exit" ]; then
  3312. break
  3313. fi
  3314. done
  3315.  
  3316. printf "\\n"
  3317. PressEnter
  3318. ;;
  3319. 6)
  3320. printf "\\n"
  3321. if [ "$(AutoBWEnable check)" = "true" ]; then
  3322. AutoBWEnable disable
  3323. elif [ "$(AutoBWEnable check)" = "false" ]; then
  3324. AutoBWEnable enable
  3325. if [ "$(ExcludeFromQoS check)" = "false" ]; then
  3326. Print_Output false "Enabling Exclude from QoS (required for AutoBW)"
  3327. ExcludeFromQoS enable
  3328. PressEnter
  3329. fi
  3330. fi
  3331. ;;
  3332. e)
  3333. break
  3334. ;;
  3335. esac
  3336. done
  3337. }
  3338.  
  3339. Menu_AutoBW_Update(){
  3340. if [ "$(nvram get qos_enable)" -eq 0 ]; then
  3341. Print_Output true "QoS is not enabled, please enable this in the Asus WebUI." "$ERR"
  3342. return 1
  3343. fi
  3344.  
  3345. dsf="$(AutoBWConf check SF DOWN | awk '{printf ($1/100)}')"
  3346. usf="$(AutoBWConf check SF UP | awk '{printf ($1/100)}')"
  3347.  
  3348. dlimitlow="$(($(AutoBWConf check LLIMIT DOWN)*1024))"
  3349. dlimithigh="$(($(AutoBWConf check ULIMIT DOWN)*1024))"
  3350. ulimitlow="$(($(AutoBWConf check LLIMIT UP)*1024))"
  3351. ulimithigh="$(($(AutoBWConf check ULIMIT UP)*1024))"
  3352. avgcalc="$(AutoBWConf check AVERAGE CALC)"
  3353.  
  3354. metriclist="Download Upload"
  3355.  
  3356. for metric in $metriclist; do
  3357. {
  3358. {
  3359. echo ".mode list"
  3360. echo ".headers off"
  3361. echo ".output /tmp/spdbw$metric"
  3362. echo "SELECT avg($metric) FROM (SELECT $metric FROM spdstats_WAN ORDER BY [Timestamp] DESC LIMIT $avgcalc);"
  3363. } > /tmp/spd-autobw.sql
  3364. "$SQLITE3_PATH" "$SCRIPT_STORAGE_DIR/spdstats.db" < /tmp/spd-autobw.sql
  3365. rm -f /tmp/spd-autobw.sql
  3366. }
  3367. done
  3368.  
  3369. autobwoutfile="$SCRIPT_STORAGE_DIR/.autobwoutfile"
  3370. TZ=$(cat /etc/TZ)
  3371. export TZ
  3372.  
  3373. printf "AutoBW report - %s\\n\\n" "$(date +"%c")" > "$autobwoutfile"
  3374.  
  3375. dspdkbps="$(echo "$(awk '{printf (1024*$1)}' /tmp/spdbwDownload)" "$dsf" | awk '{printf int($1*$2)}')"
  3376. uspdkbps="$(echo "$(awk '{printf (1024*$1)}' /tmp/spdbwUpload)" "$usf" | awk '{printf int($1*$2)}')"
  3377.  
  3378. rm -f /tmp/spdbwDownload
  3379. rm -f /tmp/spdbwUpload
  3380.  
  3381. if [ "$dspdkbps" -lt "$dlimitlow" ]; then
  3382. Print_Output true "Download speed ($dspdkbps Kbps) < lower limit ($dlimitlow Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3383. dspdkbps="$dlimitlow"
  3384. elif [ "$dspdkbps" -gt "$dlimithigh" ] && [ "$dlimithigh" -gt 0 ]; then
  3385. Print_Output true "Download speed ($dspdkbps Kbps) > upper limit ($dlimithigh Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3386. dspdkbps="$dlimithigh"
  3387. fi
  3388.  
  3389. if [ "$uspdkbps" -lt "$ulimitlow" ]; then
  3390. Print_Output true "Upload speed ($uspdkbps Kbps) < lower limit ($ulimitlow Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3391. uspdkbps="$ulimitlow"
  3392. elif [ "$uspdkbps" -gt "$ulimithigh" ] && [ "$ulimithigh" -gt 0 ]; then
  3393. Print_Output true "Upload speed ($uspdkbps Kbps) > upper limit ($ulimithigh Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3394. uspdkbps="$ulimithigh"
  3395. fi
  3396.  
  3397. old_uspdkbps="$(nvram get qos_obw)"
  3398. old_dspdkbps="$(nvram get qos_ibw)"
  3399.  
  3400. bw_changed="false"
  3401.  
  3402. dbw_threshold="$(AutoBWConf check THRESHOLD DOWN | awk '{printf ($1/100)}')"
  3403.  
  3404. if [ "$dspdkbps" -gt "$(echo "$old_dspdkbps" "$dbw_threshold" | awk '{printf int($1+$1*$2)}')" ] || [ "$dspdkbps" -lt "$(echo "$old_dspdkbps" "$dbw_threshold" | awk '{printf int($1-$1*$2)}')" ]; then
  3405. bw_changed="true"
  3406. nvram set qos_ibw="$(echo $dspdkbps | cut -d'.' -f1)"
  3407. Print_Output true "Setting QoS Download Speed to $dspdkbps Kbps (was $old_dspdkbps Kbps)" "$PASS" | tee -a "$autobwoutfile"
  3408. else
  3409. Print_Output true "Calculated Download speed ($dspdkbps Kbps) does not exceed $(AutoBWConf check THRESHOLD DOWN)% threshold of existing value ($old_dspdkbps Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3410. fi
  3411.  
  3412. ubw_threshold="$(AutoBWConf check THRESHOLD UP | awk '{printf ($1/100)}')"
  3413.  
  3414. if [ "$uspdkbps" -gt "$(echo "$old_uspdkbps" "$ubw_threshold" | awk '{printf int($1+$1*$2)}')" ] || [ "$uspdkbps" -lt "$(echo "$old_uspdkbps" "$ubw_threshold" | awk '{printf int($1-$1*$2)}')" ]; then
  3415. bw_changed="true"
  3416. nvram set qos_obw="$(echo $uspdkbps | cut -d'.' -f1)"
  3417. Print_Output true "Setting QoS Upload Speed to $uspdkbps Kbps (was $old_uspdkbps Kbps)" "$PASS" | tee -a "$autobwoutfile"
  3418. else
  3419. Print_Output true "Calculated Upload speed ($uspdkbps Kbps) does not exceed $(AutoBWConf check THRESHOLD UP)% threshold of existing value ($old_uspdkbps Kbps)" "$WARN" | tee -a "$autobwoutfile"
  3420. fi
  3421.  
  3422. if [ "$bw_changed" = "true" ]; then
  3423. nvram commit
  3424. service "restart_qos;restart_firewall" >/dev/null 2>&1
  3425. printf "AutoBW made changes to QoS bandwidth, QoS will be restarted" >> "$autobwoutfile"
  3426. else
  3427. printf "No changes made to QoS by AutoBW" >> "$autobwoutfile"
  3428. fi
  3429.  
  3430. sed -i 's/[^a-zA-Z0-9():%<>-]/ /g;s/ 1m//g;s/ 33m//g;s/ 0m//g' "$autobwoutfile"
  3431.  
  3432. Clear_Lock
  3433. }
  3434.  
  3435. Menu_Uninstall(){
  3436. if [ -n "$PPID" ]; then
  3437. ps | grep -v grep | grep -v $$ | grep -v "$PPID" | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
  3438. else
  3439. ps | grep -v grep | grep -v $$ | grep -i "$SCRIPT_NAME_LOWER" | grep generate | awk '{print $1}' | xargs kill -9 >/dev/null 2>&1
  3440. fi
  3441. PROC_NAME="speedtest"
  3442. if [ "$SPEEDTEST_BINARY" = /usr/sbin/ookla ]; then
  3443. PROC_NAME="ookla"
  3444. fi
  3445. if [ -n "$(pidof "$PROC_NAME")" ]; then
  3446. killall -q "$PROC_NAME"
  3447. fi
  3448. Print_Output true "Removing $SCRIPT_NAME..." "$PASS"
  3449. Auto_Startup delete 2>/dev/null
  3450. Auto_Cron delete 2>/dev/null
  3451. Auto_ServiceEvent delete 2>/dev/null
  3452.  
  3453. Get_WebUI_Page "$SCRIPT_DIR/spdstats_www.asp"
  3454. if [ -n "$MyPage" ] && [ "$MyPage" != "none" ] && [ -f "/tmp/menuTree.js" ]; then
  3455. sed -i "\\~$MyPage~d" /tmp/menuTree.js
  3456. umount /www/require/modules/menuTree.js
  3457. mount -o bind /tmp/menuTree.js /www/require/modules/menuTree.js
  3458. rm -f "$SCRIPT_WEBPAGE_DIR/$MyPage"
  3459. rm -f "$SCRIPT_WEBPAGE_DIR/$(echo $MyPage | cut -f1 -d'.').title"
  3460. fi
  3461.  
  3462. rm -f "$SCRIPT_DIR/spdstats_www.asp" 2>/dev/null
  3463.  
  3464. printf "\\n${BOLD}Do you want to delete %s stats and config? (y/n)${CLEARFORMAT} " "$SCRIPT_NAME"
  3465. read -r confirm
  3466. case "$confirm" in
  3467. y|Y)
  3468. rm -rf "$SCRIPT_DIR" 2>/dev/null
  3469. rm -rf "$SCRIPT_STORAGE_DIR" 2>/dev/null
  3470. ;;
  3471. *)
  3472. :
  3473. ;;
  3474. esac
  3475. Shortcut_Script delete
  3476.  
  3477. rm -rf "$SCRIPT_WEB_DIR" 2>/dev/null
  3478. rm -rf "$OOKLA_DIR" 2>/dev/null
  3479. rm -rf "$OOKLA_LICENSE_DIR" 2>/dev/null
  3480. rm -f "/jffs/scripts/$SCRIPT_NAME_LOWER" 2>/dev/null
  3481. Clear_Lock
  3482. Print_Output true "Uninstall completed" "$PASS"
  3483. }
  3484.  
  3485. NTP_Ready(){
  3486. if [ "$(nvram get ntp_ready)" -eq 0 ]; then
  3487. ntpwaitcount=0
  3488. Check_Lock
  3489. while [ "$(nvram get ntp_ready)" -eq 0 ] && [ "$ntpwaitcount" -lt 600 ]; do
  3490. ntpwaitcount="$((ntpwaitcount + 30))"
  3491. Print_Output true "Waiting for NTP to sync..." "$WARN"
  3492. sleep 30
  3493. done
  3494. if [ "$ntpwaitcount" -ge 600 ]; then
  3495. Print_Output true "NTP failed to sync after 10 minutes. Please resolve!" "$CRIT"
  3496. Clear_Lock
  3497. exit 1
  3498. else
  3499. Print_Output true "NTP synced, $SCRIPT_NAME will now continue" "$PASS"
  3500. Clear_Lock
  3501. fi
  3502. fi
  3503. }
  3504.  
  3505. ### function based on @Adamm00's Skynet USB wait function ###
  3506. Entware_Ready(){
  3507. if [ ! -f "/opt/bin/opkg" ]; then
  3508. Check_Lock
  3509. sleepcount=1
  3510. while [ ! -f /opt/bin/opkg ] && [ "$sleepcount" -le 10 ]; do
  3511. Print_Output true "Entware not found, sleeping for 10s (attempt $sleepcount of 10)" "$ERR"
  3512. sleepcount="$((sleepcount + 1))"
  3513. sleep 10
  3514. done
  3515. if [ ! -f /opt/bin/opkg ]; then
  3516. Print_Output true "Entware not found and is required for $SCRIPT_NAME to run, please resolve" "$CRIT"
  3517. Clear_Lock
  3518. exit 1
  3519. else
  3520. Print_Output true "Entware found, $SCRIPT_NAME will now continue" "$PASS"
  3521. Clear_Lock
  3522. fi
  3523. fi
  3524. }
  3525. ### ###
  3526.  
  3527. ### function based on @dave14305's FlexQoS about function ###
  3528. Show_About(){
  3529. cat <<EOF
  3530. About
  3531. $SCRIPT_NAME is an internet speedtest and monitoring tool for
  3532. AsusWRT Merlin with charts for daily, weekly and monthly summaries.
  3533. It tracks download/upload bandwidth as well as latency, jitter and
  3534. packet loss.
  3535. License
  3536. $SCRIPT_NAME is free to use under the GNU General Public License
  3537. version 3 (GPL-3.0) https://opensource.org/licenses/GPL-3.0
  3538. Help & Support
  3539. https://www.snbforums.com/forums/asuswrt-merlin-addons.60/?prefix_id=19
  3540. Source code
  3541. https://github.com/jackyaz/$SCRIPT_NAME
  3542. EOF
  3543. printf "\\n"
  3544. }
  3545. ### ###
  3546.  
  3547. ### function based on @dave14305's FlexQoS show_help function ###
  3548. Show_Help(){
  3549. cat <<EOF
  3550. Available commands:
  3551. $SCRIPT_NAME_LOWER about explains functionality
  3552. $SCRIPT_NAME_LOWER update checks for updates
  3553. $SCRIPT_NAME_LOWER forceupdate updates to latest version (force update)
  3554. $SCRIPT_NAME_LOWER startup force runs startup actions such as mount WebUI tab
  3555. $SCRIPT_NAME_LOWER install installs script
  3556. $SCRIPT_NAME_LOWER uninstall uninstalls script
  3557. $SCRIPT_NAME_LOWER generate run speedtest and save to database. also runs outputcsv
  3558. $SCRIPT_NAME_LOWER outputcsv create CSVs from database, used by WebUI and export
  3559. $SCRIPT_NAME_LOWER enable enable automatic speedtests
  3560. $SCRIPT_NAME_LOWER disable disable automatic speedtests
  3561. $SCRIPT_NAME_LOWER develop switch to development branch
  3562. $SCRIPT_NAME_LOWER stable switch to stable branch
  3563. EOF
  3564. printf "\\n"
  3565. }
  3566. ### ###
  3567.  
  3568. if [ -f "/opt/share/$SCRIPT_NAME_LOWER.d/config" ]; then
  3569. SCRIPT_CONF="/opt/share/$SCRIPT_NAME_LOWER.d/config"
  3570. SCRIPT_STORAGE_DIR="/opt/share/$SCRIPT_NAME_LOWER.d"
  3571. else
  3572. SCRIPT_CONF="/jffs/addons/$SCRIPT_NAME_LOWER.d/config"
  3573. SCRIPT_STORAGE_DIR="/jffs/addons/$SCRIPT_NAME_LOWER.d"
  3574. fi
  3575.  
  3576. SCRIPT_INTERFACES="$SCRIPT_STORAGE_DIR/.interfaces"
  3577. SCRIPT_INTERFACES_USER="$SCRIPT_STORAGE_DIR/.interfaces_user"
  3578. CSV_OUTPUT_DIR="$SCRIPT_STORAGE_DIR/csv"
  3579.  
  3580. if [ -z "$1" ]; then
  3581. NTP_Ready
  3582. Entware_Ready
  3583. if [ ! -f /opt/bin/sqlite3 ]; then
  3584. Print_Output true "Installing required version of sqlite3 from Entware" "$PASS"
  3585. opkg update
  3586. opkg install sqlite3-cli
  3587. fi
  3588.  
  3589. Create_Dirs
  3590. Conf_Exists
  3591. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  3592. printf "/usr/sbin/ookla" > /tmp/spdmerlin-binary
  3593. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  3594. printf "%s" "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
  3595. fi
  3596. ScriptStorageLocation load
  3597. Create_Symlinks
  3598.  
  3599. Process_Upgrade
  3600.  
  3601. Auto_Startup create 2>/dev/null
  3602. if AutomaticMode check; then Auto_Cron create 2>/dev/null; else Auto_Cron delete 2>/dev/null; fi
  3603. Auto_ServiceEvent create 2>/dev/null
  3604. Shortcut_Script create
  3605. ScriptHeader
  3606. MainMenu
  3607. exit 0
  3608. fi
  3609.  
  3610. case "$1" in
  3611. install)
  3612. Check_Lock
  3613. Menu_Install
  3614. exit 0
  3615. ;;
  3616. startup)
  3617. Menu_Startup "$2"
  3618. exit 0
  3619. ;;
  3620. generate)
  3621. NTP_Ready
  3622. Entware_Ready
  3623. Check_Lock
  3624. Run_Speedtest schedule
  3625. Clear_Lock
  3626. exit 0
  3627. ;;
  3628. service_event)
  3629. if [ "$2" = "start" ] && echo "$3" | grep -q "${SCRIPT_NAME_LOWER}spdtest"; then
  3630. rm -f /tmp/detect_spdtest.js
  3631. rm -f /tmp/spd-result.txt
  3632. rm -f /tmp/spd-stats.txt
  3633. Check_Lock webui
  3634. sleep 3
  3635. Run_Speedtest_WebUI "$3"
  3636. Clear_Lock
  3637. exit 0
  3638. elif [ "$2" = "start" ] && echo "$3" | grep -q "${SCRIPT_NAME_LOWER}serverlistmanual"; then
  3639. spdifacename="$(echo "$3" | sed "s/${SCRIPT_NAME_LOWER}serverlistmanual_//" | cut -f1 -d'_' | tr "a-z" "A-Z")";
  3640. GenerateServerList_WebUI "$spdifacename" "spdmerlin_manual_serverlist"
  3641. elif [ "$2" = "start" ] && echo "$3" | grep -q "${SCRIPT_NAME_LOWER}serverlist"; then
  3642. spdifacename="$(echo "$3" | sed "s/${SCRIPT_NAME_LOWER}serverlist_//" | cut -f1 -d'_' | tr "a-z" "A-Z")";
  3643. GenerateServerList_WebUI "$spdifacename" "spdmerlin_serverlist_$spdifacename"
  3644. elif [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME_LOWER}config" ]; then
  3645. Interfaces_FromSettings
  3646. Conf_FromSettings
  3647. exit 0
  3648. elif [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME_LOWER}checkupdate" ]; then
  3649. Update_Check
  3650. exit 0
  3651. elif [ "$2" = "start" ] && [ "$3" = "${SCRIPT_NAME_LOWER}doupdate" ]; then
  3652. Update_Version force unattended
  3653. exit 0
  3654. fi
  3655. exit 0
  3656. ;;
  3657. outputcsv)
  3658. NTP_Ready
  3659. Entware_Ready
  3660. Check_Lock
  3661. Generate_CSVs
  3662. Clear_Lock
  3663. exit 0
  3664. ;;
  3665. enable)
  3666. Entware_Ready
  3667. AutomaticMode enable
  3668. exit 0
  3669. ;;
  3670. disable)
  3671. Entware_Ready
  3672. AutomaticMode disable
  3673. exit 0
  3674. ;;
  3675. update)
  3676. Update_Version
  3677. exit 0
  3678. ;;
  3679. forceupdate)
  3680. Update_Version force
  3681. exit 0
  3682. ;;
  3683. postupdate)
  3684. Create_Dirs
  3685. Conf_Exists
  3686. if [ "$(SpeedtestBinary check)" = "builtin" ]; then
  3687. printf "/usr/sbin/ookla" > /tmp/spdmerlin-binary
  3688. elif [ "$(SpeedtestBinary check)" = "external" ]; then
  3689. printf "%s" "$OOKLA_DIR/speedtest" > /tmp/spdmerlin-binary
  3690. fi
  3691. ScriptStorageLocation load
  3692. Create_Symlinks
  3693. Process_Upgrade
  3694. Auto_Startup create 2>/dev/null
  3695. if AutomaticMode check; then Auto_Cron create 2>/dev/null; else Auto_Cron delete 2>/dev/null; fi
  3696. Auto_ServiceEvent create 2>/dev/null
  3697. Shortcut_Script create
  3698. Set_Version_Custom_Settings local "$SCRIPT_VERSION"
  3699. Set_Version_Custom_Settings server "$SCRIPT_VERSION"
  3700. ;;
  3701. checkupdate)
  3702. Update_Check
  3703. exit 0
  3704. ;;
  3705. uninstall)
  3706. Menu_Uninstall
  3707. exit 0
  3708. ;;
  3709. develop)
  3710. SCRIPT_BRANCH="develop"
  3711. SCRIPT_REPO="https://raw.githubusercontent.com/jackyaz/$SCRIPT_NAME/$SCRIPT_BRANCH"
  3712. Update_Version force
  3713. exit 0
  3714. ;;
  3715. stable)
  3716. SCRIPT_BRANCH="master"
  3717. SCRIPT_REPO="https://raw.githubusercontent.com/jackyaz/$SCRIPT_NAME/$SCRIPT_BRANCH"
  3718. Update_Version force
  3719. exit 0
  3720. ;;
  3721. about)
  3722. ScriptHeader
  3723. Show_About
  3724. exit 0
  3725. ;;
  3726. help)
  3727. ScriptHeader
  3728. Show_Help
  3729. exit 0
  3730. ;;
  3731. *)
  3732. ScriptHeader
  3733. Print_Output false "Command not recognised." "$ERR"
  3734. Print_Output false "For a list of available commands run: $SCRIPT_NAME_LOWER help"
  3735. exit 1
  3736. ;;
  3737. esac
  3738.  
Tags: SpdMerlin
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement