searx.sh 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck disable=SC2001
  5. # shellcheck source=utils/lib.sh
  6. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  7. source_dot_config
  8. # ----------------------------------------------------------------------------
  9. # config
  10. # ----------------------------------------------------------------------------
  11. SEARX_INTERNAL_URL="${SEARX_INTERNAL_URL:-127.0.0.1:8888}"
  12. SEARX_URL_PATH="${SEARX_URL_PATH:-$(echo "${PUBLIC_URL}" \
  13. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  14. [[ "${SEARX_URL_PATH}" == "${PUBLIC_URL}" ]] && SEARX_URL_PATH=/
  15. SEARX_INSTANCE_NAME="${SEARX_INSTANCE_NAME:-searx@$(echo "$PUBLIC_URL" \
  16. | sed -e 's,^.*://\([^\:/]*\).*,\1,g') }"
  17. SERVICE_NAME="searx"
  18. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  19. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  20. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  21. # shellcheck disable=SC2034
  22. SERVICE_GROUP="${SERVICE_USER}"
  23. SEARX_GIT_URL="${SEARX_GIT_URL:-https://github.com/asciimoo/searx.git}"
  24. SEARX_GIT_BRANCH="${SEARX_GIT_BRANCH:-master}"
  25. SEARX_PYENV="${SERVICE_HOME}/searx-pyenv"
  26. SEARX_SRC="${SERVICE_HOME}/searx-src"
  27. SEARX_SETTINGS_PATH="/etc/searx/settings.yml"
  28. SEARX_UWSGI_APP="searx.ini"
  29. # shellcheck disable=SC2034
  30. SEARX_UWSGI_SOCKET="/run/uwsgi/app/searx/socket"
  31. # FIXME: Arch Linux & RHEL should be added
  32. SEARX_APT_PACKAGES="\
  33. uwsgi uwsgi-plugin-python3 \
  34. git build-essential \
  35. libxslt-dev python3-dev python3-babel python3-venv \
  36. zlib1g-dev libffi-dev libssl-dev \
  37. "
  38. # Apache Settings
  39. APACHE_APT_PACKAGES="\
  40. libapache2-mod-uwsgi \
  41. "
  42. APACHE_SEARX_SITE="searx.conf"
  43. # shellcheck disable=SC2034
  44. CONFIG_FILES=(
  45. "${uWSGI_SETUP}/apps-available/${SEARX_UWSGI_APP}"
  46. )
  47. # shellcheck disable=SC2034
  48. CONFIG_BACKUP_ENCRYPTED=(
  49. "${SEARX_SETTINGS_PATH}"
  50. )
  51. # ----------------------------------------------------------------------------
  52. usage() {
  53. # ----------------------------------------------------------------------------
  54. # shellcheck disable=SC1117
  55. cat <<EOF
  56. usage::
  57. $(basename "$0") shell
  58. $(basename "$0") install [all|user|pyenv|searx-src|apache]
  59. $(basename "$0") update [searx]
  60. $(basename "$0") remove [all|user|pyenv|searx-src]
  61. $(basename "$0") activate [service]
  62. $(basename "$0") deactivate [service]
  63. $(basename "$0") inspect [service]
  64. $(basename "$0") option [debug-on|debug-off]
  65. $(basename "$0") apache [install|remove]
  66. shell
  67. start interactive shell from user ${SERVICE_USER}
  68. install / remove
  69. :all: complete (de-) installation of searx service
  70. :user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  71. :searx-src: clone $SEARX_GIT_URL
  72. :pyenv: create/remove virtualenv (python) in $SEARX_PYENV
  73. :settings: reinstall settings from ${REPO_ROOT}/searx/settings.yml
  74. update searx
  75. Update searx installation ($SERVICE_HOME)
  76. activate service
  77. activate and start service daemon (systemd unit)
  78. deactivate service
  79. stop and deactivate service daemon (systemd unit)
  80. inspect service
  81. run some small tests and inspect service's status and log
  82. option
  83. set one of the available options
  84. apache
  85. :install: apache site with the searx uwsgi app
  86. :remove: apache site ${APACHE_FILTRON_SITE}
  87. searx settings: ${SEARX_SETTINGS_PATH}
  88. If needed, set PUBLIC_URL of your WEB service in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
  89. PUBLIC_URL : ${PUBLIC_URL}
  90. PUBLIC_HOST : ${PUBLIC_HOST}
  91. SEARX_INSTANCE_NAME : ${SEARX_INSTANCE_NAME}
  92. SERVICE_USER : ${SERVICE_USER}
  93. EOF
  94. [[ -n ${1} ]] && err_msg "$1"
  95. }
  96. main() {
  97. rst_title "$SEARX_INSTANCE_NAME" part
  98. required_commands \
  99. dpkg systemctl apt-get install git wget curl \
  100. || exit
  101. local _usage="unknown or missing $1 command $2"
  102. case $1 in
  103. --source-only) ;;
  104. -h|--help) usage; exit 0;;
  105. shell)
  106. sudo_or_exit
  107. interactive_shell "${SERVICE_USER}"
  108. ;;
  109. inspect)
  110. case $2 in
  111. service)
  112. sudo_or_exit
  113. inspect_service
  114. ;;
  115. *) usage "$_usage"; exit 42;;
  116. esac ;;
  117. install)
  118. sudo_or_exit
  119. case $2 in
  120. all) install_all ;;
  121. user) assert_user ;;
  122. pyenv) create_pyenv ;;
  123. searx-src) clone_searx ;;
  124. settings) install_settings ;;
  125. *) usage "$_usage"; exit 42;;
  126. esac ;;
  127. update)
  128. sudo_or_exit
  129. case $2 in
  130. searx) update_searx;;
  131. *) usage "$_usage"; exit 42;;
  132. esac ;;
  133. remove)
  134. sudo_or_exit
  135. case $2 in
  136. all) remove_all;;
  137. user) drop_service_account "${SERVICE_USER}";;
  138. pyenv) remove_pyenv ;;
  139. searx-src) remove_searx ;;
  140. *) usage "$_usage"; exit 42;;
  141. esac ;;
  142. activate)
  143. sudo_or_exit
  144. case $2 in
  145. service)
  146. activate_service ;;
  147. *) usage "$_usage"; exit 42;;
  148. esac ;;
  149. deactivate)
  150. sudo_or_exit
  151. case $2 in
  152. service) deactivate_service ;;
  153. *) usage "$_usage"; exit 42;;
  154. esac ;;
  155. option)
  156. sudo_or_exit
  157. case $2 in
  158. debug-on) echo; enable_debug ;;
  159. debug-off) echo; disable_debug ;;
  160. *) usage "$_usage"; exit 42;;
  161. esac ;;
  162. apache)
  163. sudo_or_exit
  164. case $2 in
  165. install) install_apache_site ;;
  166. remove) remove_apache_site ;;
  167. *) usage "$_usage"; exit 42;;
  168. esac ;;
  169. *) usage "unknown or missing command $1"; exit 42;;
  170. esac
  171. }
  172. _service_prefix=" |$SERVICE_USER| "
  173. install_all() {
  174. rst_title "Install $SEARX_INSTANCE_NAME (service)"
  175. pkg_install "$SEARX_APT_PACKAGES"
  176. wait_key
  177. assert_user
  178. wait_key
  179. clone_searx
  180. wait_key
  181. create_pyenv
  182. wait_key
  183. install_settings
  184. wait_key
  185. test_local_searx
  186. wait_key
  187. install_searx_uwsgi
  188. if ! service_is_available "http://$SEARX_INTERNAL_URL"; then
  189. err_msg "URL http://$SEARX_INTERNAL_URL not available, check searx & uwsgi setup!"
  190. fi
  191. if ask_yn "Do you want to inspect the installation?" Yn; then
  192. inspect_service
  193. fi
  194. }
  195. update_searx() {
  196. rst_title "Update searx instance"
  197. echo
  198. tee_stderr 0.3 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  199. cd ${SEARX_SRC}
  200. git checkout -B "$SEARX_GIT_BRANCH"
  201. git pull
  202. ${SEARX_SRC}/manage.sh update_packages
  203. EOF
  204. install_settings
  205. uWSGI_restart
  206. }
  207. remove_all() {
  208. rst_title "De-Install $SEARX_INSTANCE_NAME (service)"
  209. rst_para "\
  210. It goes without saying that this script can only be used to remove
  211. installations that were installed with this script."
  212. if ! ask_yn "Do you really want to deinstall $SEARX_INSTANCE_NAME?"; then
  213. return
  214. fi
  215. remove_searx_uwsgi
  216. drop_service_account "${SERVICE_USER}"
  217. remove_settings
  218. wait_key
  219. if service_is_available "${PUBLIC_URL}"; then
  220. MSG="** Don't forgett to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  221. fi
  222. }
  223. assert_user() {
  224. rst_title "user $SERVICE_USER" section
  225. echo
  226. tee_stderr 1 <<EOF | bash | prefix_stdout
  227. sudo -H adduser --shell /bin/bash --system --home "$SERVICE_HOME" \
  228. --disabled-password --group --gecos 'searx' $SERVICE_USER
  229. sudo -H usermod -a -G shadow $SERVICE_USER
  230. groups $SERVICE_USER
  231. EOF
  232. #SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  233. #export SERVICE_HOME
  234. #echo "export SERVICE_HOME=$SERVICE_HOME"
  235. }
  236. clone_is_available() {
  237. [[ -f "$SEARX_SRC/.git/config" ]]
  238. }
  239. # shellcheck disable=SC2164
  240. clone_searx() {
  241. rst_title "Clone searx sources" section
  242. echo
  243. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME 2>/dev/null)"
  244. if [[ ! "${SERVICE_HOME}" ]]; then
  245. err_msg "to clone searx sources, user $SERVICE_USER hast to be created first"
  246. return 42
  247. fi
  248. export SERVICE_HOME
  249. git_clone "$REPO_ROOT" "$SEARX_SRC" \
  250. "$SEARX_GIT_BRANCH" "$SERVICE_USER"
  251. pushd "${SEARX_SRC}" > /dev/null
  252. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  253. cd "${SEARX_SRC}"
  254. git remote set-url origin ${SEARX_GIT_URL}
  255. git config user.email "$ADMIN_EMAIL"
  256. git config user.name "$ADMIN_NAME"
  257. git config --list
  258. EOF
  259. popd > /dev/null
  260. }
  261. install_settings() {
  262. rst_title "${SEARX_SETTINGS_PATH}" section
  263. if ! clone_is_available; then
  264. err_msg "you have to install searx first"
  265. exit 42
  266. fi
  267. mkdir -p "$(dirname ${SEARX_SETTINGS_PATH})"
  268. if [[ ! -f ${SEARX_SETTINGS_PATH} ]]; then
  269. info_msg "install settings ${REPO_ROOT}/searx/settings.yml"
  270. info_msg " --> ${SEARX_SETTINGS_PATH}"
  271. cp "${REPO_ROOT}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
  272. configure_searx
  273. return
  274. fi
  275. rst_para "Diff between origin's setting file (-) and current (+):"
  276. echo
  277. $DIFF_CMD "${SEARX_SRC}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
  278. local action
  279. choose_one action "What should happen to the settings file? " \
  280. "keep new configuration" \
  281. "start interactiv shell"
  282. case $action in
  283. "keep new configuration")
  284. info_msg "continue using new settings file"
  285. ;;
  286. "start interactiv shell")
  287. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  288. sudo -H -i
  289. rst_para 'Diff between new setting file (-) and current (+):'
  290. echo
  291. $DIFF_CMD "${SEARX_SRC}/searx/settings.yml" "${SEARX_SETTINGS_PATH}"
  292. wait_key
  293. ;;
  294. esac
  295. }
  296. remove_settings() {
  297. rst_title "remove searx settings" section
  298. echo
  299. info_msg "delete ${SEARX_SETTINGS_PATH}"
  300. rm -f "${SEARX_SETTINGS_PATH}"
  301. }
  302. remove_searx() {
  303. rst_title "Drop searx sources" section
  304. if ask_yn "Do you really want to drop searx sources ($SEARX_SRC)?"; then
  305. rm -rf "$SEARX_SRC"
  306. else
  307. rst_para "Leave searx sources unchanged."
  308. fi
  309. }
  310. pyenv_is_available() {
  311. [[ -f "${SEARX_PYENV}/bin/activate" ]]
  312. }
  313. create_pyenv() {
  314. rst_title "Create virtualenv (python)" section
  315. echo
  316. if [[ ! -f "${SEARX_SRC}/manage.sh" ]]; then
  317. err_msg "to create pyenv for searx, searx has to be cloned first"
  318. return 42
  319. fi
  320. info_msg "create pyenv in ${SEARX_PYENV}"
  321. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  322. rm -rf "${SEARX_PYENV}"
  323. python3 -m venv "${SEARX_PYENV}"
  324. grep -qFs -- 'source ${SEARX_PYENV}/bin/activate' ~/.profile \
  325. || echo 'source ${SEARX_PYENV}/bin/activate' >> ~/.profile
  326. EOF
  327. info_msg "inspect python's virtual environment"
  328. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  329. command -v python && python --version
  330. EOF
  331. wait_key
  332. info_msg "install needed python packages"
  333. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  334. ${SEARX_SRC}/manage.sh update_packages
  335. EOF
  336. }
  337. remove_pyenv() {
  338. rst_title "Remove virtualenv (python)" section
  339. if ! ask_yn "Do you really want to drop ${SEARX_PYENV} ?"; then
  340. return
  341. fi
  342. info_msg "remove pyenv activation from ~/.profile"
  343. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  344. grep -v 'source ${SEARX_PYENV}/bin/activate' ~/.profile > ~/.profile.##
  345. mv ~/.profile.## ~/.profile
  346. EOF
  347. rm -rf "${SEARX_PYENV}"
  348. }
  349. configure_searx() {
  350. rst_title "Configure searx" section
  351. rst_para "Setup searx config located at $SEARX_SETTINGS_PATH"
  352. echo
  353. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  354. cd ${SEARX_SRC}
  355. sed -i -e "s/ultrasecretkey/$(openssl rand -hex 16)/g" "$SEARX_SETTINGS_PATH"
  356. sed -i -e "s/{instance_name}/${SEARX_INSTANCE_NAME}/g" "$SEARX_SETTINGS_PATH"
  357. EOF
  358. }
  359. test_local_searx() {
  360. rst_title "Testing searx instance localy" section
  361. echo
  362. if service_is_available "http://$SEARX_INTERNAL_URL" &>/dev/null; then
  363. err_msg "URL/port http://$SEARX_INTERNAL_URL is already in use, you"
  364. err_msg "should stop that service before starting local tests!"
  365. if ! ask_yn "Continue with local tests?"; then
  366. return
  367. fi
  368. fi
  369. sed -i -e "s/debug : False/debug : True/g" "$SEARX_SETTINGS_PATH"
  370. tee_stderr 0.1 <<EOF | sudo -H -u "${SERVICE_USER}" -i 2>&1 | prefix_stdout "$_service_prefix"
  371. export SEARX_SETTINGS_PATH="${SEARX_SETTINGS_PATH}"
  372. cd ${SEARX_SRC}
  373. timeout 10 python3 searx/webapp.py &
  374. sleep 3
  375. curl --location --verbose --head --insecure $SEARX_INTERNAL_URL
  376. EOF
  377. sed -i -e "s/debug : True/debug : False/g" "$SEARX_SETTINGS_PATH"
  378. }
  379. install_searx_uwsgi() {
  380. rst_title "Install searx's uWSGI app (searx.ini)" section
  381. echo
  382. uWSGI_install_app "$SEARX_UWSGI_APP"
  383. }
  384. remove_searx_uwsgi() {
  385. rst_title "Remove searx's uWSGI app (searx.ini)" section
  386. echo
  387. uWSGI_remove_app "$SEARX_UWSGI_APP"
  388. }
  389. activate_service() {
  390. rst_title "Activate $SEARX_INSTANCE_NAME (service)" section
  391. echo
  392. uWSGI_enable_app "$SEARX_UWSGI_APP"
  393. uWSGI_restart
  394. }
  395. deactivate_service() {
  396. rst_title "De-Activate $SEARX_INSTANCE_NAME (service)" section
  397. echo
  398. uWSGI_disable_app "$SEARX_UWSGI_APP"
  399. uWSGI_restart
  400. }
  401. enable_debug() {
  402. warn_msg "Do not enable debug in production enviroments!!"
  403. info_msg "try to enable debug mode ..."
  404. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  405. cd ${SEARX_SRC}
  406. sed -i -e "s/debug : False/debug : True/g" "$SEARX_SETTINGS_PATH"
  407. EOF
  408. uWSGI_restart
  409. }
  410. disable_debug() {
  411. info_msg "try to disable debug mode ..."
  412. tee_stderr 0.1 <<EOF | sudo -H -i 2>&1 | prefix_stdout "$_service_prefix"
  413. cd ${SEARX_SRC}
  414. sed -i -e "s/debug : True/debug : False/g" "$SEARX_SETTINGS_PATH"
  415. EOF
  416. uWSGI_restart
  417. }
  418. inspect_service() {
  419. rst_title "service status & log"
  420. cat <<EOF
  421. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  422. PUBLIC_URL : ${PUBLIC_URL}
  423. PUBLIC_HOST : ${PUBLIC_HOST}
  424. SEARX_URL_PATH : ${SEARX_URL_PATH}
  425. SEARX_INSTANCE_NAME : ${SEARX_INSTANCE_NAME}
  426. SEARX_INTERNAL_URL : ${SEARX_INTERNAL_URL}
  427. EOF
  428. apache_is_installed && info_msg "Apache is installed."
  429. if service_account_is_available "$SERVICE_USER"; then
  430. info_msg "Service account $SERVICE_USER exists."
  431. else
  432. err_msg "Service account $SERVICE_USER does not exists!"
  433. fi
  434. if pyenv_is_available; then
  435. info_msg "~$SERVICE_USER: python environment is available."
  436. else
  437. err_msg "~$SERVICE_USER: python environment is not available!"
  438. fi
  439. if clone_is_available; then
  440. info_msg "~$SERVICE_USER: Searx software is installed."
  441. else
  442. err_msg "~$SERVICE_USER: Missing searx software!"
  443. fi
  444. if uWSGI_app_enabled "$SEARX_UWSGI_APP"; then
  445. info_msg "uWSGI app $SEARX_UWSGI_APP is enabled."
  446. else
  447. err_msg "uWSGI app $SEARX_UWSGI_APP not enabled!"
  448. fi
  449. uWSGI_app_available "$SEARX_UWSGI_APP" \
  450. || err_msg "uWSGI app $SEARX_UWSGI_APP not available!"
  451. if ! service_is_available "http://${SEARX_INTERNAL_URL}"; then
  452. err_msg "uWSGI app (service) at http://${SEARX_INTERNAL_URL} is not available!"
  453. echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
  454. wait_key
  455. fi
  456. if ! service_is_available "${PUBLIC_URL}"; then
  457. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  458. fi
  459. local _debug_on
  460. if ask_yn "Enable searx debug mode?"; then
  461. enable_debug
  462. _debug_on=1
  463. fi
  464. echo
  465. systemctl --no-pager -l status "${SERVICE_NAME}"
  466. echo
  467. info_msg "public URL --> ${PUBLIC_URL}"
  468. info_msg "internal URL --> http://${SEARX_INTERNAL_URL}"
  469. # shellcheck disable=SC2059
  470. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  471. read -r -s -n1 -t 2
  472. echo
  473. while true; do
  474. trap break 2
  475. #journalctl -f -u "${SERVICE_NAME}"
  476. tail -f /var/log/uwsgi/app/searx.log
  477. done
  478. if [[ $_debug_on == 1 ]]; then
  479. disable_debug
  480. fi
  481. return 0
  482. }
  483. install_apache_site() {
  484. rst_title "Install Apache site $APACHE_SEARX_SITE"
  485. rst_para "\
  486. This installs the searx uwsgi app as apache site. If your server ist public to
  487. the internet you should instead use a reverse proxy (filtron) to block
  488. excessively bot queries."
  489. ! apache_is_installed && err_msg "Apache is not installed."
  490. if ! ask_yn "Do you really want to install apache site for searx-uwsgi?"; then
  491. return
  492. fi
  493. pkg_install "$APACHE_APT_PACKAGES"
  494. a2enmod uwsgi
  495. echo
  496. apache_install_site --variant=uwsgi "${APACHE_SEARX_SITE}"
  497. if ! service_is_available "${PUBLIC_URL}"; then
  498. err_msg "Public service at ${PUBLIC_URL} is not available!"
  499. fi
  500. }
  501. remove_apache_site() {
  502. rst_title "Remove Apache site ${APACHE_SEARX_SITE}"
  503. rst_para "\
  504. This removes apache site ${APACHE_SEARX_SITE}."
  505. ! apache_is_installed && err_msg "Apache is not installed."
  506. if ! ask_yn "Do you really want to continue?"; then
  507. return
  508. fi
  509. apache_remove_site "${APACHE_SEARX_SITE}"
  510. }
  511. # ----------------------------------------------------------------------------
  512. main "$@"
  513. # ----------------------------------------------------------------------------