freedombone-utils-selector 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. #!/bin/bash
  2. # _____ _ _
  3. # | __|___ ___ ___ _| |___ _____| |_ ___ ___ ___
  4. # | __| _| -_| -_| . | . | | . | . | | -_|
  5. # |__| |_| |___|___|___|___|_|_|_|___|___|_|_|___|
  6. #
  7. # Freedom in the Cloud
  8. #
  9. # Functions for selecting which apps to install or remove
  10. #
  11. # License
  12. # =======
  13. #
  14. # Copyright (C) 2015-2018 Bob Mottram <bob@freedombone.net>
  15. #
  16. # This program is free software: you can redistribute it and/or modify
  17. # it under the terms of the GNU Affero General Public License as published by
  18. # the Free Software Foundation, either version 3 of the License, or
  19. # (at your option) any later version.
  20. #
  21. # This program is distributed in the hope that it will be useful,
  22. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. # GNU Affero General Public License for more details.
  25. #
  26. # You should have received a copy of the GNU Affero General Public License
  27. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  28. # Array containing names of available apps
  29. APPS_AVAILABLE=()
  30. # Array containing 1 or 0 indicating installed apps
  31. APPS_INSTALLED=()
  32. # Apps selected with checklist
  33. APPS_CHOSEN=()
  34. # A list of the names of installed apps
  35. APPS_INSTALLED_NAMES=()
  36. # file containing a list of removed apps
  37. REMOVED_APPS_FILE=/root/removed
  38. INSTALLED_APPS_LIST=/usr/share/${PROJECT_NAME}/installed.txt
  39. # keep a list of which users have been added to which apps
  40. # so that when a new app is added existing users can be added
  41. APP_USERS_FILE=$HOME/app_users.txt
  42. if [ ! "$COMPLETION_FILE" ]; then
  43. COMPLETION_FILE="$HOME/${PROJECT_NAME}-completed.txt"
  44. fi
  45. # Loads variables defined at the beginning of an app script
  46. function app_load_variables {
  47. app_name=$1
  48. config_var_name=${app_name}_variables
  49. # shellcheck disable=SC2086
  50. if [ ! ${!config_var_name} ]; then
  51. echo $"${app_name}_variables was not found"
  52. return
  53. fi
  54. #shellcheck disable=SC1087,SC2125,SC2178
  55. configvarname=$config_var_name[@]
  56. #shellcheck disable=SC2206
  57. configvarname=( ${!configvarname} )
  58. # shellcheck disable=SC2068
  59. for v in ${configvarname[@]}
  60. do
  61. read_config_param "$v"
  62. done
  63. }
  64. # Saves variables for a given app script
  65. function app_save_variables {
  66. app_name=$1
  67. config_var_name=${app_name}_variables
  68. #shellcheck disable=SC2086
  69. if [ ! ${!config_var_name} ]; then
  70. return
  71. fi
  72. #shellcheck disable=SC1087,SC2125,SC2178
  73. configvarname=$config_var_name[@]
  74. #shellcheck disable=SC2206
  75. configvarname=( ${!configvarname} )
  76. # shellcheck disable=SC2068
  77. for v in ${configvarname[@]}
  78. do
  79. write_config_param "$v" "${!v}"
  80. done
  81. }
  82. # gets the variants list from an app script
  83. function app_variants {
  84. filename=$1
  85. variants_line=$(grep 'VARIANTS=' "${filename}")
  86. if [[ "$variants_line" == *"'"* ]]; then
  87. variants_list=$(echo "$variants_line" | awk -F '=' '{print $2}' | awk -F "'" '{print $2}')
  88. else
  89. variants_list=$(echo "$variants_line" | awk -F '=' '{print $2}' | awk -F '"' '{print $2}')
  90. fi
  91. echo "$variants_list"
  92. }
  93. # whether a given item is in an array
  94. function item_in_array {
  95. local e
  96. for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
  97. return 1
  98. }
  99. # returns a list of available system variants
  100. # based upon the variants string in each app script
  101. function available_system_variants {
  102. function_check item_in_array
  103. FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  104. new_available_variants_list=()
  105. for filename in $FILES
  106. do
  107. system_variants_list=$(app_variants "$filename")
  108. # shellcheck disable=SC2206
  109. variants_array=($system_variants_list)
  110. # shellcheck disable=SC2068
  111. for variant_str in ${variants_array[@]}
  112. do
  113. if ! item_in_array "${variant_str}" ${new_available_variants_list[@]}; then
  114. new_available_variants_list+=("$variant_str")
  115. fi
  116. done
  117. done
  118. # shellcheck disable=SC2207
  119. available_variants_list=($(sort <<<"${new_available_variants_list[*]}"))
  120. }
  121. function is_valid_variant {
  122. sys_type="$1"
  123. available_variants_list=()
  124. function_check available_system_variants
  125. available_system_variants
  126. # shellcheck disable=SC2068
  127. for variant_str in ${available_variants_list[@]}
  128. do
  129. if [[ "$sys_type" == "$variant_str" ]]; then
  130. return "1"
  131. fi
  132. done
  133. return "0"
  134. }
  135. function show_available_variants {
  136. available_variants_list=()
  137. function_check available_system_variants
  138. available_system_variants
  139. # shellcheck disable=SC2068
  140. for variant_str in ${available_variants_list[@]}
  141. do
  142. echo " $variant_str"
  143. done
  144. }
  145. # mark a given app as having been removed so that it doesn't get reinstalled on updates
  146. function remove_app {
  147. app_name=$1
  148. if [ ! -f $REMOVED_APPS_FILE ]; then
  149. touch $REMOVED_APPS_FILE
  150. fi
  151. if ! grep -Fxq "_${app_name}_" $REMOVED_APPS_FILE; then
  152. echo "_${app_name}_" >> $REMOVED_APPS_FILE
  153. fi
  154. if grep -Fxq "install_${app_name}" "$COMPLETION_FILE"; then
  155. sed -i "/install_${app_name}/d" "$COMPLETION_FILE"
  156. fi
  157. if grep -Fxq "install_${app_name}" "$INSTALLED_APPS_LIST"; then
  158. sed -i "/install_${app_name}/d" "$INSTALLED_APPS_LIST"
  159. fi
  160. }
  161. # returns 1 if an app has been marked as removed
  162. function app_is_removed {
  163. app_name="$1"
  164. if [ ! -f $REMOVED_APPS_FILE ]; then
  165. echo "0"
  166. return
  167. fi
  168. if ! grep -Fxq "_${app_name}_" $REMOVED_APPS_FILE; then
  169. echo "0"
  170. else
  171. echo "1"
  172. fi
  173. }
  174. # Allows an app to be reinstalled even if it was previously marked as being removed
  175. function reinstall_app {
  176. app_name=$1
  177. if [ ! -f $REMOVED_APPS_FILE ]; then
  178. return
  179. fi
  180. if [[ $(app_is_removed "$app_name") == "1" ]]; then
  181. sed -i "/_${app_name}_/d" $REMOVED_APPS_FILE
  182. fi
  183. }
  184. # returns 1 if an app is installed
  185. function app_is_installed {
  186. app_name="$1"
  187. # Why does this secondary file exist, apart from COMPLETION_FILE ?
  188. # It's so that it is visible to unprivileged users from the user control panel
  189. if [ -f "$INSTALLED_APPS_LIST" ]; then
  190. if ! grep -Fxq "install_${app_name}" "$INSTALLED_APPS_LIST"; then
  191. echo "0"
  192. else
  193. echo "1"
  194. fi
  195. return
  196. fi
  197. # check the completion file to see if it was installed
  198. if [ ! -f "$COMPLETION_FILE" ]; then
  199. echo "0"
  200. return
  201. fi
  202. if ! grep -Fxq "install_${app_name}" "$COMPLETION_FILE"; then
  203. echo "0"
  204. else
  205. echo "1"
  206. fi
  207. }
  208. # called at the end of the install section of an app script
  209. function install_completed {
  210. if [ ! "${1}" ]; then
  211. exit 673935
  212. fi
  213. if ! grep -Fxq "install_${1}" "$COMPLETION_FILE"; then
  214. echo "install_${1}" >> "$COMPLETION_FILE"
  215. fi
  216. }
  217. # populates an array of "0" or "1" for whether apps are installed
  218. function get_apps_installed {
  219. # shellcheck disable=SC2068
  220. for a in ${APPS_AVAILABLE[@]}
  221. do
  222. APPS_INSTALLED+=("$(app_is_installed "$a")")
  223. done
  224. }
  225. # populates an array of installed app names
  226. function get_apps_installed_names {
  227. APPS_INSTALLED_NAMES=()
  228. # shellcheck disable=SC2068
  229. for a in ${APPS_AVAILABLE[@]}
  230. do
  231. if [[ $(app_is_installed "$a") == "1" ]]; then
  232. APPS_INSTALLED_NAMES+=("$a")
  233. fi
  234. done
  235. }
  236. function app_not_on_onion_only {
  237. app_name="$1"
  238. read_config_param ONION_ONLY
  239. if [[ "$ONION_ONLY" != 'no' ]]; then
  240. if grep -q "NOT_ON_ONION=1" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
  241. echo "0"
  242. return
  243. fi
  244. fi
  245. echo "1"
  246. }
  247. function enough_ram_for_app {
  248. app_name="$1"
  249. if ! grep -q "MINIMUM_RAM_MB=" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}"; then
  250. echo "0"
  251. return
  252. fi
  253. minimum_ram_MB=$(grep "MINIMUM_RAM_MB=" "/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-${app_name}" | head -n 1 | awk -F '=' '{print $2}')
  254. minimum_ram_bytes=$((minimum_ram_MB * 1024))
  255. ram_available=$(grep MemTotal /proc/meminfo | awk '{print $2}')
  256. if [ "$ram_available" -lt "$minimum_ram_bytes" ]; then
  257. echo "1"
  258. return
  259. fi
  260. echo "0"
  261. }
  262. # detects what apps are available
  263. function detect_apps {
  264. FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  265. function_check item_in_array
  266. APPS_AVAILABLE=()
  267. APPS_CHOSEN=()
  268. # for all the app scripts
  269. for filename in $FILES
  270. do
  271. app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')
  272. if [[ $(enough_ram_for_app "$app_name") == "0" ]]; then
  273. if [[ $(app_not_on_onion_only "$app_name") != "0" ]]; then
  274. # shellcheck disable=SC2068
  275. if ! item_in_array "${app_name}" ${APPS_AVAILABLE[@]}; then
  276. APPS_AVAILABLE+=("${app_name}")
  277. APPS_CHOSEN+=("0")
  278. fi
  279. fi
  280. fi
  281. done
  282. function_check get_apps_installed
  283. get_apps_installed
  284. get_apps_installed_names
  285. }
  286. # detects what apps are available and can be installed
  287. # If the variants list within an app script is an empty string then
  288. # it is considered to be too experimental to be installable
  289. function detect_installable_apps {
  290. FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  291. APPS_AVAILABLE=()
  292. APPS_CHOSEN=()
  293. APPS_INSTALLED=()
  294. APPS_INSTALLED_NAMES=()
  295. function_check app_variants
  296. function_check app_is_installed
  297. function_check item_in_array
  298. # for all the app scripts
  299. for filename in $FILES
  300. do
  301. app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')
  302. if [[ $(enough_ram_for_app "$app_name") == "0" ]]; then
  303. if [[ $(app_not_on_onion_only "$app_name") != "0" ]]; then
  304. # shellcheck disable=SC2068
  305. if ! item_in_array "${app_name}" ${APPS_AVAILABLE[@]}; then
  306. variants_list=$(app_variants "$filename")
  307. # check for empty string
  308. if [ ${#variants_list} -gt 0 ]; then
  309. APPS_AVAILABLE+=("${app_name}")
  310. APPS_CHOSEN+=("0")
  311. APPS_INSTALLED+=("$(app_is_installed "$app_name")")
  312. if [[ $(app_is_installed "$app_name") == "1" ]]; then
  313. APPS_INSTALLED_NAMES+=("$app_name")
  314. fi
  315. fi
  316. fi
  317. fi
  318. fi
  319. done
  320. }
  321. function detect_installed_apps {
  322. FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  323. APPS_AVAILABLE=()
  324. APPS_INSTALLED=()
  325. APPS_INSTALLED_NAMES=()
  326. function_check app_variants
  327. function_check app_is_installed
  328. function_check item_in_array
  329. # for all the app scripts
  330. for filename in $FILES
  331. do
  332. app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')
  333. if [[ $(enough_ram_for_app "$app_name") == "0" ]]; then
  334. if [[ $(app_not_on_onion_only "$app_name") != "0" ]]; then
  335. if [[ $(app_is_installed "$app_name") == "1" ]]; then
  336. # shellcheck disable=SC2068
  337. if ! item_in_array "${app_name}" ${APPS_AVAILABLE[@]}; then
  338. variants_list=$(app_variants "$filename")
  339. if [ ${#variants_list} -gt 0 ]; then
  340. APPS_AVAILABLE+=("${app_name}")
  341. APPS_INSTALLED_NAMES+=("$app_name")
  342. fi
  343. fi
  344. fi
  345. fi
  346. fi
  347. done
  348. }
  349. # creates the APPS_AVAILABLE and APPS_CHOSEN arrays based on
  350. # the given variant name
  351. function choose_apps_for_variant {
  352. variant_name="$1"
  353. function_check item_in_array
  354. function_check app_variants
  355. function_check app_is_removed
  356. if [ ${#variant_name} -eq 0 ]; then
  357. echo $"No variant name for choosing apps"
  358. exit 237567
  359. fi
  360. FILES="/usr/share/${PROJECT_NAME}/apps/${PROJECT_NAME}-app-*"
  361. APPS_CHOSEN=()
  362. # for all the app scripts
  363. for filename in $FILES
  364. do
  365. app_name=$(echo "${filename}" | awk -F '-app-' '{print $2}')
  366. if [[ $(enough_ram_for_app "$app_name") == "0" ]]; then
  367. if [[ $(app_not_on_onion_only "$app_name") != "0" ]]; then
  368. # shellcheck disable=SC2068
  369. if item_in_array "${app_name}" ${APPS_AVAILABLE[@]}; then
  370. if grep -q "VARIANTS=" "${filename}"; then
  371. variants_list=$(app_variants "$filename")
  372. if [[ "${variants_list}" == 'all'* || \
  373. "${variants_list}" == "$variant_name" || \
  374. "${variants_list}" == "$variant_name "* || \
  375. "${variants_list}" == *" $variant_name "* || \
  376. "${variants_list}" == *" $variant_name" ]]; then
  377. if [[ $(app_is_removed "${a}") == "0" ]]; then
  378. #echo $"${app_name} chosen"
  379. APPS_CHOSEN+=("1")
  380. else
  381. APPS_CHOSEN+=("0")
  382. fi
  383. else
  384. APPS_CHOSEN+=("0")
  385. fi
  386. else
  387. APPS_CHOSEN+=("0")
  388. fi
  389. fi
  390. fi
  391. fi
  392. done
  393. function_check get_apps_installed
  394. get_apps_installed
  395. }
  396. # show a list of apps which have been chosen
  397. function list_chosen_apps {
  398. app_index=0
  399. # shellcheck disable=SC2068
  400. for a in ${APPS_AVAILABLE[@]}
  401. do
  402. if [[ ${APPS_CHOSEN[$app_index]} == "1" ]]; then
  403. echo $"${a}"
  404. fi
  405. app_index=$((app_index+1))
  406. done
  407. }
  408. function remove_apps {
  409. app_index=0
  410. # shellcheck disable=SC2068
  411. for a in ${APPS_AVAILABLE[@]}
  412. do
  413. if [[ ${APPS_INSTALLED[$app_index]} == "1" ]]; then
  414. if [[ ${APPS_CHOSEN[$app_index]} == "0" ]]; then
  415. echo $"Removing users for application: ${a}"
  416. function_check remove_users_for_app
  417. remove_users_for_app "${a}"
  418. echo $"Removing application: ${a}"
  419. function_check app_load_variables
  420. app_load_variables "${a}"
  421. function_check remove_app
  422. remove_app "${a}"
  423. function_check "remove_${a}"
  424. "remove_${a}"
  425. echo $"${a} was removed"
  426. fi
  427. fi
  428. app_index=$((app_index+1))
  429. done
  430. update_installed_apps_list
  431. }
  432. function install_apps_interactive {
  433. echo $"Interactive installer"
  434. app_index=0
  435. # shellcheck disable=SC2068
  436. for a in ${APPS_AVAILABLE[@]}
  437. do
  438. if [[ ${APPS_INSTALLED[$app_index]} == "0" ]]; then
  439. if [[ ${APPS_CHOSEN[$app_index]} == "1" ]]; then
  440. # interactively obtain settings for this app
  441. if [[ $(function_exists "install_interactive_${a}") == "1" ]]; then
  442. "install_interactive_${a}"
  443. fi
  444. fi
  445. fi
  446. app_index=$((app_index+1))
  447. done
  448. echo $"Interactive settings complete"
  449. }
  450. function user_added_to_app {
  451. user_name="$1"
  452. app_name="$2"
  453. if [[ $(is_valid_user "$user_name") == "1" ]]; then
  454. if [[ $(function_exists "add_user_${app_name}") == "1" ]]; then
  455. if grep -Fxq "${app_name}_${user_name}" "$APP_USERS_FILE"; then
  456. echo "1"
  457. return
  458. fi
  459. fi
  460. fi
  461. echo "0"
  462. }
  463. function add_users_after_install {
  464. app_name="$1"
  465. read_config_param MY_USERNAME
  466. # ensure a minimum password length
  467. if [ ! "$MINIMUM_PASSWORD_LENGTH" ]; then
  468. MINIMUM_PASSWORD_LENGTH=20
  469. fi
  470. if [ ${#MINIMUM_PASSWORD_LENGTH} -lt 20 ]; then
  471. MINIMUM_PASSWORD_LENGTH=20
  472. fi
  473. ADMIN_USERNAME=$(get_completion_param "Admin user")
  474. if [ ! "$ADMIN_USERNAME" ]; then
  475. ADMIN_USERNAME=$MY_USERNAME
  476. fi
  477. for d in /home/*/ ; do
  478. USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
  479. if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
  480. if [[ "$USERNAME" != "$ADMIN_USERNAME" ]]; then
  481. if [[ $(user_added_to_app "${USERNAME}" "${app_name}") == "0" ]]; then
  482. valstr=$"Login for user ${USERNAME}="
  483. app_password="$(create_password ${MINIMUM_PASSWORD_LENGTH})"
  484. "add_user_${app_name}" "${USERNAME}" "${app_password}"
  485. echo "${app_name}_${USERNAME}" >> "$APP_USERS_FILE"
  486. fi
  487. fi
  488. fi
  489. done
  490. }
  491. function remove_users_for_app {
  492. app_name="$1"
  493. read_config_param MY_USERNAME
  494. for d in /home/*/ ; do
  495. USERNAME=$(echo "$d" | awk -F '/' '{print $3}')
  496. if [[ $(is_valid_user "$USERNAME") == "1" ]]; then
  497. if [[ "$USERNAME" != "$MY_USERNAME" ]]; then
  498. if [[ $(user_added_to_app "${USERNAME}" "${app_name}") == "1" ]]; then
  499. if [[ $(function_exists "remove_user_${app_name}") == "1" ]]; then
  500. "remove_user_${app_name}" "${USERNAME}"
  501. fi
  502. sed -i "/${app_name}_${USERNAME}/d" "$APP_USERS_FILE"
  503. fi
  504. fi
  505. fi
  506. done
  507. }
  508. function install_apps {
  509. is_interactive=$1
  510. APP_INSTALLED_SUCCESS=1
  511. # interactive install configuration for each app
  512. if [ "${is_interactive}" ]; then
  513. install_apps_interactive
  514. fi
  515. # now install the apps
  516. app_index=0
  517. # shellcheck disable=SC2068
  518. for a in ${APPS_AVAILABLE[@]}
  519. do
  520. if [[ ${APPS_INSTALLED[$app_index]} == "0" ]]; then
  521. if [[ ${APPS_CHOSEN[$app_index]} == "1" ]]; then
  522. # remove any temp files
  523. rm -rf /tmp/*
  524. if [ "${is_interactive}" ]; then
  525. # clears any removal indicator
  526. function_check reinstall_app
  527. reinstall_app "${a}"
  528. function_check app_load_variables
  529. app_load_variables "${a}"
  530. if [[ $(app_is_installed "${a}") == "1" ]]; then
  531. echo $"Upgrading application from interactive: ${a}"
  532. "upgrade_${a}"
  533. echo $"${a} was upgraded from interactive"
  534. else
  535. echo $"Installing application from interactive: ${a}"
  536. APP_INSTALLED=
  537. "install_${a}"
  538. if [ $APP_INSTALLED ]; then
  539. function_check app_save_variables
  540. app_save_variables "${a}"
  541. function_check add_users_after_install
  542. add_users_after_install "${a}"
  543. function_check lockdown_permissions
  544. lockdown_permissions
  545. function_check install_completed
  546. install_completed "${a}"
  547. echo $"${a} was installed from interactive"
  548. else
  549. echo "Failed to install: ${a}" >> "/var/log/${PROJECT_NAME}.log"
  550. APP_INSTALLED_SUCCESS=
  551. echo $"${a} was not installed from interactive"
  552. fi
  553. fi
  554. else
  555. # check if the app was removed
  556. if [[ $(app_is_removed "${a}") == "0" ]]; then
  557. function_check app_load_variables
  558. app_load_variables "${a}"
  559. if [[ $(app_is_installed "${a}") == "1" ]]; then
  560. echo $"Upgrading application: ${a}"
  561. "upgrade_${a}"
  562. echo $"${a} was upgraded"
  563. else
  564. echo $"Installing application: ${a}"
  565. APP_INSTALLED=
  566. "install_${a}"
  567. if [ $APP_INSTALLED ]; then
  568. function_check app_save_variables
  569. app_save_variables "${a}"
  570. function_check add_users_after_install
  571. add_users_after_install "${a}"
  572. function_check lockdown_permissions
  573. lockdown_permissions
  574. function_check install_completed
  575. install_completed "${a}"
  576. echo $"${a} was installed"
  577. else
  578. echo "Failed to install: ${a}" >> "/var/log/${PROJECT_NAME}.log"
  579. APP_INSTALLED_SUCCESS=
  580. echo $"${a} was not installed"
  581. fi
  582. fi
  583. else
  584. echo $"${a} has been removed and so will not be reinstalled"
  585. fi
  586. fi
  587. fi
  588. fi
  589. app_index=$((app_index+1))
  590. done
  591. function_check update_installed_apps_list
  592. update_installed_apps_list
  593. }
  594. # NOTE: deliberately no exit 0