_common.sh 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. #!/bin/bash
  2. #=================================================
  3. # BACKUP
  4. #=================================================
  5. HUMAN_SIZE () { # Transforme une taille en Ko en une taille lisible pour un humain
  6. human=$(numfmt --to=iec --from-unit=1K $1)
  7. echo $human
  8. }
  9. CHECK_SIZE () { # Vérifie avant chaque backup que l'espace est suffisant
  10. file_to_analyse=$1
  11. backup_size=$(du --summarize "$file_to_analyse" | cut -f1)
  12. free_space=$(df --output=avail "/home/yunohost.backup" | sed 1d)
  13. if [ $free_space -le $backup_size ]
  14. then
  15. ynh_print_err "Espace insuffisant pour sauvegarder $file_to_analyse."
  16. ynh_print_err "Espace disponible: $(HUMAN_SIZE $free_space)"
  17. ynh_die "Espace nécessaire: $(HUMAN_SIZE $backup_size)"
  18. fi
  19. }
  20. #=================================================
  21. # PACKAGE CHECK BYPASSING...
  22. #=================================================
  23. IS_PACKAGE_CHECK () {
  24. return $(env | grep -c container=lxc)
  25. }
  26. #=================================================
  27. # BOOLEAN CONVERTER
  28. #=================================================
  29. bool_to_01 () {
  30. local var="$1"
  31. [ "$var" = "true" ] && var=1
  32. [ "$var" = "false" ] && var=0
  33. echo "$var"
  34. }
  35. bool_to_true_false () {
  36. local var="$1"
  37. [ "$var" = "1" ] && var=true
  38. [ "$var" = "0" ] && var=false
  39. echo "$var"
  40. }
  41. #=================================================
  42. # FUTUR OFFICIAL HELPERS
  43. #=================================================
  44. # Internal helper design to allow helpers to use getopts to manage their arguments
  45. #
  46. # [internal]
  47. #
  48. # example: function my_helper()
  49. # {
  50. # declare -Ar args_array=( [a]=arg1= [b]=arg2= [c]=arg3 )
  51. # local arg1
  52. # local arg2
  53. # local arg3
  54. # ynh_handle_getopts_args "$@"
  55. #
  56. # [...]
  57. # }
  58. # my_helper --arg1 "val1" -b val2 -c
  59. #
  60. # usage: ynh_handle_getopts_args "$@"
  61. # | arg: $@ - Simply "$@" to tranfert all the positionnal arguments to the function
  62. #
  63. # This helper need an array, named "args_array" with all the arguments used by the helper
  64. # that want to use ynh_handle_getopts_args
  65. # Be carreful, this array has to be an associative array, as the following example:
  66. # declare -Ar args_array=( [a]=arg1 [b]=arg2= [c]=arg3 )
  67. # Let's explain this array:
  68. # a, b and c are short options, -a, -b and -c
  69. # arg1, arg2 and arg3 are the long options associated to the previous short ones. --arg1, --arg2 and --arg3
  70. # For each option, a short and long version has to be defined.
  71. # Let's see something more significant
  72. # declare -Ar args_array=( [u]=user [f]=finalpath= [d]=database )
  73. #
  74. # NB: Because we're using 'declare' without -g, the array will be declared as a local variable.
  75. #
  76. # Please keep in mind that the long option will be used as a variable to store the values for this option.
  77. # For the previous example, that means that $finalpath will be fill with the value given as argument for this option.
  78. #
  79. # Also, in the previous example, finalpath has a '=' at the end. That means this option need a value.
  80. # So, the helper has to be call with --finalpath /final/path, --finalpath=/final/path or -f /final/path, the variable $finalpath will get the value /final/path
  81. # If there's many values for an option, -f /final /path, the value will be separated by a ';' $finalpath=/final;/path
  82. # For an option without value, like --user in the example, the helper can be called only with --user or -u. $user will then get the value 1.
  83. #
  84. # To keep a retrocompatibility, a package can still call a helper, using getopts, with positional arguments.
  85. # The "legacy mode" will manage the positional arguments and fill the variable in the same order than they are given in $args_array.
  86. # e.g. for `my_helper "val1" val2`, arg1 will be filled with val1, and arg2 with val2.
  87. ynh_handle_getopts_args () {
  88. # Manage arguments only if there's some provided
  89. set +x
  90. if [ $# -ne 0 ]
  91. then
  92. # Store arguments in an array to keep each argument separated
  93. local arguments=("$@")
  94. # For each option in the array, reduce to short options for getopts (e.g. for [u]=user, --user will be -u)
  95. # And built parameters string for getopts
  96. # ${!args_array[@]} is the list of all option_flags in the array (An option_flag is 'u' in [u]=user, user is a value)
  97. local getopts_parameters=""
  98. local option_flag=""
  99. for option_flag in "${!args_array[@]}"
  100. do
  101. # Concatenate each option_flags of the array to build the string of arguments for getopts
  102. # Will looks like 'abcd' for -a -b -c -d
  103. # If the value of an option_flag finish by =, it's an option with additionnal values. (e.g. --user bob or -u bob)
  104. # Check the last character of the value associate to the option_flag
  105. if [ "${args_array[$option_flag]: -1}" = "=" ]
  106. then
  107. # For an option with additionnal values, add a ':' after the letter for getopts.
  108. getopts_parameters="${getopts_parameters}${option_flag}:"
  109. else
  110. getopts_parameters="${getopts_parameters}${option_flag}"
  111. fi
  112. # Check each argument given to the function
  113. local arg=""
  114. # ${#arguments[@]} is the size of the array
  115. for arg in `seq 0 $(( ${#arguments[@]} - 1 ))`
  116. do
  117. # And replace long option (value of the option_flag) by the short option, the option_flag itself
  118. # (e.g. for [u]=user, --user will be -u)
  119. # Replace long option with =
  120. arguments[arg]="${arguments[arg]//--${args_array[$option_flag]}/-${option_flag} }"
  121. # And long option without =
  122. arguments[arg]="${arguments[arg]//--${args_array[$option_flag]%=}/-${option_flag}}"
  123. done
  124. done
  125. # Read and parse all the arguments
  126. # Use a function here, to use standart arguments $@ and be able to use shift.
  127. parse_arg () {
  128. # Read all arguments, until no arguments are left
  129. while [ $# -ne 0 ]
  130. do
  131. # Initialize the index of getopts
  132. OPTIND=1
  133. # Parse with getopts only if the argument begin by -, that means the argument is an option
  134. # getopts will fill $parameter with the letter of the option it has read.
  135. local parameter=""
  136. getopts ":$getopts_parameters" parameter || true
  137. if [ "$parameter" = "?" ]
  138. then
  139. ynh_die --message="Invalid argument: -${OPTARG:-}"
  140. elif [ "$parameter" = ":" ]
  141. then
  142. ynh_die --message="-$OPTARG parameter requires an argument."
  143. else
  144. local shift_value=1
  145. # Use the long option, corresponding to the short option read by getopts, as a variable
  146. # (e.g. for [u]=user, 'user' will be used as a variable)
  147. # Also, remove '=' at the end of the long option
  148. # The variable name will be stored in 'option_var'
  149. local option_var="${args_array[$parameter]%=}"
  150. # If this option doesn't take values
  151. # if there's a '=' at the end of the long option name, this option takes values
  152. if [ "${args_array[$parameter]: -1}" != "=" ]
  153. then
  154. # 'eval ${option_var}' will use the content of 'option_var'
  155. eval ${option_var}=1
  156. else
  157. # Read all other arguments to find multiple value for this option.
  158. # Load args in a array
  159. local all_args=("$@")
  160. # If the first argument is longer than 2 characters,
  161. # There's a value attached to the option, in the same array cell
  162. if [ ${#all_args[0]} -gt 2 ]; then
  163. # Remove the option and the space, so keep only the value itself.
  164. all_args[0]="${all_args[0]#-${parameter} }"
  165. # Reduce the value of shift, because the option has been removed manually
  166. shift_value=$(( shift_value - 1 ))
  167. fi
  168. # Declare the content of option_var as a variable.
  169. eval ${option_var}=""
  170. # Then read the array value per value
  171. local i
  172. for i in `seq 0 $(( ${#all_args[@]} - 1 ))`
  173. do
  174. # If this argument is an option, end here.
  175. if [ "${all_args[$i]:0:1}" == "-" ]
  176. then
  177. # Ignore the first value of the array, which is the option itself
  178. if [ "$i" -ne 0 ]; then
  179. break
  180. fi
  181. else
  182. # Else, add this value to this option
  183. # Each value will be separated by ';'
  184. if [ -n "${!option_var}" ]
  185. then
  186. # If there's already another value for this option, add a ; before adding the new value
  187. eval ${option_var}+="\;"
  188. fi
  189. eval ${option_var}+=\"${all_args[$i]}\"
  190. shift_value=$(( shift_value + 1 ))
  191. fi
  192. done
  193. fi
  194. fi
  195. # Shift the parameter and its argument(s)
  196. shift $shift_value
  197. done
  198. }
  199. # LEGACY MODE
  200. # Check if there's getopts arguments
  201. if [ "${arguments[0]:0:1}" != "-" ]
  202. then
  203. # If not, enter in legacy mode and manage the arguments as positionnal ones..
  204. # Dot not echo, to prevent to go through a helper output. But print only in the log.
  205. set -x; echo "! Helper used in legacy mode !" > /dev/null; set +x
  206. local i
  207. for i in `seq 0 $(( ${#arguments[@]} -1 ))`
  208. do
  209. # Try to use legacy_args as a list of option_flag of the array args_array
  210. # Otherwise, fallback to getopts_parameters to get the option_flag. But an associative arrays isn't always sorted in the correct order...
  211. # Remove all ':' in getopts_parameters
  212. getopts_parameters=${legacy_args:-${getopts_parameters//:}}
  213. # Get the option_flag from getopts_parameters, by using the option_flag according to the position of the argument.
  214. option_flag=${getopts_parameters:$i:1}
  215. if [ -z "$option_flag" ]; then
  216. ynh_print_warn --message="Too many arguments ! \"${arguments[$i]}\" will be ignored."
  217. continue
  218. fi
  219. # Use the long option, corresponding to the option_flag, as a variable
  220. # (e.g. for [u]=user, 'user' will be used as a variable)
  221. # Also, remove '=' at the end of the long option
  222. # The variable name will be stored in 'option_var'
  223. local option_var="${args_array[$option_flag]%=}"
  224. # Store each value given as argument in the corresponding variable
  225. # The values will be stored in the same order than $args_array
  226. eval ${option_var}+=\"${arguments[$i]}\"
  227. done
  228. unset legacy_args
  229. else
  230. # END LEGACY MODE
  231. # Call parse_arg and pass the modified list of args as an array of arguments.
  232. parse_arg "${arguments[@]}"
  233. fi
  234. fi
  235. set -x
  236. }
  237. #=================================================
  238. # Install or update the main directory yunohost.multimedia
  239. #
  240. # usage: ynh_multimedia_build_main_dir
  241. ynh_multimedia_build_main_dir () {
  242. local ynh_media_release="v1.2"
  243. local checksum="806a827ba1902d6911095602a9221181"
  244. # Download yunohost.multimedia scripts
  245. wget -nv https://github.com/YunoHost-Apps/yunohost.multimedia/archive/${ynh_media_release}.tar.gz
  246. # Check the control sum
  247. echo "${checksum} ${ynh_media_release}.tar.gz" | md5sum -c --status \
  248. || ynh_die "Corrupt source"
  249. # Check if the package acl is installed. Or install it.
  250. ynh_package_is_installed 'acl' \
  251. || ynh_package_install acl
  252. # Extract
  253. mkdir yunohost.multimedia-master
  254. tar -xf ${ynh_media_release}.tar.gz -C yunohost.multimedia-master --strip-components 1
  255. ./yunohost.multimedia-master/script/ynh_media_build.sh
  256. }
  257. # Add a directory in yunohost.multimedia
  258. # This "directory" will be a symbolic link to a existing directory.
  259. #
  260. # usage: ynh_multimedia_addfolder "Source directory" "Destination directory"
  261. #
  262. # | arg: -s, --source_dir= - Source directory - The real directory which contains your medias.
  263. # | arg: -d, --dest_dir= - Destination directory - The name and the place of the symbolic link, relative to "/home/yunohost.multimedia"
  264. ynh_multimedia_addfolder () {
  265. # Declare an array to define the options of this helper.
  266. declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= )
  267. local source_dir
  268. local dest_dir
  269. # Manage arguments with getopts
  270. ynh_handle_getopts_args "$@"
  271. ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --source="$source_dir" --dest="$dest_dir"
  272. }
  273. # Move a directory in yunohost.multimedia, and replace by a symbolic link
  274. #
  275. # usage: ynh_multimedia_movefolder "Source directory" "Destination directory"
  276. #
  277. # | arg: -s, --source_dir= - Source directory - The real directory which contains your medias.
  278. # It will be moved to "Destination directory"
  279. # A symbolic link will replace it.
  280. # | arg: -d, --dest_dir= - Destination directory - The new name and place of the directory, relative to "/home/yunohost.multimedia"
  281. ynh_multimedia_movefolder () {
  282. # Declare an array to define the options of this helper.
  283. declare -Ar args_array=( [s]=source_dir= [d]=dest_dir= )
  284. local source_dir
  285. local dest_dir
  286. # Manage arguments with getopts
  287. ynh_handle_getopts_args "$@"
  288. ./yunohost.multimedia-master/script/ynh_media_addfolder.sh --inv --source="$source_dir" --dest="$dest_dir"
  289. }
  290. # Allow an user to have an write authorisation in multimedia directories
  291. #
  292. # usage: ynh_multimedia_addaccess user_name
  293. #
  294. # | arg: -u, --user_name= - The name of the user which gain this access.
  295. ynh_multimedia_addaccess () {
  296. # Declare an array to define the options of this helper.
  297. declare -Ar args_array=( [u]=user_name=)
  298. local user_name
  299. # Manage arguments with getopts
  300. ynh_handle_getopts_args "$@"
  301. groupadd -f multimedia
  302. usermod -a -G multimedia $user_name
  303. }
  304. #=================================================
  305. # Create a dedicated fail2ban config (jail and filter conf files)
  306. #
  307. # usage: ynh_add_fail2ban_config log_file filter [max_retry [ports]]
  308. # | arg: -l, --logpath= - Log file to be checked by fail2ban
  309. # | arg: -r, --failregex= - Failregex to be looked for by fail2ban
  310. # | arg: -m, --max_retry= - Maximum number of retries allowed before banning IP address - default: 3
  311. # | arg: -p, --ports= - Ports blocked for a banned IP address - default: http,https
  312. ynh_add_fail2ban_config () {
  313. # Declare an array to define the options of this helper.
  314. declare -Ar args_array=( [l]=logpath= [r]=failregex= [m]=max_retry= [p]=ports= )
  315. local logpath
  316. local failregex
  317. local max_retry
  318. local ports
  319. # Manage arguments with getopts
  320. ynh_handle_getopts_args "$@"
  321. max_retry=${max_retry:-3}
  322. ports=${ports:-http,https}
  323. test -n "$logpath" || ynh_die "ynh_add_fail2ban_config expects a logfile path as first argument and received nothing."
  324. test -n "$failregex" || ynh_die "ynh_add_fail2ban_config expects a failure regex as second argument and received nothing."
  325. finalfail2banjailconf="/etc/fail2ban/jail.d/$app.conf"
  326. finalfail2banfilterconf="/etc/fail2ban/filter.d/$app.conf"
  327. ynh_backup_if_checksum_is_different "$finalfail2banjailconf" 1
  328. ynh_backup_if_checksum_is_different "$finalfail2banfilterconf" 1
  329. tee $finalfail2banjailconf <<EOF
  330. [$app]
  331. enabled = true
  332. port = $ports
  333. filter = $app
  334. logpath = $logpath
  335. maxretry = $max_retry
  336. EOF
  337. tee $finalfail2banfilterconf <<EOF
  338. [INCLUDES]
  339. before = common.conf
  340. [Definition]
  341. failregex = $failregex
  342. ignoreregex =
  343. EOF
  344. ynh_store_file_checksum "$finalfail2banjailconf"
  345. ynh_store_file_checksum "$finalfail2banfilterconf"
  346. if [ "$(lsb_release --codename --short)" != "jessie" ]; then
  347. systemctl reload fail2ban
  348. else
  349. systemctl restart fail2ban
  350. fi
  351. local fail2ban_error="$(journalctl -u fail2ban | tail -n50 | grep "WARNING.*$app.*")"
  352. if [ -n "$fail2ban_error" ]
  353. then
  354. echo "[ERR] Fail2ban failed to load the jail for $app" >&2
  355. echo "WARNING${fail2ban_error#*WARNING}" >&2
  356. fi
  357. }
  358. # Remove the dedicated fail2ban config (jail and filter conf files)
  359. #
  360. # usage: ynh_remove_fail2ban_config
  361. ynh_remove_fail2ban_config () {
  362. ynh_secure_remove "/etc/fail2ban/jail.d/$app.conf"
  363. ynh_secure_remove "/etc/fail2ban/filter.d/$app.conf"
  364. if [ "$(lsb_release --codename --short)" != "jessie" ]; then
  365. systemctl reload fail2ban
  366. else
  367. systemctl restart fail2ban
  368. fi
  369. }
  370. #=================================================
  371. # Read the value of a key in a ynh manifest file
  372. #
  373. # usage: ynh_read_manifest manifest key
  374. # | arg: -m, --manifest= - Path of the manifest to read
  375. # | arg: -k, --key= - Name of the key to find
  376. ynh_read_manifest () {
  377. # Declare an array to define the options of this helper.
  378. declare -Ar args_array=( [m]=manifest= [k]=manifest_key= )
  379. local manifest
  380. local manifest_key
  381. # Manage arguments with getopts
  382. ynh_handle_getopts_args "$@"
  383. python3 -c "import sys, json;print(json.load(open('$manifest', encoding='utf-8'))['$manifest_key'])"
  384. }
  385. # Read the upstream version from the manifest
  386. # The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
  387. # For example : 4.3-2~ynh3
  388. # This include the number before ~ynh
  389. # In the last example it return 4.3-2
  390. #
  391. # usage: ynh_app_upstream_version [-m manifest]
  392. # | arg: -m, --manifest= - Path of the manifest to read
  393. ynh_app_upstream_version () {
  394. declare -Ar args_array=( [m]=manifest= )
  395. local manifest
  396. # Manage arguments with getopts
  397. ynh_handle_getopts_args "$@"
  398. manifest="${manifest:-../manifest.json}"
  399. if [ ! -e "$manifest" ]; then
  400. manifest="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
  401. fi
  402. version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
  403. echo "${version_key/~ynh*/}"
  404. }
  405. # Read package version from the manifest
  406. # The version number in the manifest is defined by <upstreamversion>~ynh<packageversion>
  407. # For example : 4.3-2~ynh3
  408. # This include the number after ~ynh
  409. # In the last example it return 3
  410. #
  411. # usage: ynh_app_package_version [-m manifest]
  412. # | arg: -m, --manifest= - Path of the manifest to read
  413. ynh_app_package_version () {
  414. declare -Ar args_array=( [m]=manifest= )
  415. local manifest
  416. # Manage arguments with getopts
  417. ynh_handle_getopts_args "$@"
  418. manifest="${manifest:-../manifest.json}"
  419. if [ ! -e "$manifest" ]; then
  420. manifest="../settings/manifest.json" # Into the restore script, the manifest is not at the same place
  421. fi
  422. version_key=$(ynh_read_manifest --manifest="$manifest" --manifest_key="version")
  423. echo "${version_key/*~ynh/}"
  424. }
  425. # Checks the app version to upgrade with the existing app version and returns:
  426. # - UPGRADE_APP if the upstream app version has changed
  427. # - UPGRADE_PACKAGE if only the YunoHost package has changed
  428. #
  429. ## It stops the current script without error if the package is up-to-date
  430. #
  431. # This helper should be used to avoid an upgrade of an app, or the upstream part
  432. # of it, when it's not needed
  433. #
  434. # To force an upgrade, even if the package is up to date,
  435. # you have to set the variable YNH_FORCE_UPGRADE before.
  436. # example: sudo YNH_FORCE_UPGRADE=1 yunohost app upgrade MyApp
  437. #
  438. # usage: ynh_check_app_version_changed
  439. ynh_check_app_version_changed () {
  440. local force_upgrade=${YNH_FORCE_UPGRADE:-0}
  441. local package_check=${PACKAGE_CHECK_EXEC:-0}
  442. # By default, upstream app version has changed
  443. local return_value="UPGRADE_APP"
  444. local current_version=$(ynh_read_manifest --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json" --manifest_key="version" || echo 1.0)
  445. local current_upstream_version="$(ynh_app_upstream_version --manifest="/etc/yunohost/apps/$YNH_APP_INSTANCE_NAME/manifest.json")"
  446. local update_version=$(ynh_read_manifest --manifest="../manifest.json" --manifest_key="version" || echo 1.0)
  447. local update_upstream_version="$(ynh_app_upstream_version)"
  448. if [ "$current_version" == "$update_version" ] ; then
  449. # Complete versions are the same
  450. if [ "$force_upgrade" != "0" ]
  451. then
  452. echo "Upgrade forced by YNH_FORCE_UPGRADE." >&2
  453. unset YNH_FORCE_UPGRADE
  454. elif [ "$package_check" != "0" ]
  455. then
  456. echo "Upgrade forced for package check." >&2
  457. else
  458. ynh_die "Up-to-date, nothing to do" 0
  459. fi
  460. elif [ "$current_upstream_version" == "$update_upstream_version" ] ; then
  461. # Upstream versions are the same, only YunoHost package versions differ
  462. return_value="UPGRADE_PACKAGE"
  463. fi
  464. echo $return_value
  465. }
  466. #=================================================
  467. # Delete a file checksum from the app settings
  468. #
  469. # $app should be defined when calling this helper
  470. #
  471. # usage: ynh_remove_file_checksum file
  472. # | arg: -f, --file= - The file for which the checksum will be deleted
  473. ynh_delete_file_checksum () {
  474. # Declare an array to define the options of this helper.
  475. declare -Ar args_array=( [f]=file= )
  476. local file
  477. # Manage arguments with getopts
  478. ynh_handle_getopts_args "$@"
  479. local checksum_setting_name=checksum_${file//[\/ ]/_} # Replace all '/' and ' ' by '_'
  480. ynh_app_setting_delete $app $checksum_setting_name
  481. }
  482. #=================================================
  483. # EXPERIMENTAL HELPERS
  484. #=================================================
  485. # Start (or other actions) a service, print a log in case of failure and optionnaly wait until the service is completely started
  486. #
  487. # usage: ynh_systemd_action [-n service_name] [-a action] [ [-l "line to match"] [-p log_path] [-t timeout] [-e length] ]
  488. # | arg: -n, --service_name= - Name of the service to reload. Default : $app
  489. # | arg: -a, --action= - Action to perform with systemctl. Default: start
  490. # | arg: -l, --line_match= - Line to match - The line to find in the log to attest the service have finished to boot.
  491. # If not defined it don't wait until the service is completely started.
  492. # | arg: -p, --log_path= - Log file - Path to the log file. Default : /var/log/$app/$app.log
  493. # | arg: -t, --timeout= - Timeout - The maximum time to wait before ending the watching. Default : 300 seconds.
  494. # | arg: -e, --length= - Length of the error log : Default : 20
  495. ynh_systemd_action() {
  496. # Declare an array to define the options of this helper.
  497. declare -Ar args_array=( [n]=service_name= [a]=action= [l]=line_match= [p]=log_path= [t]=timeout= [e]=length= )
  498. local service_name
  499. local action
  500. local line_match
  501. local length
  502. local log_path
  503. local timeout
  504. # Manage arguments with getopts
  505. ynh_handle_getopts_args "$@"
  506. local service_name="${service_name:-$app}"
  507. local action=${action:-start}
  508. local log_path="${log_path:-/var/log/$service_name/$service_name.log}"
  509. local length=${length:-20}
  510. local timeout=${timeout:-300}
  511. # Start to read the log
  512. if [[ -n "${line_match:-}" ]]
  513. then
  514. local templog="$(mktemp)"
  515. # Following the starting of the app in its log
  516. if [ "$log_path" == "systemd" ] ; then
  517. # Read the systemd journal
  518. journalctl -u $service_name -f --since=-45 > "$templog" &
  519. else
  520. # Read the specified log file
  521. tail -F -n0 "$log_path" > "$templog" &
  522. fi
  523. # Get the PID of the tail command
  524. local pid_tail=$!
  525. fi
  526. echo "${action^} the service $service_name" >&2
  527. systemctl $action $service_name \
  528. || ( journalctl --lines=$length -u $service_name >&2 \
  529. ; test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2 \
  530. ; false )
  531. # Start the timeout and try to find line_match
  532. if [[ -n "${line_match:-}" ]]
  533. then
  534. local i=0
  535. for i in $(seq 1 $timeout)
  536. do
  537. # Read the log until the sentence is found, that means the app finished to start. Or run until the timeout
  538. if grep --quiet "$line_match" "$templog"
  539. then
  540. echo "The service $service_name has correctly started." >&2
  541. break
  542. fi
  543. echo -n "." >&2
  544. sleep 1
  545. done
  546. if [ $i -eq $timeout ]
  547. then
  548. echo "The service $service_name didn't fully started before the timeout." >&2
  549. echo "Please find here an extract of the end of the log of the service $service_name:"
  550. journalctl --lines=$length -u $service_name >&2
  551. test -n "$log_path" && echo "--" && tail --lines=$length "$log_path" >&2
  552. fi
  553. echo ""
  554. ynh_clean_check_starting
  555. fi
  556. }
  557. # Clean temporary process and file used by ynh_check_starting
  558. # (usually used in ynh_clean_setup scripts)
  559. #
  560. # usage: ynh_clean_check_starting
  561. ynh_clean_check_starting () {
  562. # Stop the execution of tail.
  563. kill -s 15 $pid_tail 2>&1
  564. ynh_secure_remove "$templog" 2>&1
  565. }
  566. #=================================================
  567. # Send an email to inform the administrator
  568. #
  569. # usage: ynh_send_readme_to_admin --app_message=app_message [--recipients=recipients] [--type=type]
  570. # | arg: -m --app_message= - The message to send to the administrator.
  571. # | arg: -r, --recipients= - The recipients of this email. Use spaces to separate multiples recipients. - default: root
  572. # example: "root admin@domain"
  573. # If you give the name of a YunoHost user, ynh_send_readme_to_admin will find its email adress for you
  574. # example: "root admin@domain user1 user2"
  575. # | arg: -t, --type= - Type of mail, could be 'backup', 'change_url', 'install', 'remove', 'restore', 'upgrade'
  576. ynh_send_readme_to_admin() {
  577. # Declare an array to define the options of this helper.
  578. declare -Ar args_array=( [m]=app_message= [r]=recipients= [t]=type= )
  579. local app_message
  580. local recipients
  581. local type
  582. # Manage arguments with getopts
  583. ynh_handle_getopts_args "$@"
  584. app_message="${app_message:-...No specific information...}"
  585. recipients="${recipients:-root}"
  586. type="${type:-install}"
  587. # Retrieve the email of users
  588. find_mails () {
  589. local list_mails="$1"
  590. local mail
  591. local recipients=" "
  592. # Read each mail in argument
  593. for mail in $list_mails
  594. do
  595. # Keep root or a real email address as it is
  596. if [ "$mail" = "root" ] || echo "$mail" | grep --quiet "@"
  597. then
  598. recipients="$recipients $mail"
  599. else
  600. # But replace an user name without a domain after by its email
  601. if mail=$(ynh_user_get_info "$mail" "mail" 2> /dev/null)
  602. then
  603. recipients="$recipients $mail"
  604. fi
  605. fi
  606. done
  607. echo "$recipients"
  608. }
  609. recipients=$(find_mails "$recipients")
  610. # Subject base
  611. local mail_subject="☁️🆈🅽🅷☁️: \`$app\`"
  612. # Adapt the subject according to the type of mail required.
  613. if [ "$type" = "backup" ]; then
  614. mail_subject="$mail_subject has just been backup."
  615. elif [ "$type" = "change_url" ]; then
  616. mail_subject="$mail_subject has just been moved to a new URL!"
  617. elif [ "$type" = "remove" ]; then
  618. mail_subject="$mail_subject has just been removed!"
  619. elif [ "$type" = "restore" ]; then
  620. mail_subject="$mail_subject has just been restored!"
  621. elif [ "$type" = "upgrade" ]; then
  622. mail_subject="$mail_subject has just been upgraded!"
  623. else # install
  624. mail_subject="$mail_subject has just been installed!"
  625. fi
  626. local mail_message="This is an automated message from your beloved YunoHost server.
  627. Specific information for the application $app.
  628. $app_message
  629. ---
  630. Automatic diagnosis data from YunoHost
  631. $(yunohost tools diagnosis | grep -B 100 "services:" | sed '/services:/d')"
  632. # Define binary to use for mail command
  633. if [ -e /usr/bin/bsd-mailx ]
  634. then
  635. local mail_bin=/usr/bin/bsd-mailx
  636. else
  637. local mail_bin=/usr/bin/mail.mailutils
  638. fi
  639. # Send the email to the recipients
  640. echo "$mail_message" | $mail_bin -a "Content-Type: text/plain; charset=UTF-8" -s "$mail_subject" "$recipients"
  641. }
  642. #=================================================
  643. ynh_debian_release () {
  644. lsb_release --codename --short
  645. }
  646. is_stretch () {
  647. if [ "$(ynh_debian_release)" == "stretch" ]
  648. then
  649. return 0
  650. else
  651. return 1
  652. fi
  653. }
  654. is_jessie () {
  655. if [ "$(ynh_debian_release)" == "jessie" ]
  656. then
  657. return 0
  658. else
  659. return 1
  660. fi
  661. }
  662. #=================================================
  663. ynh_maintenance_mode_ON () {
  664. # Load value of $path_url and $domain from the config if their not set
  665. if [ -z $path_url ]; then
  666. path_url=$(ynh_app_setting_get $app path)
  667. fi
  668. if [ -z $domain ]; then
  669. domain=$(ynh_app_setting_get $app domain)
  670. fi
  671. # Create an html to serve as maintenance notice
  672. echo "<!DOCTYPE html>
  673. <html>
  674. <head>
  675. <meta http-equiv="refresh" content="3">
  676. <title>Your app $app is currently under maintenance!</title>
  677. <style>
  678. body {
  679. width: 70em;
  680. margin: 0 auto;
  681. }
  682. </style>
  683. </head>
  684. <body>
  685. <h1>Your app $app is currently under maintenance!</h1>
  686. <p>This app has been put under maintenance by your administrator at $(date)</p>
  687. <p>Please wait until the maintenance operation is done. This page will be reloaded as soon as your app will be back.</p>
  688. </body>
  689. </html>" > "/var/www/html/maintenance.$app.html"
  690. # Create a new nginx config file to redirect all access to the app to the maintenance notice instead.
  691. echo "# All request to the app will be redirected to ${path_url}_maintenance and fall on the maintenance notice
  692. rewrite ^${path_url}/(.*)$ ${path_url}_maintenance/? redirect;
  693. # Use another location, to not be in conflict with the original config file
  694. location ${path_url}_maintenance/ {
  695. alias /var/www/html/ ;
  696. try_files maintenance.$app.html =503;
  697. # Include SSOWAT user panel.
  698. include conf.d/yunohost_panel.conf.inc;
  699. }" > "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  700. # The current config file will redirect all requests to the root of the app.
  701. # To keep the full path, we can use the following rewrite rule:
  702. # rewrite ^${path_url}/(.*)$ ${path_url}_maintenance/\$1? redirect;
  703. # The difference will be in the $1 at the end, which keep the following queries.
  704. # But, if it works perfectly for a html request, there's an issue with any php files.
  705. # This files are treated as simple files, and will be downloaded by the browser.
  706. # Would be really be nice to be able to fix that issue. So that, when the page is reloaded after the maintenance, the user will be redirected to the real page he was.
  707. systemctl reload nginx
  708. }
  709. ynh_maintenance_mode_OFF () {
  710. # Load value of $path_url and $domain from the config if their not set
  711. if [ -z $path_url ]; then
  712. path_url=$(ynh_app_setting_get $app path)
  713. fi
  714. if [ -z $domain ]; then
  715. domain=$(ynh_app_setting_get $app domain)
  716. fi
  717. # Rewrite the nginx config file to redirect from ${path_url}_maintenance to the real url of the app.
  718. echo "rewrite ^${path_url}_maintenance/(.*)$ ${path_url}/\$1 redirect;" > "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  719. systemctl reload nginx
  720. # Sleep 4 seconds to let the browser reload the pages and redirect the user to the app.
  721. sleep 4
  722. # Then remove the temporary files used for the maintenance.
  723. rm "/var/www/html/maintenance.$app.html"
  724. rm "/etc/nginx/conf.d/$domain.d/maintenance.$app.conf"
  725. systemctl reload nginx
  726. }
  727. #=================================================
  728. # Download and check integrity of a file from app.src_file
  729. #
  730. # The file conf/app.src_file need to contains:
  731. #
  732. # FILE_URL=Address to download the file
  733. # FILE_SUM=Control sum
  734. # # (Optional) Program to check the integrity (sha256sum, md5sum...)
  735. # # default: sha256
  736. # FILE_SUM_PRG=sha256
  737. # # (Optionnal) Name of the local archive (offline setup support)
  738. # # default: Name of the downloaded file.
  739. # FILENAME=example.deb
  740. #
  741. # usage: ynh_download_file --dest_dir="/destination/directory" [--source_id=myfile]
  742. # | arg: -d, --dest_dir= - Directory where to download the file
  743. # | arg: -s, --source_id= - Name of the source file 'app.src_file' if it isn't '$app'
  744. ynh_download_file () {
  745. # Declare an array to define the options of this helper.
  746. declare -Ar args_array=( [d]=dest_dir= [s]=source_id= )
  747. local dest_dir
  748. local source_id
  749. # Manage arguments with getopts
  750. ynh_handle_getopts_args "$@"
  751. source_id=${source_id:-app} # If the argument is not given, source_id equals "$app"
  752. # Load value from configuration file (see above for a small doc about this file
  753. # format)
  754. local src_file="$YNH_CWD/../conf/${source_id}.src_file"
  755. # If the src_file doesn't exist, use the backup path instead, with a "settings" directory
  756. if [ ! -e "$src_file" ]
  757. then
  758. src_file="$YNH_CWD/../settings/conf/${source_id}.src_file"
  759. fi
  760. local file_url=$(grep 'FILE_URL=' "$src_file" | cut -d= -f2-)
  761. local file_sum=$(grep 'FILE_SUM=' "$src_file" | cut -d= -f2-)
  762. local file_sumprg=$(grep 'FILE_SUM_PRG=' "$src_file" | cut -d= -f2-)
  763. local filename=$(grep 'FILENAME=' "$src_file" | cut -d= -f2-)
  764. # Default value
  765. file_sumprg=${file_sumprg:-sha256sum}
  766. if [ "$filename" = "" ] ; then
  767. filename="$(basename "$file_url")"
  768. fi
  769. local local_src="/opt/yunohost-apps-src/${YNH_APP_ID}/${filename}"
  770. if test -e "$local_src"
  771. then # Use the local source file if it is present
  772. cp $local_src $filename
  773. else # If not, download the source
  774. local out=`wget -nv -O $filename $file_url 2>&1` || ynh_print_err $out
  775. fi
  776. # Check the control sum
  777. echo "${file_sum} ${filename}" | ${file_sumprg} -c --status \
  778. || ynh_die "Corrupt file"
  779. # Create the destination directory, if it's not already.
  780. mkdir -p "$dest_dir"
  781. # Move the file to its destination
  782. mv $filename $dest_dir
  783. }