1#!/bin/sh -u
2#
3# -u: nounset (enable: set -u | disable: set +u)
4# -e: errexit
5# -r: restricted
6#
7#
8# VARIABLE CONVENTIONS
9#
10# 1. Function variables
11# ----------------------
12# * Lowercase
13# * Prefixed with _
14# Example: _tmp, _dir, _len
15#
16# 2. Config file variables
17# ------------------------
18# * Uppercase
19# * No prefix
20# Example: MYSQL_OPTS
21#
22# 3. Default values for config file variables
23# -------------------------------------------
24# * Uppercase
25# * Prefixed with _DEFAULT_
26# * Same name as config file variables
27# Example: _DEFAULT_CONFIG_FILE
28#
29# 4. Global program variables
30# -------------------------------------------
31# TODO: Also think about other schema, so I don't mix
32#       them up with vars from the config.
33# * Uppercase
34# * Prefixed with identifier, such as: MDS_[SECTION]_, DB_[SECTION]_
35# Example: MDS_INFO_NAME, DB_CNT_FAILED
36#
37# 5. Variables within loops / Temporary variables
38# -------------------------------------------
39# * Uppercase
40# * Prefixed with _TMP
41# Example: _TMP_RESULT <-- TODO: Fix this
42
43
44#
45# Normalize
46# Don't screw with numbers, sorting, date etc
47#
48LANG=C
49LC_ALL=C
50
51
52
53####################################################################################################
54####################################################################################################
55##
56## GLOBAL VARIABLES
57##
58####################################################################################################
59####################################################################################################
60
61
62################################################################################
63#
64# VERSION / CREDITS
65#
66################################################################################
67
68#
69# Some of this data is also written to the nagios logfile
70# in order to be able to check against latest/desired mysqldump-secure version.
71#
72# TODO: Prefix with MDS_
73INFO_NAME="mysqldump-secure"
74INFO_AUTHOR="Patrick Plocke <patrick@plocke.de>"
75INFO_GPGKEY="0x28BF179F"
76INFO_LICENSE="MIT"
77INFO_URL="http://mysqldump-secure.org"
78INFO_REPO="https://github.com/cytopia/mysqldump-secure"
79INFO_DATE="2016-08-18"
80INFO_VERSION="0.16.3"
81
82
83
84################################################################################
85#
86# AUTO-GENERATED
87#
88################################################################################
89
90# The following are auto-generated variables by the installer.
91# to determine where the script and its config files are installed.
92_PREFIX_ETC=""
93_PREFIX_LOG=""
94_PREFIX_VAR=""
95
96
97
98
99################################################################################
100#
101# EXIT CODES
102#
103################################################################################
104
105# Everything went fine.
106# No errors and no warnings.
107EXIT_OK=0
108
109# The database dump was successful, but some other
110# warnings occured.
111# E.g.: tmpreaper/tmpwatch could not delete files, etc
112EXIT_WARNING=1
113
114# The database dump was successful, but some other
115# errors occured.
116# E.g.: Directories could not be created, etc
117EXIT_ERROR=2
118
119# The database dump had errors.
120# E.g.: File already existed, wrong mysqldump options, wrong compression options, etc
121EXIT_FAIL=3
122
123# The program terminated before it could do backups
124# E.g.: No database connection, wrong config settings, etc
125EXIT_ABORT=4
126
127
128# Internal program error.
129# This should never happen, but when it does
130# the code is wrong
131EXIT_INT_ERR=5
132
133
134
135
136################################################################################
137#
138# WARNING, ERROR, FAIL COUNTER
139#
140################################################################################
141
142#
143# How many warnings occured
144#
145MDS_WARNING_COUNT=0
146
147#
148# How many errors occured
149#
150MDS_ERROR_COUNT=0
151
152
153#
154# How many failed database dumps occured
155#
156MDS_FAIL_COUNT=0
157
158
159
160
161################################################################################
162#
163# DEFAULT VARIABLES
164#
165################################################################################
166
167#
168# Do not djust the following default variables!
169# They can be overwritten inside mysqldump-secure.conf
170# or via command line arguments
171#
172
173# Default Configuration Path/Name
174_DEFAULT_CONFIG_FILE="${_PREFIX_ETC}/etc/mysqldump-secure.conf"
175_DEFAULT_CONFIG_CHMOD="0400"
176
177# Default output Variables
178_DEFAULT_DUMP_DIR="${_PREFIX_VAR}/var/mysqldump-secure"
179_DEFAULT_DUMP_DIR_CHMOD="0700"
180
181_DEFAULT_DUMP_FILE_PRE="$(date '+%Y-%m-%d')_$(date '+%H-%M')__"
182_DEFAULT_DUMP_FILE_CHMOD="0400"
183
184
185# MySQL defaults
186_DEFAULT_MYSQL_CNF_CHMOD="0400"
187
188# Default minimum size (in MB) required to enable `--quick`
189_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE=200
190
191# Default OpenSSL Variables
192_DEFAULT_OPENSSL_ALGO_ARG="-aes256"
193
194# Logging defaults
195_DEFAULT_LOG_CHMOD="0600"
196_DEFAULT_LOG_FILE="${_PREFIX_LOG}/var/log/mysqldump-secure.log"
197
198# Default nagios variables
199_DEFAULT_NAGIOS_LOG_CHMOD="0644"
200
201# Default system temp directory
202_DEFAULT_TMP_DIR="/tmp"
203
204
205
206################################################################################
207#
208# MYSQL VARIABLES
209#
210################################################################################
211
212
213# These command line arguments are considered insecure and can lead
214# to compromising your data
215MDS_MYSQL_EVIL_OPTS="--password -p --port -P --user -u --host -h --socket -s"
216
217# Do not allow to read any other MySQL configuration file
218# than the one specified in the configuration.
219MDS_MYSQL_BAD_OPTS="--no-defaults --defaults-extra-file --defaults-file"
220# All SSL Options are done via configuration
221MDS_MYSQL_BAD_OPTS="${MDS_MYSQL_BAD_OPTS} --ssl --ssl-ca --ssl-cert --ssl-key"
222# All Transaction Options (Consistency) are done via configuration
223MDS_MYSQL_BAD_OPTS="${MDS_MYSQL_BAD_OPTS} --single-transaction --lock-tables --skip-lock-tables"
224# Handled conditionally
225MDS_MYSQL_BAD_OPTS="${MDS_MYSQL_BAD_OPTS} --quick -q --skip-quick"
226
227
228
229################################################################################
230#
231# TERMINAL COLORS
232#
233################################################################################
234
235# If having a tty (console) use colors
236if [ -t 1 ]; then
237	CLR_FATAL="\033[0;31m"		# Red
238	CLR_ERROR="\033[0;31m"		# Red
239	CLR_WARNING="\033[0;33m"	# Yellow
240	CLR_INFO=""
241	CLR_OK="\033[0;32m"			# Green
242	CLR_DEBUG="\033[0;37m"		# Gray
243	CLR_TRACE="\033[0;37m"		# Gray
244	CLR_RESET="\033[m"			# Normal
245# Dump terminal (e.g.: via cron)
246else
247	CLR_FATAL=""
248	CLR_ERROR=""
249	CLR_WARNING=""
250	CLR_INFO=""
251	CLR_OK=""
252	CLR_DEBUG=""
253	CLR_TRACE=""
254	CLR_RESET=""
255fi
256
257
258
259
260
261####################################################################################################
262####################################################################################################
263##
264##  G L O B A L   F U N C T I O N S
265##
266####################################################################################################
267####################################################################################################
268
269
270#
271# Naming convention:
272# ------------------
273# Functions starting with '_name' are considered private and should only
274# be called from within other functions.
275#
276
277
278
279################################################################################
280#
281# ABORT
282#
283################################################################################
284
285# This function is used to abort
286# the whole script if internal errors occured.
287# This function should never be called.
288# If this function is called, the programmer screwed up.
289#
290# @param  string Calling function name (for reference)
291# @param  string Affected variable name (for reference)
292# @param  string Affected variable value (for reference)
293# @output string Error message
294# @exit   integer This function aborts with exit code
295_abort_on_internal_error() {
296	_func="${1}"
297	_var="${2}"
298	_val="${3}"
299
300	echo "Unhandled exception in: ${_func}" 1>&2
301	echo "Invalid value for ${_var}: '${_val}'" 1>&2
302	echo "Please report this error on github: ${INFO_REPO}" 1>&2
303	echo "The programmer fucked up" 1>&2
304	echo "Good bye" 1>&2
305
306	exit ${EXIT_INT_ERR}
307}
308
309
310
311################################################################################
312#
313#  L O G G I N G   F U N C T I O N S
314#
315################################################################################
316
317
318############################################################
319# Private Logger Helper
320############################################################
321
322
323# Get the severity prefix for stdout/stderr and logging
324#
325# @param  string  Severity
326# @output string  Formatted level
327# @return integer 0: success, 1: unknown level
328_get_severity_level_prefix() {
329	_lvl="${1}"
330
331	case "${_lvl}" in
332		trace)
333			echo "[TRACE]"
334			return 0
335			;;
336		debug)
337			echo "[DEBUG]"
338			return 0
339			;;
340		info)
341			echo "[INFO] "
342			return 0
343			;;
344		ok)
345			echo "[OK]   "
346			return 0
347			;;
348		warn)
349			echo "[WARN] "
350			return 0
351			;;
352		err)
353			echo "[ERR]  "
354			return 0
355			;;
356		fatal)
357			echo "[FATAL]"
358			return 0
359			;;
360		*)
361			echo "[UNDEF]"
362			return 1
363			;;
364	esac
365}
366
367
368# Get the severity color based on error level
369#
370# @param  string  Severity
371# @output string  Color code
372# @return integer 0: success, 1: unknown level
373_get_severity_color_prefix() {
374	_lvl="${1}"
375
376	case "${_lvl}" in
377		trace)
378			echo "${CLR_TRACE}"
379			return 0
380			;;
381		debug)
382			echo "${CLR_DEBUG}"
383			return 0
384			;;
385		info)
386			echo "${CLR_INFO}"
387			return 0
388			;;
389		ok)
390			echo "${CLR_OK}"
391			return 0
392			;;
393		warn)
394			echo "${CLR_WARNING}"
395			return 0
396			;;
397		err)
398			echo "${CLR_ERROR}"
399			return 0
400			;;
401		fatal)
402			echo "${CLR_FATAL}"
403			return 0
404			;;
405		*)
406			echo ""
407			return 1
408			;;
409	esac
410}
411
412
413#
414# Output (single or multi-line) text to stdout, stderr or file
415# (Console Out Recursive: _cout)
416#
417# @param  string  Where to output: 'stdout', 'stderr' or file
418# @param  string  Line Prefix (e.g.: date or color)
419# @param  string  Multi/single line message to outout
420# @param  string  Line Suffix (e.g.: color resetter)
421# @return integer Success
422_coutr() {
423	_target="${1}"
424	_prefix="${2}"
425	_string="${3}"
426	_suffix="${4}"
427
428	if [ "${_target}" = "stderr" ]; then
429		IFS='
430		'
431		for _line in ${_string}; do
432			printf "${_prefix}%s${_suffix}\n" "${_line}"  1>&2	# stdout -> stderr
433		done
434		unset IFS
435		return 0
436	elif  [ "${_target}" = "stdout" ]; then
437		IFS='
438		'
439		for _line in ${_string}; do
440			printf "${_prefix}%s${_suffix}\n" "${_line}" # stdout
441		done
442		unset IFS
443		return 0
444	elif [ -f "${_target}" ]; then
445		IFS='
446		'
447		for _line in ${_string}; do
448			printf "${_prefix}%s${_suffix}\n" "${_line}" >> "${_target}" # file
449		done
450		unset IFS
451		return 0
452	fi
453
454	return 1
455}
456
457
458#
459# Output single line to stdout, stderr or file.
460# (Console Out Inline: _couti)
461#
462# Make sure to take care about trailing newlines inside $_string
463#
464# @param  string  Where to output: 'stdout', 'stderr' or file
465# @param  string  Line Prefix (e.g.: date or color)
466# @param  string  Single line message to outout
467# @param  string  Line Suffix (e.g.: color resetter)
468# @return integer Success
469_couti() {
470	_target="${1}"
471	_prefix="${2}"
472	_string="${3}"
473	_suffix="${4}"
474
475	if [ "${_target}" = "stderr" ]; then
476		printf "${_prefix}${_string}${_suffix}%s" "" 1>&2	# stdout -> stderr
477		return 0
478	elif  [ "${_target}" = "stdout" ]; then
479		printf "${_prefix}${_string}${_suffix}%s" "" # stdout
480		return 0
481	elif [ -f "${_target}" ]; then
482		printf "${_prefix}${_string}${_suffix}%s" "" >> "${_target}" # file
483		return 0
484	fi
485
486	return 1
487}
488
489
490
491############################################################
492# Public Logger functions
493############################################################
494
495#
496# Single- multi-line output to stdout/stderr and/or logfile.
497#
498# @public
499#
500# @param  string  _lvl	  Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
501#                         Can also be a combination separated with '|' for an extra prefix.
502#                         E.g.: "err|(RUN)"
503# @param  string  _msg	  Message (single-line or multiline)
504# @param  integer _ver	  (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
505# @param  string  _log	  (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
506# @param  integer _file   Full path to logfile
507# @return integer 0
508debug() {
509	_lvl="${1}"		# Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
510	_msg="${2}"		# Message (single-line or multiline)
511	_ver="${3}"		# (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
512	_log="${4}"		# (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
513	_file="${5}"	# Full path to logfile
514
515
516	# Separate _lvl which could be in format:
517	# "err|(RUN): "
518	_pre="$( echo "${_lvl}" | awk -F '|' '{print $2}' )" # Get prefix if it exists behind a '|' separator
519	_lvl="$( echo "${_lvl}" | awk -F '|' '{print $1}' )" # Extract _lvl (must be 2nd line, as it overwrites itself)
520
521
522	# Make sure this function is used correctly
523	if [ "${#}" != "5" ]; then
524		_abort_on_internal_error "debug()" "\$#" "${#}"
525	fi
526	if [ "${_lvl}" != "trace" ] && [ "${_lvl}" != "debug" ] && [ "${_lvl}" != "info" ] && [ "${_lvl}" != "ok" ] && [ "${_lvl}" != "err" ] && [ "${_lvl}" != "warn" ] && [ "${_lvl}" != "fatal" ]; then
527		_abort_on_internal_error "debug()" "\$_lvl" "${_lvl}"
528	fi
529	if [ "${_ver}" != "0" ] && [ "${_ver}" != "1" ] && [ "${_ver}" != "2" ] && [ "${_ver}" != "3" ]; then
530		_abort_on_internal_error "debug()" "\$_ver" "${_ver}"
531	fi
532	if [ "${_log}" != "0" ] && [ "${_log}" != "1" ] && [ "${_log}" != "2" ] && [ "${_log}" != "3" ]; then
533		_abort_on_internal_error "debug()" "\$_log" "${_log}"
534	fi
535
536
537	# Prefixes for severity level and date
538	_pre_level="$( _get_severity_level_prefix "${_lvl}" )"	# e.g.: "[DEBUG]" or [ERR], etc
539	_pre_color="$( _get_severity_color_prefix "${_lvl}" )"	# e.g.: Red color code for error
540	_pre_date="$( date '+%Y-%m-%d %H:%M:%S' )"
541
542
543	# Remove empty lines and lines which only contain spaces from $_msg
544	_msg="$( echo "${_msg}" | sed '/^[[:space:]]*$/d' )"
545
546
547	#
548	# ---------- [OUT] to stdout or stderr ----------
549	#
550
551
552	#
553	# 1.) [OUT] Always output '[fatal], [error] and [warning] to stderr
554	#
555	if [ "${_lvl}" = "fatal" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "warn" ]; then
556		_coutr "stderr" "${_pre_color}${_pre_level} ${_pre}" "${_msg}" "${CLR_RESET}"
557	fi
558
559	#
560	# 2.) [OUT] Highest verbosity (Trace mode: -vv)
561	#
562	if [ "${_ver}" = "3" ]; then
563		if [ "${_lvl}" = "trace" ] || [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
564			_coutr "stdout" "${_pre_color}${_pre_level} ${_pre}" "${_msg}" "${CLR_RESET}"
565		fi
566	fi
567
568	#
569	# 3.) [OUT] Debug verbosity (Debug mode: -v)
570	#
571	if [ "${_ver}" = "2" ]; then
572		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
573			_coutr "stdout" "${_pre_color}${_pre_level} ${_pre}" "${_msg}" "${CLR_RESET}"
574		fi
575	fi
576
577	#
578	# 4.) [OUT] Normal verbosity (Normal mode)
579	#
580	if [ "${_ver}" = "1" ]; then
581		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
582			_coutr "stdout" "${_pre_color}${_pre_level} ${_pre}" "${_msg}" "${CLR_RESET}"
583		fi
584	fi
585
586
587	#
588	# ---------- [FILE] to logfile ----------
589	#
590
591	#
592	# 5.) [FILE] Highest log level (LOG=3)
593	#
594	if [ "${_log}" = "3" ]; then
595		_coutr "${_file}" "${_pre_date} ${_pre_level} ${_pre}" "${_msg}" ""
596	fi
597
598	#
599	# 6.) [FILE] Debug log level (LOG=2)
600	#
601	if [ "${_log}" = "2" ]; then
602		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
603			_coutr "${_file}" "${_pre_date} ${_pre_level} ${_pre}" "${_msg}" ""
604		fi
605	fi
606
607	#
608	# 6.) [FILE] Normal log level (LOG=1)
609	#
610	if [ "${_log}" = "1" ]; then
611		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
612			_coutr "${_file}" "${_pre_date} ${_pre_level} ${_pre}" "${_msg}" ""
613		fi
614	fi
615
616	return 0
617}
618
619#
620# Single-line inline output (without prefix and without newline) to stdout/stderr and/or logfile.
621#
622# @public
623#
624# @param  string  _lvl	  Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
625# @param  string  _msg	  Message (single-line or multiline)
626# @param  integer _ver	  (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
627# @param  string  _log	  (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
628# @param  integer _file   Full path to logfile
629# @return integer 0
630debug_i() {
631	_lvl="${1}"		# Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
632	_msg="${2}"		# Message (single-line or multiline)
633	_ver="${3}"		# (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
634	_log="${4}"		# (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
635	_file="${5}"	# Full path to logfile
636
637	# Make sure this function is used correctly
638	if [ "${#}" != "5" ]; then
639		_abort_on_internal_error "debug_i()" "\$#" "${#}"
640	fi
641	if [ "${_lvl}" != "trace" ] && [ "${_lvl}" != "debug" ] && [ "${_lvl}" != "info" ] && [ "${_lvl}" != "ok" ] && [ "${_lvl}" != "err" ] && [ "${_lvl}" != "warn" ] && [ "${_lvl}" != "fatal" ]; then
642		_abort_on_internal_error "debug_i()" "\$_lvl" "${_lvl}"
643	fi
644	if [ "${_ver}" != "0" ] && [ "${_ver}" != "1" ] && [ "${_ver}" != "2" ] && [ "${_ver}" != "3" ]; then
645		_abort_on_internal_error "debug_i()" "\$_ver" "${_ver}"
646	fi
647	if [ "${_log}" != "0" ] && [ "${_log}" != "1" ] && [ "${_log}" != "2" ] && [ "${_log}" != "3" ]; then
648		_abort_on_internal_error "debug_i()" "\$_log" "${_log}"
649	fi
650
651
652
653	# Prefixes for severity level and date
654	_pre_color="$( _get_severity_color_prefix "${_lvl}" )"	# e.g.: Red color code for error
655
656	# Prefix the line?
657	_pre_date=""
658	_pre_level=""
659
660
661	# Remove empty lines and lines which only contain spaces from $_msg
662	#_msg="$( echo "${_msg}" | sed '/^[[:space:]]*$/d' )"
663
664
665	#
666	# ---------- [OUT] to stdout or stderr ----------
667	#
668
669
670	#
671	# 1.) [OUT] Always output '[fatal], [error] and [warning] to stderr
672	#
673	if [ "${_lvl}" = "fatal" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "warn" ]; then
674		_couti "stderr" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
675	fi
676
677	#
678	# 2.) [OUT] Highest verbosity (Trace mode: -vv)
679	#
680	if [ "${_ver}" = "3" ]; then
681		if [ "${_lvl}" = "trace" ] || [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
682			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
683		fi
684	fi
685
686	#
687	# 3.) [OUT] Debug verbosity (Debug mode: -v)
688	#
689	if [ "${_ver}" = "2" ]; then
690		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
691			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
692		fi
693	fi
694
695	#
696	# 4.) [OUT] Normal verbosity (Normal mode)
697	#
698	if [ "${_ver}" = "1" ]; then
699		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
700			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
701		fi
702	fi
703
704
705	#
706	# ---------- [FILE] to logfile ----------
707	#
708
709	#
710	# 5.) [FILE] Highest log level (LOG=3)
711	#
712	if [ "${_log}" = "3" ]; then
713		_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
714	fi
715
716	#
717	# 6.) [FILE] Debug log level (LOG=2)
718	#
719	if [ "${_log}" = "2" ]; then
720		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
721			_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
722		fi
723	fi
724
725	#
726	# 6.) [FILE] Normal log level (LOG=1)
727	#
728	if [ "${_log}" = "1" ]; then
729		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
730			_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
731		fi
732	fi
733
734	return 0
735}
736
737
738#
739# Single-line inline output with prefix (without newline) to stdout/stderr and/or logfile.
740#
741# @public
742#
743# @param  string  _lvl	  Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
744# @param  string  _msg	  Message (single-line or multiline)
745# @param  integer _ver	  (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
746# @param  string  _log	  (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
747# @param  integer _file   Full path to logfile
748# @return integer 0
749debug_pi() {
750	_lvl="${1}"		# Assigned log level: "trace", "debug", "info", "warn" or "err" "fatal"
751	_msg="${2}"		# Message (single-line or multiline)
752	_ver="${3}"		# (0|1|2|3) Current set verbosity level (0:fat,err,warn, 1:normal, 2:debug, 3:trace)
753	_log="${4}"		# (0|1|2|3) Current set file logging level (0:off, 1:normal, 2:debug, 3:trace)
754	_file="${5}"	# Full path to logfile
755
756	# Make sure this function is used correctly
757	if [ "${#}" != "5" ]; then
758		_abort_on_internal_error "debug_pi()" "\$#" "${#}"
759	fi
760	if [ "${_lvl}" != "trace" ] && [ "${_lvl}" != "debug" ] && [ "${_lvl}" != "info" ] && [ "${_lvl}" != "ok" ] && [ "${_lvl}" != "err" ] && [ "${_lvl}" != "warn" ] && [ "${_lvl}" != "fatal" ]; then
761		_abort_on_internal_error "debug_pi()" "\$_lvl" "${_lvl}"
762	fi
763	if [ "${_ver}" != "0" ] && [ "${_ver}" != "1" ] && [ "${_ver}" != "2" ] && [ "${_ver}" != "3" ]; then
764		_abort_on_internal_error "debug_pi()" "\$_ver" "${_ver}"
765	fi
766	if [ "${_log}" != "0" ] && [ "${_log}" != "1" ] && [ "${_log}" != "2" ] && [ "${_log}" != "3" ]; then
767		_abort_on_internal_error "debug_pi()" "\$_log" "${_log}"
768	fi
769
770
771	# Prefixes for severity level and date
772	_pre_color="$( _get_severity_color_prefix "${_lvl}" )"	# e.g.: Red color code for error
773
774	_pre_date="$( date '+%Y-%m-%d %H:%M:%S' )"
775	_pre_level="$( _get_severity_level_prefix "${_lvl}" )"	# e.g.: "[DEBUG]" or [ERR], etc
776
777
778	# Remove empty lines and lines which only contain spaces from $_msg
779	#_msg="$( echo "${_msg}" | sed '/^[[:space:]]*$/d' )"
780
781
782	#
783	# ---------- [OUT] to stdout or stderr ----------
784	#
785
786
787	#
788	# 1.) [OUT] Always output '[fatal], [error] and [warning] to stderr
789	#
790	if [ "${_lvl}" = "fatal" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "warn" ]; then
791		_couti "stderr" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
792	fi
793
794	#
795	# 2.) [OUT] Highest verbosity (Trace mode: -vv)
796	#
797	if [ "${_ver}" = "3" ]; then
798		if [ "${_lvl}" = "trace" ] || [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
799			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
800		fi
801	fi
802
803	#
804	# 3.) [OUT] Debug verbosity (Debug mode: -v)
805	#
806	if [ "${_ver}" = "2" ]; then
807		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
808			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
809		fi
810	fi
811
812	#
813	# 4.) [OUT] Normal verbosity (Normal mode)
814	#
815	if [ "${_ver}" = "1" ]; then
816		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ]; then
817			_couti "stdout" "${_pre_color}${_pre_level} " "${_msg}" "${CLR_RESET}"
818		fi
819	fi
820
821
822	#
823	# ---------- [FILE] to logfile ----------
824	#
825
826	#
827	# 5.) [FILE] Highest log level (LOG=3)
828	#
829	if [ "${_log}" = "3" ]; then
830		_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
831	fi
832
833	#
834	# 6.) [FILE] Debug log level (LOG=2)
835	#
836	if [ "${_log}" = "2" ]; then
837		if [ "${_lvl}" = "debug" ] || [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
838			_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
839		fi
840	fi
841
842	#
843	# 6.) [FILE] Normal log level (LOG=1)
844	#
845	if [ "${_log}" = "1" ]; then
846		if [ "${_lvl}" = "info" ] || [ "${_lvl}" = "ok" ] || [ "${_lvl}" = "warn" ] || [ "${_lvl}" = "err" ] || [ "${_lvl}" = "fatal" ]; then
847			_couti "${_file}" "${_pre_date} ${_pre_level} " "${_msg}" ""
848		fi
849	fi
850
851	return 0
852}
853
854
855
856
857################################################################################
858#
859#  M A T H   F U N C T I O N S
860#
861################################################################################
862
863
864# Test if argument is an integer.
865#
866# @param  mixed
867# @return integer	0: is number | 1: not a number
868isint(){
869	printf "%d" "${1}" >/dev/null 2>&1 && return 0 || return 1;
870}
871
872
873# Sum up two numbers.
874#
875# @param  float/integer
876# @param  float/integer
877# @output float/integer
878sum() {
879	echo | awk -v "a=${1}" -v "b=${2}" '{print a + b}'
880}
881
882# Subtract two numbers.
883#
884# @param  float/integer
885# @param  float/integer
886# @output float/integer
887sub() {
888	echo | awk -v "a=${1}" -v "b=${2}" '{print a - b}'
889}
890
891# Divide two numbers.
892#
893# @param  float/integer
894# @param  float/integer
895# @output float/integer
896div() {
897	echo | awk -v "a=${1}" -v "b=${2}" '{print a / b}'
898}
899
900
901
902# Round a number
903#
904# @param  float	   Number to round
905# @param  integer  Decimal places
906# @output float    Result
907round() {
908	_number="${1}"
909	_precision="${2}"
910
911	# Note this is a locale dependent usage of printf
912	# Separators are assumed '.' and not ','
913	# This is fixed via setting LC_ALL=C and LANG=C
914	# at the very top of this script.
915	printf '%.*f\n' "${_precision}" "${_number}"
916}
917
918
919################################################################################
920#
921#  S T R I N G   F U N C T I O N S
922#
923################################################################################
924
925
926#
927# Get the length of a string.
928#
929# @param  string
930# @output integer Length
931str_len() {
932	echo "${1}" | awk '{print length()}'
933}
934
935
936# Concatenate two strings with a glue (separator).
937# Do not add separator if first string is empty.
938#
939# @param  string  First string
940# @param  string  Glue
941# @param  string  Second string
942# @output string  Final string
943str_join() {
944	_first="${1}"
945	_glue="${2}"
946	_last="${3}"
947
948	if [ "${_first}" = "" ]; then
949		echo "${_last}";
950		return 0
951	elif [ "${_last}" = "" ]; then
952		echo "${_first}";
953		return 0
954	fi
955
956	# Make sure $_glue is within the placeholder part of printf
957	# this way it can also use '\n' and make a real newline
958	printf "%s${_glue}%s\n" "${_first}" "${_last}"
959	return
960}
961
962# Renove a word from a space separated string.
963#
964# @param  string  Space separated string of words
965# @param  string  Word to remove
966# @output string  Final string
967str_remove_word() {
968	_string="${1}"
969	_word="${2}"
970
971	# Loop over each space separated word line by line
972	for _each in ${_string}; do
973		# Desired word found?
974		# Remove from variable
975		if [ "${_word}" = "${_each}" ]; then
976			_string="$( echo "${_string}" | sed "s/${_word}//" )"
977		fi
978	done
979
980	echo "${_string}"
981}
982
983
984# Get number of lines in a string
985#
986# @param  string  String
987# @output integer Number of lines
988str_count_lines() {
989	_string="${1}"
990	echo "${_string}" | grep -c ''
991}
992
993
994
995
996################################################################################
997#
998#  D A T E  F U N C T I O N S
999#
1000################################################################################
1001
1002
1003# Timestamp to formated date.
1004#
1005# @param  integer  Timestamp
1006# @param  string   Format (e.g.: '%Y-%m-%d %H:%M:%S %Z [%z')
1007# @output string   Formated date
1008# @return integer  0:success, 1:fail
1009formatted_timestamp() {
1010	_timestamp="${1}"
1011	_format="${2}"
1012
1013	# BSD / OSX date function
1014	if date -r 1457171267 >/dev/null 2>&1; then
1015		date -r "${_timestamp}" +"${_format}"
1016		return 0
1017	# Linux date
1018	elif date -d @1457171267 >/dev/null 2>&1; then
1019		date -d @"${_timestamp}" +"${_format}"
1020		return 0
1021	fi
1022	echo "${_timestamp}"
1023
1024	return 1
1025}
1026
1027
1028# Get time in sec since unix epoch
1029#
1030# @output integer Time in Seconds
1031#
1032get_time() {
1033	date +%s
1034}
1035
1036# Calculate duration in seconds
1037#
1038# @param  integer Unix epoch start time (in seconds)
1039# @output integer Duration in seconds
1040get_duration() {
1041	_start_time="${1}"
1042	_end_time="$(get_time)"
1043
1044	_duration="$((_end_time - _start_time))"
1045	echo "${_duration}"
1046}
1047
1048
1049################################################################################
1050#
1051#  F I L E   F U N C T I O N S
1052#
1053################################################################################
1054
1055
1056
1057# Get the file mtime
1058# When file is modified
1059#
1060# @param  string	path to file/folder
1061# @output integer	File mtime (timestamp)
1062# @return integer	Return code
1063get_file_mtime() {
1064	_file="${1}"
1065	_mtime="0"
1066	_exit=0
1067
1068	# Linux version
1069	if ! _mtime="$(stat -c %Y "${_file}" 2>/dev/null)"; then
1070		# OSX/BSD version
1071		if ! _mtime="$(stat -f %m "${_file}" 2>/dev/null)"; then
1072			# Try date
1073			if ! _mtime="$(date -r "${_file}" +%s 2>/dev/null)"; then
1074				_mtime="0"
1075				_exit=1
1076			fi
1077		fi
1078	fi
1079
1080	echo "${_mtime}"
1081	return ${_exit}
1082}
1083
1084
1085# Get the file ctime
1086# When file is modified or when inode changes (chown/chmod)
1087#
1088# @param  string	path to file/folder
1089# @output integer	File mtime (timestamp)
1090# @return integer	Return code
1091get_file_ctime() {
1092	_file="${1}"
1093	_ctime="0"
1094	_exit=0
1095
1096	# Linux version
1097	if ! _ctime="$(stat -c %Z "${_file}" 2>/dev/null)"; then
1098		# OSX/BSD version
1099		if ! _ctime="$(stat -f %c "${_file}" 2>/dev/null)"; then
1100			_ctime="0"
1101			_exit=1
1102		fi
1103	fi
1104
1105	echo "${_ctime}"
1106	return ${_exit}
1107}
1108
1109
1110
1111# Get file size in bytes of file or directory.
1112#
1113# @param  string	path to file/folder
1114# @param  char	    Unit: 'b': Bytes, 'k': KB, 'm': MB, 'g': GB (defaults to 'b')
1115# @output integer	File size in bytes
1116# @return integer	Return code
1117get_file_size() {
1118	_file="${1}"
1119	_unit="${2}"
1120	_size="0"
1121	_exit=1
1122
1123	_size="$($(which ls) -l "${_file}" 2>/dev/null)"
1124	_exit=$?
1125	_size="$(echo "${_size}" | awk '{print $5}')"
1126
1127	if [ "${_unit}" = "k" ]; then
1128		_size="$( div "${_size}" "1024" )"
1129		_size="$( round "${_size}" "2" )"
1130	elif [ "${_unit}" = "m" ]; then
1131		_size="$( div "${_size}" "1048576" )"
1132		_size="$( round "${_size}" "2" )"
1133	elif [ "${_unit}" = "g" ]; then
1134		_size="$( div "${_size}" "1073741824" )"
1135		_size="$( round "${_size}" "2" )"
1136	fi
1137
1138	echo "${_size}"
1139	return ${_exit}
1140}
1141
1142
1143# Get md5/sha256 hash of file or directory.
1144#
1145# @param  string	path to file/folder
1146# @param  string	algo: 'md5' or 'sha256' (defaults to md5)
1147# @output string	Hash
1148# @return integer	Return code
1149get_file_hash() {
1150	_file="${1}"
1151	_algo="${2}"
1152	_hash="unknown"
1153	_exit=1
1154
1155	if [ "${_algo}" = "sha256" ]; then
1156		if command -v shasum > /dev/null 2>&1 ; then
1157			_hash="$($(which shasum) -a 256 "${_file}" 2>/dev/null)"
1158			_exit=$?
1159			_hash="$(echo "${_hash}" | awk '{print $1}')"
1160		elif command -v sha256sum > /dev/null 2>&1 ; then
1161			_hash="$($(which sha256sum) "${_file}" 2>/dev/null)"
1162			_exit=$?
1163			_hash="$(echo "${_hash}" | awk '{print $1}')"
1164		fi
1165	else
1166		if command -v md5 > /dev/null 2>&1 ; then
1167			_hash="$($(which md5) "${_file}" 2>/dev/null)"
1168			_exit=$?
1169			_hash="$(echo "${_hash}" | awk -F '=' '{print $2}' | awk '{print $1}')"
1170		elif command -v md5sum > /dev/null 2>&1 ; then
1171			_hash="$($(which md5sum) "${_file}" 2>/dev/null)"
1172			_exit=$?
1173			_hash="$(echo "${_hash}" | awk '{print $1}')"
1174		fi
1175	fi
1176
1177	echo "${_hash}"
1178	return ${_exit}
1179}
1180
1181
1182# Get Operating system independent numerical 4-digit chmod value.
1183#
1184# @param  string	path to file/folder
1185# @output string	numerical chmod (4-digit format)
1186# @return integer	Return code
1187get_file_chmod() {
1188	_file="${1}"
1189	_perm="000"
1190	_exit=1
1191
1192	# e.g. 640
1193	if [ "$(uname)" = "Linux" ]; then
1194		# If no special permissions are set (no sticky bit...), linux will
1195		# only output the 3 digit number
1196		_perm="$(stat --format '%a' "${_file}" 2>/dev/null)"
1197		_exit=$?
1198	else # Darwin or FreeBSD, OpenBSD, NetBSD
1199		_perm="$(stat -f "%Mp%Lp" "${_file}" 2>/dev/null)"
1200		_exit=$?
1201	fi
1202
1203	# For special cases check the length and add a leading 0
1204	_len="$(echo "${_perm}" | awk '{ print length() }')"
1205	if [ "${_len}" = "3" ]; then
1206		_perm="0${_perm}"
1207	fi
1208
1209	echo "${_perm}"
1210	return ${_exit}
1211}
1212
1213
1214# Get Operating system independent owner of file
1215#
1216# @param  string	path to file/folder
1217# @output string	Owner
1218# @return integer	Return code
1219get_file_owner() {
1220	_file="${1}"
1221	_owner="unknown"
1222	_exit=0
1223
1224	# Linux version
1225	if ! _owner="$(stat -c %U "${_file}" 2>/dev/null)"; then
1226		# OSX/BSD version
1227		if ! _owner="$(stat -f %Su "${_file}" 2>/dev/null)"; then
1228			_owner="unknown"
1229			_exit=1
1230		fi
1231	fi
1232
1233	echo "${_owner}"
1234	return ${_exit}
1235}
1236
1237# Get Operating system independent group of file
1238#
1239# @param  string	path to file/folder
1240# @output string	Owner
1241# @return integer	Return code
1242get_file_group() {
1243	_file="${1}"
1244	_group="unknown"
1245	_exit=0
1246
1247	# Linux version
1248	if ! _group="$(stat -c %G "${_file}" 2>/dev/null)"; then
1249		# OSX/BSD version
1250		if ! _group="$(stat -f %Sg "${_file}" 2>/dev/null)"; then
1251			_group="unknown"
1252			_exit=1
1253		fi
1254	fi
1255
1256	echo "${_group}"
1257	return ${_exit}
1258}
1259
1260
1261# Get the real path of a file/folder if it is a symlink
1262#
1263# @param  string	path (file, folder or symlink)
1264# @output string	New path
1265# @return integer	Success
1266get_file_realpath() {
1267	_file="${1}"
1268	_exit=1
1269
1270	_path="$(realpath "${_file}" 2>/dev/null)"
1271	_exit=$?
1272
1273	# If path not found, return the original specified path
1274	if [ "${_exit}" != "0" ]; then
1275		_path="${_file}"
1276	fi
1277
1278	echo "${_path}"
1279	return "${_exit}"
1280}
1281
1282# Create a temporary directory using mktemp
1283#
1284# @param  string	Path where the file should be created
1285# @param  string	Chmod of file
1286# @output string	Full path of the created temp file
1287# @return integer	Success
1288create_tmp_dir() {
1289	_path="${1}"
1290	_chmod="${2}"
1291
1292	umask "$(chmod_2_umask "${_chmod}")";
1293	if ! _dir="$( $(which mktemp) -d "${_path}" 2>/dev/null )"; then
1294		return $?
1295	else
1296		echo "${_dir}"
1297	fi
1298
1299	return 0
1300}
1301
1302
1303# Create a temporary file using mktemp
1304#
1305# @param  string	Path where the file should be created
1306# @param  string	Chmod of file
1307# @output string	Full path of the created temp file
1308# @return integer	Success
1309create_tmp_file() {
1310	_path="${1}"
1311	_chmod="${2}"
1312
1313	umask "$(chmod_2_umask "${_chmod}")";
1314	if ! _file="$( $(which mktemp) "${_path}" 2>/dev/null )"; then
1315		return $?
1316	else
1317		echo "${_file}"
1318	fi
1319
1320	return 0
1321}
1322
1323
1324
1325################################################################################
1326#
1327#  C H M O D   F U N C T I O N S
1328#
1329################################################################################
1330
1331
1332# Validate chmod value.
1333#
1334# @param  string	numerical chmod
1335# @return boolean	0: valid, 1: invalid
1336valid_chmod() {
1337	_chmod="${1}"
1338	_len="$(echo "${_chmod}" | awk '{ print length() }')"
1339
1340
1341	if [ "${_len}" = "3" ]; then
1342
1343		r="$(echo "${_chmod}" | awk '{print substr($0,1,1)}')"
1344		w="$(echo "${_chmod}" | awk '{print substr($0,2,1)}')"
1345		x="$(echo "${_chmod}" | awk '{print substr($0,3,1)}')"
1346
1347
1348		# Check if it is an integer
1349		if ! isint "${r}" > /dev/null 2>&1 ; then
1350			return 1
1351		elif ! isint "${w}" > /dev/null 2>&1 ; then
1352			return 1
1353		elif ! isint "${x}" > /dev/null 2>&1 ; then
1354			return 1
1355		fi
1356
1357		# Error out
1358		if [ "$r" -lt 0 ] || [ "$r" -gt 7 ]; then
1359			return 1
1360		fi
1361		if [ "$w" -lt 0 ] || [ "$w" -gt 7 ]; then
1362			return 1
1363		fi
1364		if [ "$x" -lt 0 ] || [ "$x" -gt 7 ]; then
1365			return 1
1366		fi
1367		# All good
1368		return 0
1369
1370	elif  [ "${_len}" = "4" ]; then
1371
1372		s="$(echo "${_chmod}" | awk '{print substr($0,1,1)}')"
1373		r="$(echo "${_chmod}" | awk '{print substr($0,2,1)}')"
1374		w="$(echo "${_chmod}" | awk '{print substr($0,3,1)}')"
1375		x="$(echo "${_chmod}" | awk '{print substr($0,4,1)}')"
1376
1377		# Check if it is an integer
1378		if ! isint "${s}" > /dev/null 2>&1 ; then
1379			return 1
1380		elif ! isint "${r}" > /dev/null 2>&1 ; then
1381			return 1
1382		elif ! isint "${w}" > /dev/null 2>&1 ; then
1383			return 1
1384		elif ! isint "${x}" > /dev/null 2>&1 ; then
1385			return 1
1386		fi
1387
1388		# Error out
1389		if [ "$s" -lt 0 ] || [ "$s" -gt 7 ]; then
1390			return 1
1391		fi
1392		if [ "$r" -lt 0 ] || [ "$r" -gt 7 ]; then
1393			return 1
1394		fi
1395		if [ "$w" -lt 0 ] || [ "$w" -gt 7 ]; then
1396			return 1
1397		fi
1398		if [ "$x" -lt 0 ] || [ "$x" -gt 7 ]; then
1399			return 1
1400		fi
1401		# All good
1402		return 0
1403
1404	else
1405		# Nope!
1406		return 1
1407	fi
1408}
1409
1410
1411# Compare two chmod values.
1412#
1413# @param  string	numerical chmod (3 or 4 digits)
1414# @param  string	numerical chmod (3 or 4 digits)
1415# @return boolean	0: equals, 1: unequal
1416compare_chmod() {
1417	_chmod1="${1}"
1418	_chmod2="${2}"
1419
1420	_len1="$(echo "${_chmod1}" | awk '{ print length() }')"
1421	_len2="$(echo "${_chmod2}" | awk '{ print length() }')"
1422
1423	if [ "${_len1}" = "${_len2}" ]; then
1424		if [ "${_chmod1}" = "${_chmod2}" ]; then
1425			return 0
1426		else
1427			return 1
1428		fi
1429	elif [ "${_len1}" = "3" ] && [ "${_len2}" = "4" ]; then
1430		if [ "0${_chmod1}" = "${_chmod2}" ]; then
1431			return 0
1432		else
1433			return 1
1434		fi
1435	elif [ "${_len1}" = "4" ] && [ "${_len2}" = "3" ]; then
1436		if [ "${_chmod1}" = "0${_chmod2}" ]; then
1437			return 0
1438		else
1439			return 1
1440		fi
1441	else
1442		return 1
1443	fi
1444}
1445
1446
1447# Convert 3-digit or 4-digit chmod to 3-digit umask
1448#
1449# @param  string	numerical chmod (3 or 4 digit)
1450# @output string	3-digit umask
1451# @return integer	0
1452chmod_2_umask() {
1453	_chmod="${1}"
1454	_len="$(echo "${_chmod}" | awk '{print length()}')"
1455
1456	if [ "${_len}" = "3" ]; then
1457		r=$(echo "${_chmod}" | awk '{print substr($0,1,1)}')
1458		w=$(echo "${_chmod}" | awk '{print substr($0,2,1)}')
1459		x=$(echo "${_chmod}" | awk '{print substr($0,3,1)}')
1460	elif  [ "${_len}" = "4" ]; then
1461		r=$(echo "${_chmod}" | awk '{print substr($0,2,1)}')
1462		w=$(echo "${_chmod}" | awk '{print substr($0,3,1)}')
1463		x=$(echo "${_chmod}" | awk '{print substr($0,4,1)}')
1464	fi
1465
1466	ur="$(sub "7" "${r}")"
1467	uw="$(sub "7" "${w}")"
1468	ux="$(sub "7" "${x}")"
1469
1470	echo "${ur}${uw}${ux}"
1471}
1472
1473
1474
1475
1476################################################################################
1477#
1478#  T M P W A T C H   F U N C T I O N S
1479#
1480################################################################################
1481
1482
1483############################################################
1484# tmpwatch/tmpreaper checker/helper
1485############################################################
1486
1487# Check for correct tmpwatch/tmpreaper value
1488#
1489# @param  string    tmpwatch/tmpreaper deletion value (1, 1m, 1h, 1d)
1490# @return integer   0: success, 1: failure
1491valid_tmpwatch() {
1492	_val="${1}"
1493
1494	# No unit (auto-defaults to hours)
1495	if echo "${_val}" | grep -Eq '^[0-9]+$'; then
1496		if [ "${_val}" -gt 0 ]; then
1497			return 0
1498		fi
1499	# 'm' for minutes
1500	elif echo "${_val}" | grep -Eq '^[0-9]+m$'; then
1501		_num="$(echo "${_val}" | sed 's/m//g')"
1502		if [ "${_num}" -gt 0 ]; then
1503			return 0
1504		fi
1505	# 'h' for hours
1506	elif echo "${_val}" | grep -Eq '^[0-9]+h$'; then
1507		_num="$(echo "${_val}" | sed 's/h//g')"
1508		if [ "${_num}" -gt 0 ]; then
1509			return 0
1510		fi
1511	# 'd' for days
1512	elif echo "${_val}" | grep -Eq '^[0-9]+d$'; then
1513		_num="$(echo "${_val}" | sed 's/d//g')"
1514		if [ "${_num}" -gt 0 ]; then
1515			return 0
1516		fi
1517	fi
1518
1519	# Fuck off
1520	return 1
1521}
1522
1523# Get numerical value for tmpwatch/tmpreaper deletions
1524#
1525# @param  string    tmpwatch/tmpreaper deletion value (1, 1m, 1h, 1d)
1526# @output integer   Value
1527# @return integer	Success
1528get_tmpwatch_value() {
1529	_val="${1}"
1530
1531	# No unit (auto-defaults to hours)
1532	if echo "${_val}" | grep -Eq '^[0-9]+$'; then
1533		echo "${_val}"
1534		return 0
1535	# 'm' for minutes
1536	elif echo "${_val}" | grep -Eq '^[0-9]+m$'; then
1537		echo "${_val}" | sed 's/m//g'
1538		return 0
1539	# 'h' for hours
1540	elif echo "${_val}" | grep -Eq '^[0-9]+h$'; then
1541		echo "${_val}" | sed 's/h//g'
1542		return 0
1543	# 'd' for days
1544	elif echo "${_val}" | grep -Eq '^[0-9]+d$'; then
1545		echo "${_val}" | sed 's/d//g'
1546		return 0
1547	else
1548		echo "Internal Error: [get_tmpwatch_value] Invalid value for \$_val: '${_val}'"
1549		echo "Please report this at github."
1550		exit 1
1551	fi
1552}
1553
1554# Get human readable unit for tmpwatch/tmpreaper deletions (plural or singular)
1555#
1556# @param  string    tmpwatch/tmpreaper deletion value (1, 1m, 1h, 1d)
1557# @return string    Human readable unit
1558get_tmpwatch_unit_name() {
1559	_val="${1}"
1560
1561	# No unit (auto-defaults to hours)
1562	if echo "${_val}" | grep -Eq '^[0-9]+$'; then
1563		if [ "${_val}" -gt 1 ]; then
1564			echo "hours"
1565		else
1566			echo "hour"
1567		fi
1568	# 'm' for minutes
1569	elif echo "${_val}" | grep -Eq '^[0-9]+m$'; then
1570		_num="$(echo "${_val}" | sed 's/m//g')"
1571		if [ "${_num}" -gt 1 ]; then
1572			echo "minutes"
1573		else
1574			echo "minute"
1575		fi
1576	# 'h' for hours
1577	elif echo "${_val}" | grep -Eq '^[0-9]+h$'; then
1578		_num="$(echo "${_val}" | sed 's/h//g')"
1579		if [ "${_num}" -gt 1 ]; then
1580			echo "hours"
1581		else
1582			echo "hour"
1583		fi
1584	# 'd' for days
1585	elif echo "${_val}" | grep -Eq '^[0-9]+d$'; then
1586		_num="$(echo "${_val}" | sed 's/d//g')"
1587		if [ "${_num}" -gt 1 ]; then
1588			echo "days"
1589		else
1590			echo "day"
1591		fi
1592	else
1593		echo "Internal Error: [get_tmpwatch_unit_name] Invalid value for \$_val: '${_val}'"
1594		echo "Please report this at github."
1595		exit 1
1596	fi
1597}
1598
1599
1600
1601################################################################################
1602#
1603#  N A G I O S   F U N C T I O N S
1604#
1605################################################################################
1606
1607
1608# Aggregate nagios exit code.
1609#
1610# OK < Warning < Error < Unknown
1611# @param  integer The current exit code.
1612# @param  integer The new exit code
1613# @output integer The combined exit code
1614# @return integer The combined exit code
1615merge_exit_codes() {
1616	_curr_exit="${1}"
1617	_next_exit="${2}"
1618
1619	# OK
1620	if [ "${_curr_exit}" = "0" ]; then
1621		_curr_exit="${_next_exit}"
1622	# Warning
1623	elif [ "${_curr_exit}" = "1" ]; then
1624		if [ "${_next_exit}" = "0" ]; then
1625			_curr_exit="1"
1626		elif [ "${_next_exit}" = "1" ]; then
1627			_curr_exit="1"
1628		elif [ "${_next_exit}" = "2" ]; then
1629			_curr_exit="2"
1630		elif [ "${_next_exit}" = "3" ]; then # UNKNOWN -> WARNING
1631			_curr_exit="1"
1632		fi
1633	# Error
1634	elif [ "${_curr_exit}" = "2" ]; then
1635		_curr_exit="2"
1636	# Unknown
1637	elif [ "${_curr_exit}" = "3" ]; then
1638		if [ "${_next_exit}" = "0" ]; then
1639			_curr_exit="3"
1640		elif [ "${_next_exit}" = "1" ]; then
1641			_curr_exit="1"
1642		elif [ "${_next_exit}" = "2" ]; then
1643			_curr_exit="2"
1644		elif [ "${_next_exit}" = "3" ]; then # UNKNOWN -> WARNING
1645			_curr_exit="3"
1646		fi
1647	fi
1648	echo "${_curr_exit}"
1649	return ${_curr_exit}
1650}
1651
1652
1653
1654
1655
1656################################################################################
1657#
1658#  M Y S Q L   F U N C T I O N S
1659#
1660################################################################################
1661
1662
1663############################################################
1664# MySQL Connection Helper
1665############################################################
1666
1667
1668# Test if connection to the server is successful.
1669#
1670# @param  string  Credentials file (mysqldump-secure.cnf).
1671# @param  string  SSL connection options.
1672# @output string  Error message
1673# @return integer Success (0: OK | 1: Error)
1674mysql_test_connection() {
1675	_cnf_file="${1}"
1676	_ssl_opts="${2}"
1677	_error=""
1678	_errno=0
1679
1680	# Redirect stderr into stdout and both into variable
1681	_error="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" -e exit 2>&1 )"
1682	_errno=$?
1683
1684	if [ "${_errno}" != "0" ] || [ "${_error}" != "" ]; then
1685		echo "${_error}"
1686		return 1
1687	else
1688		return 0
1689	fi
1690}
1691
1692
1693############################################################
1694# MySQL Server Info Helper
1695############################################################
1696
1697# Get MySQL server status 'status;'
1698#
1699# @param  string  Credentials file (mysqldump-secure.cnf).
1700# @param  string  SSL connection options.
1701# @output string  MySQL 'status;'
1702# @return integer Success (0: OK | 1: Error)
1703get_mysql_server_status() {
1704	_cnf_file="${1}"
1705	_ssl_opts="${2}"
1706	_exit=1
1707
1708	_query="status;"
1709	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1710	_exit=$?
1711
1712	echo "${_result}"
1713	return ${_exit}
1714}
1715
1716# Get MySQL server hostname
1717#
1718# @param  string  Credentials file (mysqldump-secure.cnf).
1719# @param  string  SSL connection options.
1720# @output string  Hostname
1721# @return integer Success (0: OK | 1: Error)
1722get_mysql_server_hostname() {
1723	_cnf_file="${1}"
1724	_ssl_opts="${2}"
1725	_exit=1
1726
1727	_query="SHOW GLOBAL VARIABLES LIKE 'HOSTNAME';"
1728
1729	# Redirect stderr into stdout and both into variable
1730	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1731	_exit=$?
1732
1733	_result="$( echo "${_result}" | tail -n1 | sed 's/hostname[[:space:]]*//g' )"
1734
1735	echo "${_result}"
1736	return ${_exit}
1737}
1738
1739# Get MySQL server port
1740#
1741# @param  string  Credentials file (mysqldump-secure.cnf).
1742# @param  string  SSL connection options.
1743# @output string  Port
1744# @return integer Success (0: OK | 1: Error)
1745get_mysql_server_port() {
1746	_cnf_file="${1}"
1747	_ssl_opts="${2}"
1748	_exit=1
1749
1750	_query="SHOW GLOBAL VARIABLES LIKE 'PORT';"
1751
1752	# Redirect stderr into stdout and both into variable
1753	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1754	_exit=$?
1755
1756	_result="$( echo "${_result}" | tail -n1 | sed 's/port[[:space:]]*//g' )"
1757
1758	echo "${_result}"
1759	return ${_exit}
1760}
1761
1762# Determines wheter the server connected to
1763# is
1764# * a master without replication (single)
1765# * a master with replication (master)
1766# * a slave
1767# * or unknown
1768#
1769# @param  string  Credentials file (mysqldump-secure.cnf).
1770# @param  string  SSL connection options.
1771# @output string  Type (unknown|master|slave)
1772# @return integer Success (0: OK | 1: Error)
1773get_mysql_server_replication_type() {
1774	_cnf_file="${1}"
1775	_ssl_opts="${2}"
1776	_exit=1
1777
1778	_query="select COUNT(1) SlaveThreads from information_schema.processlist where user = 'system user';"
1779	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1780	_exit=$?
1781
1782	_result="$( echo "${_result}" | tail -n1 )"
1783
1784	if [ "${_exit}" != "0" ]; then
1785		echo "unknown"
1786		return ${_exit}
1787	else
1788		if [ "${_result}" = "0" ]; then
1789			echo "master"
1790			return ${_exit}
1791		elif  [ "${_result}" -gt "0" ]; then
1792			echo "slave"
1793			return ${_exit}
1794		else
1795			echo "unknown"
1796			return 1
1797		fi
1798	fi
1799}
1800
1801# Get MySQL Server Version
1802#
1803# @param  string  MySQL server 'status;' output
1804# @output string  Server Version
1805# @return integer 0
1806get_mysql_server_version() {
1807	_mysql_server_status="${1}"
1808
1809	echo "${_mysql_server_status}" | grep -E '^Server version:.*' | sed 's/Server version:[[:space:]]*//g'
1810	return 0
1811}
1812
1813# Get MySQL Server Name (MySQL or MariaDB)
1814#
1815# @param  string  MySQL server 'status;' output
1816# @output string  Server name
1817# @return integer 0
1818get_mysql_server_name() {
1819	_mysql_server_status="${1}"
1820
1821	echo "${_mysql_server_status}" | grep -E '^Server:.*' | sed 's/Server:[[:space:]]*//g'
1822	return 0
1823}
1824
1825
1826############################################################
1827# MySQL Connection Info Helper
1828############################################################
1829
1830# Get MySQL connection info (TCP/IP or Socket)
1831#
1832# @param  string  MySQL server 'status;' output
1833# @output string  Connection type (TCP/IP or Socket)
1834# @return integer 0
1835get_mysql_connection_type_info() {
1836	_mysql_server_status="${1}"
1837
1838	echo "${_mysql_server_status}" | grep -E '^Connection:.*' | sed 's/Connection:[[:space:]]*//g'
1839	return 0
1840}
1841
1842# Get MySQL connection info about SSL status
1843#
1844# @param  string  MySQL server 'status;' output
1845# @output string  SSL Connection info
1846# @return integer 0
1847get_mysql_connection_ssl_info() {
1848	_mysql_server_status="${1}"
1849
1850	echo "${_mysql_server_status}" | grep -E '^SSL:.*' | sed 's/SSL:[[:space:]]*//g'
1851	return 0
1852}
1853
1854
1855
1856############################################################
1857# MySQL Database Helper
1858############################################################
1859
1860
1861# Get all databas names
1862#
1863# @param  string  Credentials file (mysqldump-secure.cnf).
1864# @param  string  SSL connection options.
1865# @output string  All databases (including empty ones)
1866# @return integer Success (0: OK | 1: Error)
1867get_mysql_databases() {
1868	_cnf_file="${1}"
1869	_ssl_opts="${2}"
1870	_exit=1
1871
1872	_query="show databases;"
1873	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1874	_exit=$?
1875
1876	# Only gets databases which have content (tables)
1877	#DATABASES="$( ${MYSQL} --defaults-file="${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" --no-auto-rehash --skip-column-names -e 'SELECT DISTINCT table_schema FROM information_schema.tables;')"
1878
1879	# Remove first column (is sql column name)
1880	_result="$( echo "${_result}" | sed 1d )"
1881
1882	# output all databases on success
1883	if [ "${_exit}" = "0" ]; then
1884		echo "${_result}"
1885	fi
1886
1887	return "${_exit}"
1888}
1889
1890# Get database size in btyes
1891#
1892# @param  string  Credentials file (mysqldump-secure.cnf).
1893# @param  string  SSL connection options.
1894# @output integer Database size in bytes
1895# @return integer Success (0: OK | 1: Error)
1896get_mysql_database_size() {
1897	_cnf_file="${1}"
1898	_ssl_opts="${2}"
1899	_database="${3}"
1900	_exit=1
1901
1902	_query="SELECT SUM(DATA_LENGTH + INDEX_LENGTH) AS Size
1903				FROM INFORMATION_SCHEMA.TABLES
1904				WHERE TABLE_SCHEMA = '${_database}';"
1905
1906
1907	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1908	_exit=$?
1909
1910	_result="$( echo "${_result}" | tail -n1 )"
1911
1912	echo "${_result}"
1913	return ${_exit}
1914}
1915
1916# Determines whether database is empty
1917#
1918# @param  string  Credentials file (mysqldump-secure.cnf).
1919# @param  string  SSL connection options.
1920# @return integer 0: Empty | 1: Not empty
1921mysql_database_is_empty() {
1922	_cnf_file="${1}"
1923	_ssl_opts="${2}"
1924	_database="${3}"
1925
1926
1927	# If a database does not show up in information_schema.tables, it means it
1928	# has no tables yet and is therefore empty.
1929	# If count == 0, return '0', else '1'
1930	_query="SELECT IF(COUNT(*) = 0, '0', '1') AS empty
1931				FROM INFORMATION_SCHEMA.TABLES
1932				WHERE TABLE_SCHEMA = '${_database}';"
1933
1934	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1935	_result="$( echo "${_result}" | tail -n1 )"
1936
1937	return "${_result}"
1938}
1939
1940############################################################
1941# Table Helper Helper
1942############################################################
1943
1944# Count all InnoDB tables
1945#
1946# @param  string  Credentials file (mysqldump-secure.cnf).
1947# @param  string  SSL connection options.
1948# @param  string  Database.
1949count_innodb_tables() {
1950	_cnf_file="${1}"
1951	_ssl_opts="${2}"
1952	_database="${3}"
1953	_exit=1
1954
1955	_query="SELECT COUNT(TABLE_NAME) AS cnt
1956				FROM information_schema.TABLES
1957				WHERE ENGINE = 'InnoDB'
1958				AND TABLE_SCHEMA = '${_database}';"
1959
1960	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1961	_result="$( echo "${_result}" | tail -n1 )"
1962
1963	echo "${_result}"
1964}
1965
1966# Count all InnoDB tables
1967#
1968# @param  string  Credentials file (mysqldump-secure.cnf).
1969# @param  string  SSL connection options.
1970# @param  string  Database.
1971count_non_innodb_tables() {
1972	_cnf_file="${1}"
1973	_ssl_opts="${2}"
1974	_database="${3}"
1975	_exit=1
1976
1977	_query="SELECT COUNT(TABLE_NAME) AS cnt
1978				FROM information_schema.TABLES
1979				WHERE ENGINE <> 'InnoDB'
1980				AND TABLE_SCHEMA = '${_database}';"
1981
1982	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
1983	_result="$( echo "${_result}" | tail -n1 )"
1984
1985	echo "${_result}"
1986}
1987
1988# Count all tables
1989#
1990# @param  string  Credentials file (mysqldump-secure.cnf).
1991# @param  string  SSL connection options.
1992# @param  string  Database.
1993count_total_tables() {
1994	_cnf_file="${1}"
1995	_ssl_opts="${2}"
1996	_database="${3}"
1997	_exit=1
1998
1999	_query="SELECT COUNT(TABLE_NAME) AS cnt
2000				FROM information_schema.TABLES
2001				WHERE TABLE_SCHEMA = '${_database}';"
2002
2003	_result="$( $(which mysql) --defaults-file="${_cnf_file}" "${_ssl_opts}" --batch -e "${_query}" 2>/dev/null)"
2004	_result="$( echo "${_result}" | tail -n1 )"
2005
2006	echo "${_result}"
2007}
2008
2009
2010
2011################################################################################
2012#
2013#  D A T A B A S E   I G N O R E / R E Q U I R E   H E L P E R
2014#
2015################################################################################
2016
2017# Check if the specified database should be ignored
2018# This can either be by the full name or a wildcard with '*'
2019#
2020# @param  string  Ignore list
2021# @param  string  Database name
2022# @output string  Ignore pattern
2023# @return integer 0: ignored, 1: not ignored
2024database_is_ignored() {
2025	_ignore_list="${1}"
2026	_database="${2}"
2027
2028	# Default exit with 1, which means
2029	# it was not found.
2030	_exit=1
2031
2032	# The ignore pattern if it was ignored
2033	_pattern=""
2034
2035	# We need to disable "variable globbing" (set -f) here,
2036	# because if there is only a '*' inside '$IGNORE'
2037	# then
2038	#       'for ign_db in ${IGNORE}; do'
2039	# would list all files in the current directory.
2040	set -f
2041	for _ignore_pattern in ${_ignore_list}; do
2042
2043		# Replace '*' with '.*' to create a regex pattern
2044		_regex="$(echo "${_ignore_pattern}" | sed 's/\*/\.\*/')"
2045
2046		# Check if the pattern matches the complete db name
2047		_found="$(echo "${_database}" | grep -oe "${_regex}")"
2048
2049		if [ "${_found}" = "${_database}" ]; then
2050
2051			# Assign new ignore pattern
2052			_pattern="${_ignore_pattern}"
2053
2054			# Return with 0 to indicate it was found
2055			_exit=0
2056
2057			# Stop the loop
2058			break
2059		fi
2060	done
2061	set +f
2062
2063	echo "${_pattern}"
2064	return ${_exit}
2065}
2066
2067# Check if the specified database is required.
2068#
2069# @param  string  Require list
2070# @param  string  Database name
2071# @return integer 0: required, 1: not required
2072database_is_required() {
2073	_require_list="${1}"
2074	_database="${2}"
2075
2076	# Now check if the ignored db is actually a required db inside $REQUIRE
2077	for _db_required in ${_require_list}; do
2078		# Required database found?
2079		if [ "${_database}" = "${_db_required}" ]; then
2080			# Returning 0 indicates it is required
2081			return 0
2082		fi
2083	done
2084
2085	# Returning invalid return code indicates it is not required
2086	return 1
2087
2088}
2089
2090
2091################################################################################
2092#
2093#  M I S C   F U N C T I O N S
2094#
2095################################################################################
2096
2097
2098
2099
2100# Determine the file extension
2101# based on encrypted/compressed files
2102#
2103# @param  integer _encrypt       Encryption enabled? (0: off | 1: on)
2104# @param  integer _compress      Compression enabled? (0: off | 1: on)
2105# @param  string  _compress_ext  Compression extension (e.g.: gz)
2106# @output string   File extension
2107build_file_extension() {
2108	_encrypt="${1}"
2109	_compress="${2}"
2110	_compress_ext="${3}"
2111
2112	# Get file extension
2113	if [ "${_compress}" = "1" ]; then
2114		if [ "${_encrypt}" = "1" ]; then
2115			echo ".sql.${_compress_ext}.enc"
2116		else
2117			echo ".sql.${_compress_ext}"
2118		fi
2119	else
2120		if [ "${_encrypt}" = "1" ]; then
2121			echo ".sql.enc"
2122		else
2123			echo ".sql"
2124		fi
2125	fi
2126}
2127
2128
2129
2130# Validate mysqldump-secure.cnf file
2131#
2132# The only allowed directives are:
2133#   [client]
2134#   socket =
2135#   host =
2136#   port =
2137#   user =
2138#   password =
2139# "[client]" must also be the first non-commented
2140# directive.
2141#
2142# @param  string  mysqldump-secure.cnf file path
2143# @output string  Error message
2144# @return integer 0: valid | 1: invalid
2145validate_cnf_file() {
2146	_file_path="${1}"
2147
2148	# Get contents
2149	cnf="$(cat "${_file_path}")"
2150
2151	# Remove line comments ('#' and ';')
2152	cnf="$(echo "${cnf}" | sed 's/^[[:space:]]*#.*$//g')"
2153	cnf="$(echo "${cnf}" | sed 's/^[[:space:]]*;.*$//g')"
2154
2155	# Remove empty lines
2156	cnf="$(echo "${cnf}" | sed '/^$/d')"
2157
2158	# Remove leading spaces
2159	cnf="$(echo "${cnf}" | sed 's/^[[:space:]]*//g')"
2160
2161	# Remove trailing spaces
2162	cnf="$(echo "${cnf}" | sed 's/[[:space:]]*$//g')"
2163
2164	IFS='
2165	'
2166	i=0
2167	set -f
2168	for _line in ${cnf}; do
2169		i=$((i + 1))
2170
2171		# Everything before the '=' is the actual directive to check against
2172		# E.g: "host = localhost" results in "host"
2173		_directive="$(echo "${_line}" | awk -F '=' '{print $1}' | sed 's/^[[:space:]]*//g' | sed 's/[[:space:]]*$//g')"
2174
2175		# Check for '[client]' in the first non-commented line
2176		if [ "${i}" = "1" ] && [ "${_line}" != "[client]" ]; then
2177			echo "The first non-commented line must contain a \"[client]\" directive"
2178			return 1
2179		fi
2180
2181		# Only allow the following directives
2182		if  [ "${_directive}" != "[client]" ] &&
2183			[ "${_directive}" != "socket" ] &&
2184			[ "${_directive}" != "host" ] &&
2185			[ "${_directive}" != "port" ] &&
2186			[ "${_directive}" != "user" ] &&
2187			[ "${_directive}" != "password" ]; then
2188			echo "Invalid directive found: \"${_directive}\""
2189			return 1
2190		fi
2191
2192	done
2193	set +f
2194	unset IFS
2195
2196	# All fine, nothing bad found.
2197	return 0
2198}
2199
2200
2201
2202################################################################################
2203#
2204#  M Y S Q L D U M P   F U N CT I O N S
2205#
2206################################################################################
2207
2208# Get mysqldump consistency options based on database and settings.
2209#
2210# @param  integer  Settings for InnoDB only Database
2211# @param  integer  Settings for mixed InnoDB and others Database
2212# @param  integer  Settings for non-InnoDB Database
2213# @param  integer  How many InnoDB tables
2214# @param  integer  How many non-InnoDB tables
2215# @output string   Mysqldump consistency options
2216# @return integer  0
2217get_consistency_opts() {
2218	_consistent_dump_only_innodb="${1}"
2219	_consistent_dump_mixed_innodb="${2}"
2220	_consistent_dump_no_innodb="${3}"
2221	_tbl_cnt_innodb="${4}"
2222	_tbl_cnt_others="${5}"
2223
2224
2225	# Default is to ignore locks completely
2226	_lock_opts="--skip-lock-tables"
2227
2228	#
2229	# Case 1: Only InnoDB Tables
2230	#
2231	if [ "${_tbl_cnt_others}" = "0" ]; then
2232		# Apply consistency to InnoDB
2233		if [ "${_consistent_dump_only_innodb}" = "1" ]; then
2234			_lock_opts="--single-transaction"
2235		else
2236			_lock_opts="--skip-lock-tables"
2237		fi
2238	#
2239	# Case 2: InnoDB + Other Tables
2240	#
2241	elif [ "${_tbl_cnt_innodb}" != "0" ] && [ "${_tbl_cnt_others}" != "0" ]; then
2242		# Apply consistency to InnoDB
2243		if [ "${_consistent_dump_mixed_innodb}" = "1" ]; then
2244			_lock_opts="--lock-tables"
2245		elif [ "${_consistent_dump_mixed_innodb}" = "2" ]; then
2246			_lock_opts="--single-transaction"
2247		else
2248			_lock_opts="--skip-lock-tables"
2249		fi
2250	#
2251	# Case 3: No InnoDB Tables
2252	#
2253	elif [ "${_tbl_cnt_innodb}" = "0" ]; then
2254		# Apply consistency to InnoDB
2255		if [ "${_consistent_dump_no_innodb}" = "1" ]; then
2256			_lock_opts="--lock-tables"
2257		else
2258			_lock_opts="--skip-lock-tables"
2259		fi
2260	#
2261	# Case 4: FALLBACK
2262	#
2263	else
2264		_lock_opts="--skip-lock-tables"
2265	fi
2266
2267	echo "${_lock_opts}"
2268	return 0
2269}
2270
2271# Run the actualy mysqldump here
2272#
2273# @param  integer  Dump mode (0: plain, 1: compressed, 2: encrypted, 3: compressed & encrypted)
2274# @param  string   MySQL connection args (cnf file and SSL arguments)
2275# @param  string   Database name
2276# @param  string   Destination file full path
2277# @param  integer  Destination file chmod
2278# @param  string   Name of compression binary (e.g.: gzip)
2279# @param  string   Compression arguments (e.g.: -9)
2280# @param  string   OpenSSL asymmetric encryption algorithm (e.g.: -aes256)
2281# @param  string   OpenSSL full path to public key file
2282# @param  string   Full path to temporary directory
2283# @output string   Multiline string of pipefail errors/warnings/success
2284# @return integer  0
2285run_mysqldump() {
2286	_dump_mode="${1}"			# 0: plain, 1: compressed, 2: encrypted, 3: compressed & encrypted
2287	_mysql_arg="${2}"			# mysql connection args, ssl and mysqldump arguments
2288	_database="${3}"			# which database to dump
2289	_file_name="${4}"
2290	_file_chmod="${5}"
2291	_compress_bin="${6}"
2292	_compress_arg="${7}"
2293	_openssl_algo="${8}"
2294	_openssl_cert="${9}"
2295	_tmp_dir="${10}"
2296
2297
2298	_error_statuses=""
2299
2300	#
2301	# 0: Plain
2302	#
2303	if [ "${_dump_mode}" = "0" ]; then
2304
2305		# Temp file 'mysqldump'
2306		_err_tmp_file_dump=""
2307		_ern_tmp_file_dump="0"
2308		if ! _tmp_file_dump="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2309			_err_tmp_file_dump="Could not create tmp file in ${_tmp_dir}"
2310			_ern_tmp_file_dump="1"
2311		fi
2312
2313		# Set umask prior writing, so we get the correct chmod just at the time of writing to disk
2314		umask "$(chmod_2_umask "${_file_chmod}")";
2315
2316		# POSIX pipefail emulation
2317		exec 4>&1
2318		# Ignore ${_mysql_arg} to be quoted
2319		# shellcheck disable=SC2086
2320		_error_statuses="$( (
2321			(
2322				$(which mysqldump) ${_mysql_arg} "${_database}" 2> "${_tmp_file_dump}" > "${_file_name}";
2323				printf "%s\n%s\n" \
2324					"0:$?:$(head -n1 "${_tmp_file_dump}")" \
2325					"3:${_ern_tmp_file_dump}:${_err_tmp_file_dump}" >&3;
2326			)
2327		) 3>&1 >&4)"
2328		exec 4>&-
2329
2330		# Delete tmp file
2331		if [ "${_ern_tmp_file_dump}" = "0" ]; then
2332			if [ ! -f "${_tmp_file_dump}" ]; then
2333				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:tmp file does not exist ${_tmp_file_dump}" )"
2334			elif ! rm "${_tmp_file_dump}" 2>/dev/null; then
2335				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:Could not delete tmp file ${_tmp_file_dump}" )"
2336			fi
2337		fi
2338
2339
2340	#
2341	# 1: Compressed
2342	#
2343	elif [ "${_dump_mode}" = "1" ]; then
2344
2345		# Temp file 'mysqldump'
2346		_err_tmp_file_dump=""
2347		_ern_tmp_file_dump="0"
2348		if ! _tmp_file_dump="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2349			_err_tmp_file_dump="Could not create tmp file ${_tmp_dir}"
2350			_ern_tmp_file_dump="1"
2351		fi
2352		# Temp file 'compress'
2353		_err_tmp_file_comp=""
2354		_ern_tmp_file_comp="0"
2355		if ! _tmp_file_comp="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2356			_err_tmp_file_comp="Could not create tmp file ${_tmp_dir}"
2357			_ern_tmp_file_comp="1"
2358		fi
2359
2360		# Set umask prior writing, so we get the correct chmod just at the time of writing to disk
2361		umask "$(chmod_2_umask "${_file_chmod}")";
2362
2363		# POSIX pipefail emulation
2364		exec 4>&1
2365		# Ignore ${_mysql_arg} to be quoted
2366		# shellcheck disable=SC2086
2367		_error_statuses="$( (
2368			(
2369				$(which mysqldump) ${_mysql_arg} "${_database}" 2> "${_tmp_file_dump}";
2370				printf "%s\n%s\n" \
2371					"0:$?:$(head -n1 "${_tmp_file_dump}")" \
2372					"3:${_ern_tmp_file_dump}:${_err_tmp_file_dump}" >&3;
2373			) |
2374			(
2375				${_compress_bin} ${_compress_arg} 2> "${_tmp_file_comp}" > "${_file_name}";
2376				printf "%s\n%s\n" \
2377					"1:$?:$(head -n1 "${_tmp_file_comp}")" \
2378					"4:${_ern_tmp_file_comp}:${_err_tmp_file_comp}" >&3;
2379			)
2380		) 3>&1 >&4)"
2381		exec 4>&-
2382
2383		# Delete tmp file
2384		if [ "${_ern_tmp_file_dump}" = "0" ]; then
2385			if [ ! -f "${_tmp_file_dump}" ]; then
2386				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:tmp file does not exist ${_tmp_file_dump}" )"
2387			elif ! rm "${_tmp_file_dump}" 2>/dev/null; then
2388				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:Could not delete tmp file ${_tmp_file_dump}" )"
2389			fi
2390		fi
2391		# Delete tmp file
2392		if [ "${_ern_tmp_file_comp}" = "0" ]; then
2393			if [ ! -f "${_tmp_file_comp}" ]; then
2394				_error_statuses="$( printf "${_error_statuses}\n%s\n" "7:1:tmp file does not exist ${_tmp_file_comp}" )"
2395			elif ! rm "${_tmp_file_comp}" 2>/dev/null; then
2396				_error_statuses="$( printf "${_error_statuses}\n%s\n" "7:1:Could not delete tmp file ${_tmp_file_comp}" )"
2397			fi
2398		fi
2399
2400
2401	#
2402	# 2: Encrypted
2403	#
2404	elif [ "${_dump_mode}" = "2" ]; then
2405
2406		# Temp file 'mysqldump'
2407		_err_tmp_file_dump=""
2408		_ern_tmp_file_dump="0"
2409		if ! _tmp_file_dump="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2410			_err_tmp_file_dump="Could not create tmp file ${_tmp_dir}"
2411			_ern_tmp_file_dump="1"
2412		fi
2413		# Temp file 'encrypt'
2414		_err_tmp_file_encr=""
2415		_ern_tmp_file_encr="0"
2416		if ! _tmp_file_encr="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2417			_err_tmp_file_encr="Could not create tmp file ${_tmp_dir}"
2418			_ern_tmp_file_encr="1"
2419		fi
2420
2421		# Set umask prior writing, so we get the correct chmod just at the time of writing to disk
2422		umask "$(chmod_2_umask "${_file_chmod}")";
2423
2424		# POSIX pipefail emulation
2425		exec 4>&1
2426
2427		# Ignore ${_mysql_arg} to be quoted
2428		# shellcheck disable=SC2086
2429		_error_statuses="$( (
2430			(
2431				$(which mysqldump) ${_mysql_arg} "${_database}" 2> "${_tmp_file_dump}";
2432				printf "%s\n%s\n" \
2433					"0:$?:$(head -n1 "${_tmp_file_dump}")" \
2434					"3:${_ern_tmp_file_dump}:${_err_tmp_file_dump}" >&3;
2435
2436			) |
2437			(
2438				$(which openssl) smime -encrypt -binary -text -outform DER ${_openssl_algo} -out "${_file_name}" "${_openssl_cert}" 2> "${_tmp_file_encr}";
2439				printf "%s\n%s\n" \
2440					"2:$?:$(head -n1 "${_tmp_file_encr}")" \
2441					"5:${_ern_tmp_file_encr}:${_err_tmp_file_encr}" >&3;
2442			)
2443
2444		) 3>&1 >&4)"
2445		exec 4>&-
2446
2447		# Delete tmp file
2448		if [ "${_ern_tmp_file_dump}" = "0" ]; then
2449			if [ ! -f "${_tmp_file_dump}" ]; then
2450				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:tmp file does not exist ${_tmp_file_dump}" )"
2451			elif ! rm "${_tmp_file_dump}" 2>/dev/null; then
2452				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:Could not delete tmp file ${_tmp_file_dump}" )"
2453			fi
2454		fi
2455		# Delete tmp file
2456		if [ "${_ern_tmp_file_encr}" = "0" ]; then
2457			if [ ! -f "${_tmp_file_encr}" ]; then
2458				_error_statuses="$( printf "${_error_statuses}\n%s\n" "8:1:tmp file does not exist ${_tmp_file_encr}" )"
2459			elif ! rm "${_tmp_file_encr}" 2>/dev/null; then
2460				_error_statuses="$( printf "${_error_statuses}\n%s\n" "8:1:Could not delete tmp file ${_tmp_file_encr}" )"
2461			fi
2462		fi
2463
2464
2465	#
2466	# 3: Compressed & Encrypted
2467	#
2468	elif [ "${_dump_mode}" = "3" ]; then
2469
2470		# Temp file 'mysqldump'
2471		_err_tmp_file_dump=""
2472		_ern_tmp_file_dump="0"
2473		if ! _tmp_file_dump="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2474			_err_tmp_file_dump="Could not create tmp file ${_tmp_dir}"
2475			_ern_tmp_file_dump="1"
2476		fi
2477		# Temp file 'compress'
2478		_err_tmp_file_comp=""
2479		_ern_tmp_file_comp="0"
2480		if ! _tmp_file_comp="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2481			_err_tmp_file_comp="Could not create tmp file ${_tmp_dir}"
2482			_ern_tmp_file_comp="1"
2483		fi
2484		# Temp file 'encrypt'
2485		_err_tmp_file_encr=""
2486		_ern_tmp_file_encr="0"
2487		if ! _tmp_file_encr="$( create_tmp_file "${_tmp_dir}/.dump_XXXXXXXXXXXXXXX" "0600" 2>/dev/null)"; then
2488			_err_tmp_file_encr="Could not create tmp file ${_tmp_dir}"
2489			_ern_tmp_file_encr="1"
2490		fi
2491
2492		# Set umask prior writing, so we get the correct chmod just at the time of writing to disk
2493		umask "$(chmod_2_umask "${_file_chmod}")";
2494
2495		# POSIX pipefail emulation
2496		exec 4>&1
2497		# Ignore ${_mysql_arg} to be quoted
2498		# shellcheck disable=SC2086
2499		_error_statuses="$( (
2500			(
2501				$(which mysqldump) ${_mysql_arg} "${_database}" 2> "${_tmp_file_dump}";
2502				printf "%s\n%s\n" \
2503					"0:$?:$(head -n1 "${_tmp_file_dump}")" \
2504					"3:${_ern_tmp_file_dump}:${_err_tmp_file_dump}" >&3;
2505			) |
2506			(
2507				${_compress_bin} ${_compress_arg} 2> "${_tmp_file_comp}";
2508				printf "%s\n%s\n" \
2509					"1:$?:$(head -n1 "${_tmp_file_comp}")" \
2510					"4:${_ern_tmp_file_comp}:${_err_tmp_file_comp}" >&3;
2511			) |
2512			(
2513				$(which openssl) smime -encrypt -binary -text -outform DER ${_openssl_algo} -out "${_file_name}" "${_openssl_cert}" 2> "${_tmp_file_encr}";
2514				printf "%s\n%s\n" \
2515					"2:$?:$(head -n1 "${_tmp_file_encr}")" \
2516					"5:${_ern_tmp_file_encr}:${_err_tmp_file_encr}" >&3;
2517			)
2518
2519		) 3>&1 >&4)"
2520		exec 4>&-
2521
2522		# Delete tmp file
2523		if [ "${_ern_tmp_file_dump}" = "0" ]; then
2524			if [ ! -f "${_tmp_file_dump}" ]; then
2525				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:tmp file does not exist ${_tmp_file_dump}" )"
2526			elif ! rm "${_tmp_file_dump}" 2>/dev/null; then
2527				_error_statuses="$( printf "${_error_statuses}\n%s\n" "6:1:Could not delete tmp file ${_tmp_file_dump}" )"
2528			fi
2529		fi
2530		# Delete tmp file
2531		if [ "${_ern_tmp_file_comp}" = "0" ]; then
2532			if [ ! -f "${_tmp_file_comp}" ]; then
2533				_error_statuses="$( printf "${_error_statuses}\n%s\n" "7:1:tmp file does not exist ${_tmp_file_comp}" )"
2534			elif ! rm "${_tmp_file_comp}" 2>/dev/null; then
2535				_error_statuses="$( printf "${_error_statuses}\n%s\n" "7:1:Could not delete tmp file ${_tmp_file_comp}" )"
2536			fi
2537		fi
2538		# Delete tmp file
2539		if [ "${_ern_tmp_file_encr}" = "0" ]; then
2540			if [ ! -f "${_tmp_file_encr}" ]; then
2541				_error_statuses="$( printf "${_error_statuses}\n%s\n" "8:1:tmp file does not exist ${_tmp_file_encr}" )"
2542			elif ! rm "${_tmp_file_encr}" 2>/dev/null; then
2543				_error_statuses="$( printf "${_error_statuses}\n%s\n" "8:1:Could not delete tmp file ${_tmp_file_encr}" )"
2544			fi
2545		fi
2546	fi
2547
2548	# Output the error statuses
2549	echo "${_error_statuses}"
2550	return 0
2551}
2552
2553
2554# Evaluate pipefail errors
2555#
2556# @param  string  Multiline pipefail string
2557# @output string  Multiline error messages
2558# @return integer Success
2559mysqldump_pipefail_errors() {
2560	_error_statuses="${1}"
2561
2562	_errors=""
2563	_errno="0"
2564
2565	IFS='
2566	'
2567	for _err in ${_error_statuses}; do
2568		_type="$( echo "${_err}" | awk -F ':' '{print $1}' )"
2569		_exit="$( echo "${_err}" | awk -F ':' '{print $2}' )"
2570		_msg="$(  echo "${_err}" | awk -F ':' '{for (i=3; i<NF; i++) printf $i " "; print $NF}' )"
2571
2572		# ---- dumping
2573		if [ "${_type}" = "0" ]; then
2574			if [ "${_exit}" != "0" ]; then
2575				[ -z "${_errors}" ] && _errors="mysqldump: ${_msg}" || _errors="$( printf "%s\nmysqldump: %s" "${_errors}" "${_msg}")"
2576				_errno=$((_errno + 1))
2577			fi
2578		elif [ "${_type}" = "1" ]; then
2579			if [ "${_exit}" != "0" ]; then
2580				[ -z "${_errors}" ] && _errors="compression: ${_msg}" || _errors="$( printf "%s\ncompression: %s" "${_errors}" "${_msg}")"
2581				_errno=$((_errno + 1))
2582			fi
2583		elif [ "${_type}" = "2" ]; then
2584			if [ "${_exit}" != "0" ]; then
2585				[ -z "${_errors}" ] && _errors="encryption: ${_msg}" || _errors="$( printf "%s\nencryption: %s" "${_errors}" "${_msg}")"
2586				_errno=$((_errno + 1))
2587			fi
2588		# ---- file creation
2589		elif [ "${_type}" = "3" ]; then
2590			if [ "${_exit}" != "0" ]; then
2591				[ -z "${_errors}" ] && _errors="tmpfile creation: ${_msg}" || _errors="$( printf "%s\ntmpfile creation: %s" "${_errors}" "${_msg}")"
2592				_errno=$((_errno + 1))
2593			fi
2594		elif [ "${_type}" = "4" ]; then
2595			if [ "${_exit}" != "0" ]; then
2596				[ -z "${_errors}" ] && _errors="tmpfile creation: ${_msg}" || _errors="$( printf "%s\ntmpfile creation: %s" "${_errors}" "${_msg}")"
2597				_errno=$((_errno + 1))
2598			fi
2599		elif [ "${_type}" = "5" ]; then
2600			if [ "${_exit}" != "0" ]; then
2601				[ -z "${_errors}" ] && _errors="tmpfile creation: ${_msg}" || _errors="$( printf "%s\ntmpfile creation: %s" "${_errors}" "${_msg}")"
2602				_errno=$((_errno + 1))
2603			fi
2604		# ---- file deletion
2605		elif [ "${_type}" = "6" ]; then
2606			if [ "${_exit}" != "0" ]; then
2607				[ -z "${_errors}" ] && _errors="tmpfile deletion: ${_msg}" || _errors="$( printf "%s\ntmpfile deletion: %s" "${_errors}" "${_msg}")"
2608				_errno=$((_errno + 1))
2609			fi
2610		elif [ "${_type}" = "7" ]; then
2611			if [ "${_exit}" != "0" ]; then
2612				[ -z "${_errors}" ] && _errors="tmpfile deletion: ${_msg}" || _errors="$( printf "%s\ntmpfile deletion: %s" "${_errors}" "${_msg}")"
2613				_errno=$((_errno + 1))
2614			fi
2615		elif [ "${_type}" = "8" ]; then
2616			if [ "${_exit}" != "0" ]; then
2617				[ -z "${_errors}" ] && _errors="tmpfile deletion: ${_msg}" || _errors="$( printf "%s\ntmpfile deletion: %s" "${_errors}" "${_msg}")"
2618				_errno=$((_errno + 1))
2619			fi
2620		fi
2621	done
2622	unset IFS
2623
2624	echo "${_errors}"
2625	return ${_errno}
2626}
2627
2628# Evaluate pipefail warnings
2629#
2630# @param  string  Multiline pipefail string
2631# @output string  Multiline warning messages
2632# @return integer Success
2633mysqldump_pipefail_warnings() {
2634	_error_statuses="${1}"
2635
2636	_warnings=""
2637	_errno="0"
2638
2639	IFS='
2640	'
2641	for _err in ${_error_statuses}; do
2642		_type="$( echo "${_err}" | awk -F ':' '{print $1}' )"
2643		_exit="$( echo "${_err}" | awk -F ':' '{print $2}' )"
2644		_msg="$(  echo "${_err}" | awk -F ':' '{for (i=3; i<NF; i++) printf $i " "; print $NF}' )"
2645
2646		# ---- dumping
2647		if [ "${_type}" = "0" ]; then
2648			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2649				[ -z "${_warnings}" ] && _warnings="mysqldump: ${_msg}" || _warnings="$( printf "%s\nmysqldump: %s" "${_warnings}" "${_msg}")"
2650				_errno=$((_errno + 1))
2651			fi
2652		elif [ "${_type}" = "1" ]; then
2653			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2654				[ -z "${_warnings}" ] && _warnings="compression: ${_msg}" || _warnings="$( printf "%s\ncompression: %s" "${_warnings}" "${_msg}")"
2655				_errno=$((_errno + 1))
2656			fi
2657		elif [ "${_type}" = "2" ]; then
2658			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2659				[ -z "${_warnings}" ] && _warnings="encryption: ${_msg}" || _warnings="$( printf "%s\nencryption: %s" "${_warnings}" "${_msg}")"
2660				_errno=$((_errno + 1))
2661			fi
2662		# ---- file creation
2663		elif [ "${_type}" = "3" ]; then
2664			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2665				[ -z "${_warnings}" ] && _warnings="tmpfile creation: ${_msg}" || _warnings="$( printf "%s\ntmpfile creation: %s" "${_warnings}" "${_msg}")"
2666				_errno=$((_errno + 1))
2667			fi
2668		elif [ "${_type}" = "4" ]; then
2669			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2670				[ -z "${_warnings}" ] && _warnings="tmpfile creation: ${_msg}" || _warnings="$( printf "%s\ntmpfile creation: %s" "${_warnings}" "${_msg}")"
2671				_errno=$((_errno + 1))
2672			fi
2673		elif [ "${_type}" = "5" ]; then
2674			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2675				[ -z "${_warnings}" ] && _warnings="tmpfile creation: ${_msg}" || _warnings="$( printf "%s\ntmpfile creation: %s" "${_warnings}" "${_msg}")"
2676				_errno=$((_errno + 1))
2677			fi
2678		# ---- file deletion
2679		elif [ "${_type}" = "6" ]; then
2680			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2681				[ -z "${_warnings}" ] && _warnings="tmpfile deletion: ${_msg}" || _warnings="$( printf "%s\ntmpfile deletion: %s" "${_warnings}" "${_msg}")"
2682				_errno=$((_errno + 1))
2683			fi
2684		elif [ "${_type}" = "7" ]; then
2685			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2686				[ -z "${_warnings}" ] && _warnings="tmpfile deletion: ${_msg}" || _warnings="$( printf "%s\ntmpfile deletion: %s" "${_warnings}" "${_msg}")"
2687				_errno=$((_errno + 1))
2688			fi
2689		elif [ "${_type}" = "8" ]; then
2690			if [ "${_exit}" = "0" ] && [ "${_msg}" != "" ]; then
2691				[ -z "${_warnings}" ] && _warnings="tmpfile deletion: ${_msg}" || _warnings="$( printf "%s\ntmpfile deletion: %s" "${_warnings}" "${_msg}")"
2692				_errno=$((_errno + 1))
2693			fi
2694		fi
2695	done
2696	unset IFS
2697
2698	echo "${_warnings}"
2699	return ${_errno}
2700}
2701
2702
2703
2704#
2705# Write the database dump info file with lot's of
2706# useful information.
2707#
2708write_info_file() {
2709	# File arguments
2710	_file_path="${1}"
2711	_file_name="${2}"
2712	_file_chmod="${3}"
2713	# Database arguments
2714	_db_name="${4}"
2715	_db_size="${5}"
2716	_db_tbl_cnt="${6}"
2717	_db_dump_args="${7}"
2718	_db_dump_time="${8}"
2719	# Compression arguments
2720	_compress_opt="${9}"
2721	_compress_bin="${10}"
2722	_compress_arg="${11}"
2723	# Encryption arguments
2724	_encrypt_opt="${12}"
2725	_encrypt_alg="${13}"
2726	_encrypt_pem="${14}"
2727	# MySQL arguments
2728	_mysql_args="${15}"
2729	_mysql_ssl_opt="${16}"
2730	_mysql_ssl_status="${17}"
2731	# MySQL Server Info arguments
2732	_mysql_server_status="${18}"
2733	_mysql_host="${19}"
2734	_mysql_port="${20}"
2735	_mysql_repl_type="${21}"
2736	_mysql_server="${22}"
2737	_mysql_version="${23}"
2738
2739
2740	_mtime="$( get_file_mtime "${_file_path}/${_file_name}" )"
2741	_mtime_h="$( formatted_timestamp "${_mtime}" "%Y-%m-%d %H:%M:%S %Z [%z]" )"
2742
2743	_db_size_kb="$( div "${_db_size}" "1024" )"
2744	_db_size_mb="$( div "${_db_size_kb}" "1024" )"
2745	_db_size_mb="$( round "${_db_size_mb}" "2" )"
2746
2747	#
2748	# Set umask prior writing.
2749	# (Use the same chmod as the dumps itself)
2750	#
2751	umask "$(chmod_2_umask "${_file_chmod}")";
2752
2753	# Create file
2754	{
2755		echo "; ${INFO_NAME} backup record";
2756		echo "; Do not alter this file!";
2757		echo "; Creation of this file can be turned off via config file.";
2758		echo;
2759		echo "; ============================================================";
2760		echo "; = Local system information";
2761		echo "; ============================================================";
2762		echo "[${INFO_NAME}]";
2763		echo "version    = $( which ${INFO_NAME} ) (${INFO_VERSION})";
2764		echo "vdate      = ${INFO_DATE}";
2765		echo "config     = ${CONFIG_FILE}";
2766		echo;
2767		echo "[system]";
2768		echo "uname      = $( uname -sr )";
2769		echo "hostname   = $( hostname )";
2770		echo "user       = $( whoami )";
2771		echo "group      = $( id -g -n )";
2772		echo;
2773		echo "[tools]";
2774		echo "mysqldump  = $( which mysqldump ) $( _get_version "mysqldump" )";
2775		echo "mysql      = $( which mysql     ) $( _get_version "mysql" )";
2776		echo "compressor = $(if [ "${_compress_opt}" = "1" ]; then echo "$( which "${_compress_bin}" ) $( _get_version "${_compress_bin}" )"; else echo "Not used"; fi)";
2777		echo "encryptor  = $(if [ "${_encrypt_opt}"  = "1" ]; then echo "$( which openssl ) $( _get_version "openssl" )"; else echo "Not used"; fi)";
2778		echo;
2779		echo "; ============================================================";
2780		echo "; = Database / File information";
2781		echo "; ============================================================";
2782		echo "[database]";
2783		echo "db_name    = ${_db_name}";
2784		echo "db_size    = ${_db_size} Bytes (${_db_size_mb} MB)";
2785		echo "tbl_cnt    = ${_db_tbl_cnt}";
2786		echo;
2787		echo "[file]";
2788		echo "file_path  = ${_file_path}";
2789		echo "file_name  = ${_file_name}";
2790		echo "file_size  = $( get_file_size  "${_file_path}/${_file_name}" "b" ) Bytes ($( get_file_size "${_file_path}/${_file_name}" "m" ) MB)";
2791		echo "file_chmod = $( get_file_chmod "${_file_path}/${_file_name}" )";
2792		echo "file_owner = $( get_file_owner "${_file_path}/${_file_name}" )";
2793		echo "file_group = $( get_file_group "${_file_path}/${_file_name}" )";
2794		echo "file_mtime = ${_mtime} (${_mtime_h})";
2795		echo "file_md5   = $( get_file_hash "${_file_path}/${_file_name}" "md5" )";
2796		echo "file_sha   = $( get_file_hash "${_file_path}/${_file_name}" "sha256" )";
2797		echo;
2798		echo "; ============================================================";
2799		echo "; = Dump procedure information";
2800		echo "; ============================================================";
2801		echo "[mysqldump]";
2802		echo "encrypted  = ${_encrypt_opt}";
2803		echo "compressed = ${_compress_opt}";
2804		echo "arguments  = ${_db_dump_args}";
2805		echo "duration   = ${_db_dump_time} sec"
2806		echo;
2807		echo "[compression]";
2808		echo "compressor = $(if [ "${_compress_opt}" = "1" ]; then echo "${_compress_bin}"; fi)";
2809		echo "arguments  = $(if [ "${_compress_opt}" = "1" ]; then echo "${_compress_arg}"; fi)";
2810		echo;
2811		echo "[encryption]";
2812		echo "encryptor  = $(if [ "${_encrypt_opt}" = "1" ]; then echo "openssl"; fi)";
2813		echo "algorithm  = $(if [ "${_encrypt_opt}" = "1" ]; then echo "${_encrypt_alg}"; fi)";
2814		echo "pubkey     = $(if [ "${_encrypt_opt}" = "1" ]; then echo "${_encrypt_pem}"; fi)";
2815		echo;
2816		echo "; ============================================================";
2817		echo "; = Server information";
2818		echo "; ============================================================";
2819		echo "[connection]";
2820		echo "protocol   = $( get_mysql_connection_type_info "${_mysql_server_status}" )";
2821		echo "secured    = $(if [ "${_mysql_ssl_opt}" = "1" ]; then echo "SSL: ${_mysql_ssl_status}"; else echo "No SSL"; fi )";
2822		echo "arguments  = ${_mysql_args}";
2823		echo;
2824		echo "[server]";
2825		echo "hostname   = ${_mysql_host}";
2826		echo "port       = ${_mysql_port}";
2827		echo "replica    = ${_mysql_repl_type}";
2828		echo "version    = $(if [ "${_mysql_server}" != "" ]; then echo "${_mysql_server} ";fi)${_mysql_version}";
2829		echo;
2830	} 2>/dev/null > "${_file_path}/${_file_name}.info"
2831
2832	_exit="$?"
2833
2834	return ${_exit}
2835}
2836
2837
2838
2839################################################################################
2840#
2841#  M I S C   F U N CT I O N S
2842#
2843################################################################################
2844
2845#
2846# Get version information of certain binaries
2847#
2848# @param  string  binary
2849# @output string  Detailed version information
2850# @return integer Success
2851_get_version() {
2852	_tool="${1}"
2853
2854	_version=""
2855	_extra=""
2856	_exit=0
2857
2858	if [ "${_tool}" = "mysqldump" ]; then
2859		_version="$( $(which mysqldump)  --version  | sed 's/.*mysqldump[[:space:]]*Ver[[:space:]]*//' | awk -F ',' '{print $1}' )"
2860		_extra="$( $(which mysqldump) --version  | sed 's/.*mysqldump[[:space:]]*Ver[[:space:]]*//' | awk -F ',' '{print $2}' | sed 's/^[[:space:]]*//g' )"
2861	elif [ "${_tool}" = "mysql" ]; then
2862		_version="$( $(which mysql)  --version  | sed 's/.*mysql[[:space:]]*Ver[[:space:]]*//' | awk -F ',' '{print $1}' )"
2863		_extra="$( $(which mysql) --version  | sed 's/.*mysql[[:space:]]*Ver[[:space:]]*//' | awk -F ',' '{print $2}' | sed 's/^[[:space:]]*//g' )"
2864	elif [ "${_tool}" = "openssl" ]; then
2865		_version="$( $(which openssl)  version  | sed 's/^OpenSSL[[:space:]]*//' )"
2866		_extra=""
2867	elif [ "${_tool}" = "tmpwatch" ]; then
2868		_version="$( $(which tmpwatch) --version 2>&1 | grep -oE 'tmpwatch[[:space:]]+[0-9.]+' | sed 's/tmpwatch[[:space:]]//' )"
2869		_extra=""
2870	elif [ "${_tool}" = "tmpreaper" ]; then
2871		_version="$( $(which tmpreaper) --version 2>&1 | grep -oiE 'tmpreaper.*version.*[0-9.]+' | sed 's/.*Version:[[:space:]]//' )"
2872		_extra=""
2873	elif [ "${_tool}" = "gzip" ]; then
2874		_version="$( $(which gzip) --version 2>&1 | head -n1 )"
2875		_extra=""
2876	elif [ "${_tool}" = "bzip2" ]; then
2877		_version="$( $(which bzip2) --help 2>&1 | head -n1 | sed 's/.*Version[[:space:]]*//' )"
2878		_extra=""
2879	else
2880		_version="Unable to obtain version"
2881		_exit=1
2882	fi
2883
2884	if [ "${_extra}" != "" ]; then
2885		echo "(${_version}) [${_extra}]"
2886	else
2887		echo "(${_version})"
2888	fi
2889
2890	return ${_exit}
2891}
2892
2893
2894
2895
2896################################################################################
2897#
2898#  U S A G E   F U N CT I O N S
2899#
2900################################################################################
2901
2902
2903
2904############################################################
2905# Usage/Help/Version
2906############################################################
2907
2908#
2909# Usage
2910#
2911print_usage() {
2912#	printf "%s %s %s\n" "Usage:" "${INFO_NAME}" "[--conf] [--cnf] [--cron] [-v[v]] [--test] [--info] [--help] [--version]"
2913	printf "%s %s %s\n" "Usage:" "${INFO_NAME}" "[--conf] [--cron] [--test] [-v[v]]"
2914#	printf "%s %s %s\n" "      " "${INFO_NAME}" "--info"
2915	printf "%s %s %s\n" "      " "${INFO_NAME}" "--help"
2916	printf "%s %s %s\n" "      " "${INFO_NAME}" "--version"
2917}
2918
2919#
2920# Display program usage
2921#
2922print_help() {
2923
2924	print_usage
2925	echo
2926	echo "When invoked without any arguments, it will start dumping databases as"
2927	echo "defined in mysqldump-secure.conf."
2928	echo
2929	echo "  --conf          Pass a different configuration file than the default one."
2930	echo "                  E.g.: --conf=/etc/mysqldump-secure-alt.conf"
2931	echo
2932#	echo "  --cnf           Pass different mysql cnf credentials file than the default one."
2933#	echo "                  E.g.: --cnf=/etc/mysqldump-secure-slave.cnf"
2934#	echo
2935	echo "  --cron          Use for cron run. It will only output errors and warnings"
2936	echo "                  and will silence all info, debug and trace output."
2937	echo
2938	echo "  --test          Test requirements and exit."
2939	echo "                  Combine with -v or -vv for more verbose output."
2940	echo
2941	echo "  -v              Show debug output."
2942	echo "                  Can be combined with --conf  and --test"
2943	echo
2944	echo "  -vv             Show debug and trace output."
2945	echo "                  Can be combined with --conf  and --test"
2946	echo
2947#	echo "  --info          Show settings and exit."
2948#	echo
2949	echo "  --help          Show this help screen."
2950	echo
2951	echo "  --version       Show version information."
2952	echo
2953	echo
2954	echo "Exit codes"
2955	echo
2956	echo "  0               All fine, no fatals, no errors and no warnings occured."
2957	echo "  1               Warnings occured, but all dumps were successfull."
2958	echo "  2               Errors occured, but all dumps were successfull."
2959	echo "  3               Failed. Mysqldump encountered errors."
2960	echo "  4               Abort. The program aborted, due to missing requirements,"
2961	echo "                  wrong arguments or a misconfiguration."
2962	echo
2963	echo "Further reading"
2964	echo
2965	echo "See 'man mysqldump-secure' for more help."
2966	echo "Visist http://mysqldump-secure.org and browse documentation."
2967}
2968# TODO:
2969# --------
2970# --info			Shows current configuration and paths
2971# --cli				Start interactive cli (mysqldump-secure-cli) to show dumps, import dumps, set configs, etc
2972
2973
2974
2975#
2976# Display program version and credits
2977#
2978print_version() {
2979	printf "Name:    %s\n" "${INFO_NAME}"
2980	printf "Version: %s (%s)\n" "${INFO_VERSION}" "${INFO_DATE}"
2981	printf "Author:  %s (%s)\n" "${INFO_AUTHOR}" "${INFO_GPGKEY}"
2982	printf "Code:    %s\n" "${INFO_REPO}"
2983	printf "URL:     %s\n" "${INFO_URL}"
2984	printf "License: %s\n" "${INFO_LICENSE}"
2985}
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995####################################################################################################
2996####################################################################################################
2997##
2998##  M A I N   E N T R Y   P O I N T  ( A R G U M E N T S )
2999##
3000####################################################################################################
3001####################################################################################################
3002
3003
3004
3005################################################################################
3006#
3007# COMMAND LINE ARGUMENTS
3008#
3009################################################################################
3010
3011############################################################
3012# 1.) Evaluate cmd arguments
3013############################################################
3014
3015
3016_ARG_CONF="0"	# Different config file specified?
3017_ARG_VERB="1"	# Verbose mode?
3018_ARG_CRON="0"	# Cron mode?
3019_ARG_TEST="0"	# Test mode?
3020_ARG_HELP="0"	# Show help?
3021_ARG_VERS="0"	# Show version?
3022
3023_CUS_CONF=""	# Where is the custom config?
3024#_ARG_INFO="0"
3025
3026
3027#
3028# Loop over command line arguments
3029#
3030while [ $# -gt 0  ]; do
3031	case "$1" in
3032
3033		--conf=*)
3034			if [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERS}" = "1" ]; then
3035				echo "Invalid. Arguments cannot be mixed." 1>&2
3036				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3037				exit $EXIT_ABORT
3038			fi
3039			if [ "${_ARG_CONF}" != "0" ]; then
3040				echo "Invalid. Argument '--conf' already specified." 1>&2
3041				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3042				exit $EXIT_ABORT
3043			fi
3044			_ARG_CONF="1"
3045			_CUS_CONF="$(echo "$1" | sed 's/--conf=//g')"
3046			;;
3047
3048
3049		-v)
3050			if [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERS}" = "1" ] || [ "${_ARG_CRON}" = "1" ]; then
3051				echo "Invalid. Arguments cannot be mixed." 1>&2
3052				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3053				exit $EXIT_ABORT
3054			fi
3055			if [ "${_ARG_VERB}" != "1" ]; then
3056				echo "Invalid. Argument '-v' already specified (use -vv for more verbosity)." 1>&2
3057				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3058				exit $EXIT_ABORT
3059			fi
3060			_ARG_VERB="2"
3061			;;
3062
3063
3064		-vv)
3065			if [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERS}" = "1" ] || [ "${_ARG_CRON}" = "1" ]; then
3066				echo "Invalid. Arguments cannot be mixed." 1>&2
3067				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3068				exit $EXIT_ABORT
3069			fi
3070			if [ "${_ARG_VERB}" != "1" ]; then
3071				echo "Invalid. Argument '-v' already specified (use -vv for more verbosity)." 1>&2
3072				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3073				exit $EXIT_ABORT
3074			fi
3075			_ARG_VERB="3"
3076			;;
3077
3078
3079		--cron)
3080			if [ "${_ARG_TEST}" = "1" ] || [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERS}" = "1" ] || [ "${_ARG_VERB}" != "1" ]; then
3081				echo "Invalid. Arguments cannot be mixed." 1>&2
3082				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3083				exit $EXIT_ABORT
3084			fi
3085			if [ "${_ARG_CRON}" != "0" ]; then
3086				echo "Invalid. Argument '--cron' already specified." 1>&2
3087				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3088				exit $EXIT_ABORT
3089			fi
3090			_ARG_CRON="1"
3091			;;
3092
3093
3094		--test)
3095			if [ "${_ARG_CRON}" = "1" ] || [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERS}" = "1" ]; then
3096				echo "Invalid. Arguments cannot be mixed." 1>&2
3097				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3098				exit $EXIT_ABORT
3099			fi
3100			if [ "${_ARG_TEST}" != "0" ]; then
3101				echo "Invalid. Argument '--test' already specified." 1>&2
3102				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3103				exit $EXIT_ABORT
3104			fi
3105			_ARG_TEST="1"
3106			;;
3107
3108#		--info)
3109#			_ARG_INFO="1"
3110#			;;
3111
3112
3113		--help)
3114			if [ "${_ARG_CONF}" = "1" ] || [ "${_ARG_CRON}" = "1" ] || [ "${_ARG_TEST}" = "1" ] || [ "${_ARG_VERS}" = "1" ] || [ "${_ARG_VERB}" != "1" ]; then
3115				echo "Invalid. Arguments cannot be mixed." 1>&2
3116				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3117				exit $EXIT_ABORT
3118			fi
3119			if [ "${_ARG_HELP}" != "0" ]; then
3120				echo "Invalid. Argument '--help' already specified." 1>&2
3121				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3122				exit $EXIT_ABORT
3123			fi
3124			_ARG_HELP="1"
3125			print_help
3126			exit 0
3127			;;
3128
3129
3130		--version)
3131			if [ "${_ARG_CONF}" = "1" ] || [ "${_ARG_CRON}" = "1" ] || [ "${_ARG_TEST}" = "1" ] || [ "${_ARG_HELP}" = "1" ] || [ "${_ARG_VERB}" != "1" ]; then
3132				echo "Invalid. Arguments cannot be mixed." 1>&2
3133				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3134				exit $EXIT_ABORT
3135			fi
3136			if [ "${_ARG_VERS}" != "0" ]; then
3137				echo "Invalid. Argument '--versopm' already specified." 1>&2
3138				echo "Type '${INFO_NAME} --help' for available options." 1>&2
3139				exit $EXIT_ABORT
3140			fi
3141			_ARG_VERS="1"
3142			print_version
3143			exit 0
3144			;;
3145
3146
3147		*)
3148			echo "Invalid argument: '${1}'." 1>&2
3149			echo "Type '${INFO_NAME} --help' for available options." 1>&2
3150			exit $EXIT_ABORT
3151			;;
3152
3153	esac
3154	shift
3155done
3156
3157
3158#
3159# Set output verbosity
3160#
3161if [ "${_ARG_CRON}" = "1" ]; then
3162	OUT_VERBOSITY="0" # only show fatals, errors and warnings
3163else
3164	OUT_VERBOSITY="${_ARG_VERB}"	# 1, 2 or 3
3165fi
3166
3167
3168#
3169# Set file verbosity (default is off)
3170#
3171LOG_VERBOSITY="0"
3172
3173
3174#
3175# Use default config or user specified config file
3176#
3177if [ -z "${_CUS_CONF-}" ]; then
3178	CONFIG_FILE="${_DEFAULT_CONFIG_FILE}"
3179else
3180	CONFIG_FILE="${_CUS_CONF}"
3181fi
3182
3183
3184############################################################
3185# 2.) Validate config file location/rights
3186############################################################
3187
3188if [ ! -f "${CONFIG_FILE}" ]; then
3189	debug "fatal" "(RUN): Configuration file not found in ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3190	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3191	exit $EXIT_ABORT
3192fi
3193if [ -L "${CONFIG_FILE}" ]; then
3194	if _TMP="$(get_file_realpath "${CONFIG_FILE}")" >/dev/null 2>&1; then
3195		debug "trace" "(RUN): \$CONFIG_FILE is a symlink. Setting target to: ${_TMP}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3196		CONFIG_FILE="${_TMP}"
3197	else
3198		debug "fatal" "(RUN): Cannot resolve symlink of: $CONFIG_FILE" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3199		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3200		exit $EXIT_ABORT
3201	fi
3202fi
3203if [ ! -r "${CONFIG_FILE}" ]; then
3204	debug "fatal" "(RUN): Configuration file is not readable in ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3205	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3206	exit $EXIT_ABORT
3207fi
3208if ! compare_chmod "$(get_file_chmod "${CONFIG_FILE}")" "${_DEFAULT_CONFIG_CHMOD}" > /dev/null 2>&1 ; then
3209	debug    "warn" "(RUN): Configuration file ${CONFIG_FILE} has dangerous permissions: $(get_file_chmod "${CONFIG_FILE}"), should be: ${_DEFAULT_CONFIG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3210	debug_pi "warn" "(RUN): Trying to chmod to ${_DEFAULT_CONFIG_CHMOD}..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3211	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3212
3213	if ! chmod ${_DEFAULT_CONFIG_CHMOD} "${CONFIG_FILE}" > /dev/null 2>&1 ; then
3214		debug_i "fatal" "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3215		debug   "fatal" "Failed to chmod ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3216		debug   "fatal" "Fix it manually to ${_DEFAULT_CONFIG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3217		debug   "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3218		exit $EXIT_ABORT
3219	else
3220		debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3221	fi
3222fi
3223
3224
3225
3226# Read config file
3227# Comment required by shellcheck,
3228# See problem here: https://github.com/koalaman/shellcheck/wiki/SC1090
3229# shellcheck disable=SC1090
3230#
3231# TODO: Manually parse the file via sed or awk to be safer
3232. "${CONFIG_FILE}"
3233
3234
3235
3236
3237
3238
3239
3240####################################################################################################
3241####################################################################################################
3242##
3243##  M A I N   E N T R Y   P O I N T   ( E R R O R   C H E C K I N G )
3244##
3245####################################################################################################
3246####################################################################################################
3247
3248
3249
3250
3251################################################################################
3252#
3253# EVALUATE CONFIG FILE
3254#
3255################################################################################
3256
3257
3258############################################################
3259# Logging Options
3260############################################################
3261
3262# Be really strict on checking if we are going to log to file
3263# or not. Also make sure that the logfile is writeable and
3264# that no other has read permissions to the file.
3265if ! set | grep '^LOG=' >/dev/null 2>&1; then
3266	debug "warn" "(CFG): \$LOG variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3267	debug "warn" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3268	LOG=0
3269	LOG_FILE=""
3270	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3271elif [ -z "${LOG}" ]; then
3272	debug "warn" "(CFG): \$LOG variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3273	debug "warn" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3274	LOG=0
3275	LOG_FILE=""
3276	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3277elif [ "${LOG}" = "1" ] || [ "${LOG}" = "2" ] || [ "${LOG}" = "3" ]; then
3278
3279	# Check chmod variable
3280	if ! set | grep '^LOG_CHMOD=' >/dev/null 2>&1; then
3281		debug "warn" "(CFG): \$LOG_CHMOD variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3282		debug "warn" "(CFG): Setting default to: ${_DEFAULT_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3283		LOG_CHMOD="${_DEFAULT_LOG_CHMOD}"
3284		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3285	elif [ -z "${LOG_CHMOD}" ]; then
3286		debug "warn" "(CFG): \$LOG_CHMOD variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3287		debug "warn" "(CFG): Setting default to: ${_DEFAULT_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3288		LOG_CHMOD="${_DEFAULT_LOG_CHMOD}"
3289		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3290	elif ! valid_chmod "${LOG_CHMOD}" > /dev/null 2>&1; then
3291		debug "warn" "(CFG): Invalid value for \$LOG_CHMOD: ${LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3292		debug "warn" "(CFG): Setting default to: ${_DEFAULT_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3293		LOG_CHMOD="${_DEFAULT_LOG_CHMOD}"
3294		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3295	fi
3296
3297	# Check logfile variable
3298	if ! set | grep '^LOG_FILE=' >/dev/null 2>&1; then
3299		debug "warn" "(CFG): \$LOG_FILE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3300		debug "warn" "(OPT): Setting default to: ${_DEFAULT_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3301		LOG_FILE="${_DEFAULT_LOG_FILE}"
3302		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3303	elif [ -z "${LOG_FILE}" ]; then
3304		debug "warn" "(CFG): \$LOG_FILE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3305		debug "warn" "(OPT): Setting default to: ${_DEFAULT_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3306		LOG_FILE="${_DEFAULT_LOG_FILE}"
3307		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3308	fi
3309
3310	# Resolve symlink?
3311	if [ -L "${LOG_FILE}" ]; then
3312		if _TMP="$(get_file_realpath "${LOG_FILE}")" >/dev/null 2>&1; then
3313			debug "trace" "(RUN): \$LOG_FILE is a symlink. Setting target to: ${_TMP}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3314			LOG_FILE="${_TMP}"
3315		else
3316			debug "err" "(RUN): Cannot resolve symlink of: $LOG_FILE" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3317			debug "err" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3318			LOG=0
3319			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3320		fi
3321	fi
3322
3323	# Check if logfile exists
3324	if [ ! -f "${LOG_FILE}" ]; then
3325		# Check if logging directory exists
3326		if [ ! -d "$(dirname "${LOG_FILE}")" ]; then
3327			debug    "warn" "(RUN): Log directory does not exist in $(dirname "${LOG_FILE}")" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3328			debug_pi "warn" "(RUN): Trying to create..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3329			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3330			if ! mkdir -p "$(dirname "${LOG_FILE}")" > /dev/null 2>&1 ; then
3331				debug_i "err" "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3332				debug   "err" "(RUN): Failed to create directoy: $(dirname "${LOG_FILE}")" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3333				debug   "err" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3334				LOG=0
3335				MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3336			else
3337				debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3338			fi
3339		fi
3340		# If logging is still OK (dir exists), check if the file can be created
3341		if [ "${LOG}" != "0" ]; then
3342			debug    "warn" "(RUN): Log file does not exist in ${LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3343			debug_pi "warn" "(RUN): Trying to create..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3344			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3345
3346			if ! touch "${LOG_FILE}" > /dev/null 2>&1 ; then
3347				debug_i "err"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3348				debug   "err"  "(RUN): Failed to create file: ${LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3349				debug   "err"  "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3350				LOG=0
3351				MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3352			else
3353				debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3354			fi
3355		fi
3356	fi
3357
3358	# Logging still on?
3359	# Check for permissions
3360	if [ "${LOG}" != "0" ]; then
3361		if ! compare_chmod "$(get_file_chmod "${LOG_FILE}")" "${LOG_CHMOD}" > /dev/null 2>&1 ; then
3362			debug    "warn" "(RUN): Log file has wrong permissions: $(get_file_chmod "${LOG_FILE}"), should be: ${LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3363			debug_pi "warn" "(RUN): Trying to chmod to ${LOG_CHMOD}..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3364			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3365
3366			if ! chmod ${LOG_CHMOD} "${LOG_FILE}" > /dev/null 2>&1 ; then
3367				debug_i "err"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3368				debug   "err"  "(RUN): Failed to chmod ${LOG_CHMOD} ${LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3369				debug   "err"  "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3370				LOG=0
3371				MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3372			else
3373				debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3374			fi
3375		fi
3376	fi
3377
3378	# Logging still on?
3379	# Check if it is writeable
3380	if [ "${LOG}" != "0" ]; then
3381
3382		# Logfile not writeable
3383		if [ ! -w "${LOG_FILE}" ]; then
3384			debug  "err" "(RUN): Log file ${LOG_FILE} not writeable. Check \$LOG_CHMOD value inf config." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3385			debug  "err" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3386			LOG=0
3387			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3388		fi
3389	fi
3390elif [ "${LOG}" = "0" ]; then
3391	debug "info" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3392	LOG_FILE=""
3393else
3394	debug "warn" "(CFG): Invalid value for \$LOG: ${LOG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3395	debug "warn" "(OPT): Logging disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" ""
3396	LOG=0
3397	LOG_FILE=""
3398	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3399fi
3400
3401# Is logging still enabled after all checks?
3402# Write to the file
3403if [ "${LOG}" != "0" ]; then
3404
3405	# Assign new value for logging verbosity
3406	LOG_VERBOSITY="${LOG}"
3407
3408	{
3409		echo;
3410		echo "--------------------------------------------------------------------------------";
3411		echo "$(date '+%Y-%m-%d') $(date '+%H:%M:%S') Starting";
3412	} >> "${LOG_FILE}"
3413	debug "debug" "(CFG): Using config: ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3414	debug "info"  "(OPT): Logging enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3415	debug "debug" "(OPT): Log level: ${LOG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3416	debug "debug" "(OPT): Log file: ${LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3417else
3418	debug "debug" "(CFG): Using config: ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3419fi
3420
3421
3422
3423
3424
3425############################################################
3426# Command line arguments
3427############################################################
3428if [ "${_ARG_CRON}" = "1" ]; then
3429	# Note: This will never be outputted to stdout/stderr (only to logfile)
3430	debug "trace" "(ARG): Running in cron mode (--cron)." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3431fi
3432if [ "${_ARG_TEST}" = "1" ]; then
3433	debug "info" "(ARG): Running in test mode (--test)." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3434fi
3435if [ "${_ARG_VERB}" = "1" ]; then
3436	debug "trace" "(ARG): Running in verbose mode (--verbose)." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3437fi
3438#if [ "${_ARG_INFO}" = "1" ]; then
3439#	debug "info" "Showing information only (--info)."  "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3440#fi
3441
3442
3443
3444############################################################
3445# Tmp folder
3446############################################################
3447
3448
3449# Check if mktemp exits
3450if ! command -v mktemp > /dev/null 2>&1 ; then
3451	debug "fatal" "(RUN): 'mktemp' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3452	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3453	exit $EXIT_ABORT
3454fi
3455
3456# Check $TMP_DIR variable
3457if ! set | grep '^TMP_DIR=' >/dev/null 2>&1; then
3458	debug "warn" "(CFG): \$TMP_DIR variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3459	debug "warn" "(CFG): Setting default to: ${_DEFAULT_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3460	TMP_DIR=${_DEFAULT_TMP_DIR}
3461	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3462elif [ -z "${TMP_DIR}" ]; then
3463	debug "warn" "(CFG): \$TMP_DIR variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3464	debug "warn" "(CFG): Setting default to: ${_DEFAULT_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3465	TMP_DIR=${_DEFAULT_TMP_DIR}
3466	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3467fi
3468
3469# Check directory
3470if [ ! -d "${TMP_DIR}" ]; then
3471	debug "fatal" "(CFG): \$TMP_DIR is not a directory: ${TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3472	debug "fatal" "(HLP): Change value of \$TMP_DIR in your config" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3473	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3474	exit $EXIT_ABORT
3475elif [ ! -w "${TMP_DIR}" ]; then
3476	debug "fatal" "(CFG): \$TMP_DIR is not writeable" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3477	debug "fatal" "(HLP): Change value of \$TMP_DIR in your config" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3478	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3479	exit $EXIT_ABORT
3480fi
3481debug "trace" "(CFG): Using temporary directory: ${TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3482
3483
3484
3485
3486############################################################
3487# Destination Directory and Prefix
3488############################################################
3489
3490# Check $DUMP_DIR_CHMOD
3491if ! set | grep '^DUMP_DIR_CHMOD=' >/dev/null 2>&1; then
3492	debug "warn" "(CFG): \$DUMP_DIR_CHMOD variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3493	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_DIR_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3494	DUMP_DIR_CHMOD=${_DEFAULT_DUMP_DIR_CHMOD}
3495	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3496elif [ -z "${DUMP_DIR_CHMOD}" ]; then
3497	debug "warn" "(CFG): \$DUMP_DIR_CHMOD variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3498	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_DIR_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3499	DUMP_DIR_CHMOD=${_DEFAULT_DUMP_DIR_CHMOD}
3500	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3501elif ! valid_chmod "${DUMP_DIR_CHMOD}" > /dev/null 2>&1; then
3502	debug "warn" "(CFG): Invalid value for \$DUMP_DIR_CHMOD: ${DUMP_DIR_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3503	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_DIR_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3504	DUMP_DIR_CHMOD="${_DEFAULT_DUMP_DIR_CHMOD}"
3505	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3506fi
3507
3508# Check $DUMP_FILE_CHMOD
3509if ! set | grep '^DUMP_FILE_CHMOD=' >/dev/null 2>&1; then
3510	debug "warn" "(CFG): \$DUMP_FILE_CHMOD variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3511	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_FILE_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3512	DUMP_FILE_CHMOD=${_DEFAULT_DUMP_DIR_CHMOD}
3513	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3514elif [ -z "${DUMP_FILE_CHMOD}" ]; then
3515	debug "warn" "(CFG): \$DUMP_FILE_CHMOD variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3516	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_FILE_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3517	DUMP_FILE_CHMOD=${_DEFAULT_DUMP_DIR_CHMOD}
3518	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3519elif ! valid_chmod "${DUMP_FILE_CHMOD}" > /dev/null 2>&1; then
3520	debug "warn" "(CFG): Invalid value for \$DUMP_FILE_CHMOD: ${DUMP_FILE_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3521	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_FILE_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3522	DUMP_FILE_CHMOD="${_DEFAULT_DUMP_DIR_CHMOD}"
3523	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3524fi
3525
3526# Check $DUMP_DIR
3527if ! set | grep '^DUMP_DIR=' >/dev/null 2>&1; then
3528	debug "warn" "(CFG): \$DUMP_DIR variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3529	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3530	DUMP_DIR=${_DEFAULT_DUMP_DIR}
3531	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3532elif [ -z "${DUMP_DIR}" ]; then
3533	debug "warn" "(CFG): \$DUMP_DIR variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3534	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3535	DUMP_DIR=${_DEFAULT_DUMP_DIR}
3536	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3537fi
3538
3539# Resolve symlink?
3540if [ -L "${DUMP_DIR}" ]; then
3541	if _TMP="$(get_file_realpath "${DUMP_DIR}")" >/dev/null 2>&1; then
3542		debug "trace" "(RUN): \$DUMP_DIR is a symlink. Setting target to: ${_TMP}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3543		DUMP_DIR="${_TMP}"
3544	else
3545		debug "fatal" "(RUN): Cannot resolve symlink of: $DUMP_DIR" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3546		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3547		exit $EXIT_ABORT
3548	fi
3549fi
3550
3551if [ ! -d "${DUMP_DIR}" ]; then
3552	debug    "warn" "(RUN): Destination dir does not exist: ${DUMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3553	debug_pi "warn" "(RUN): Trying to create... " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3554	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3555
3556	if ! mkdir -p "${DUMP_DIR}" > /dev/null 2>&1 ; then
3557		debug_i "fatal"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3558		debug   "fatal"  "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3559		exit $EXIT_ABORT
3560	else
3561		debug_i  "warn" "Done\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3562		debug_pi "warn" "(RUN): Trying to chmod to: ${DUMP_DIR_CHMOD}..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3563		if ! chmod ${DUMP_DIR_CHMOD} "${DUMP_DIR}" >/dev/null 2>&1; then
3564			debug_i "fatal"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3565			debug   "fatal"  "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3566			exit $EXIT_ABORT
3567		else
3568			debug_i "warn" "Done\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3569		fi
3570	fi
3571fi
3572
3573# Check correct permissions of destination dir
3574if ! compare_chmod "$(get_file_chmod "${DUMP_DIR}")" "${DUMP_DIR_CHMOD}" > /dev/null 2>&1 ; then
3575	debug    "warn" "(RUN): Destination dir has wrong permissions: $(get_file_chmod "${DUMP_DIR}"), but should ${DUMP_DIR_CHMOD}." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3576	debug_pi "warn" "(RUN): Trying to chmod to ${DUMP_DIR_CHMOD}... " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3577	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3578
3579	if ! chmod "${DUMP_DIR_CHMOD}" "${DUMP_DIR}" > /dev/null 2>&1 ; then
3580		debug_i "fatal" "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3581		debug   "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3582		exit $EXIT_ABORT
3583	else
3584		debug_i "warn" "Done\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3585	fi
3586fi
3587# Check if destination dir is writeable
3588if [ ! -w "${DUMP_DIR}" ]; then
3589	debug "fatal" "(RUN): Destination dir ${DUMP_DIR} is not writeable" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3590	debug "fatal" "(HLP): Fix your configured permissions" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3591	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3592	exit $EXIT_ABORT
3593fi
3594
3595# Show information
3596debug "debug" "(CFG): Destination dir: ${DUMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3597
3598
3599# Check $DUMP_FILE_PRE
3600if ! set | grep '^DUMP_FILE_PRE=' >/dev/null 2>&1; then
3601	debug "warn" "(CFG): \$DUMP_FILE_PRE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3602	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_FILE_PRE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3603	DUMP_FILE_PRE=${_DEFAULT_DUMP_FILE_PRE}
3604	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3605elif [ -z "${DUMP_FILE_PRE}" ]; then
3606	debug "warn" "(CFG): \$DUMP_FILE_PRE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3607	debug "warn" "(CFG): Setting default to: ${_DEFAULT_DUMP_FILE_PRE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3608	DUMP_FILE_PRE=${_DEFAULT_DUMP_FILE_PRE}
3609	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3610fi
3611
3612# Show information
3613debug "debug" "(CFG): Using file Prefix: ${DUMP_FILE_PRE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3614
3615
3616
3617############################################################
3618# MySQL
3619############################################################
3620
3621# Check Binaries
3622if ! command -v mysql > /dev/null 2>&1 ; then
3623	debug "fatal" "(RUN): 'mysql' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3624	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3625	exit $EXIT_ABORT
3626fi
3627if ! command -v mysqldump > /dev/null 2>&1 ; then
3628	debug "fatal" "(RUN): 'mysqldump' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3629	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3630	exit $EXIT_ABORT
3631fi
3632
3633# Check $MYSQL_CNF_FILE
3634if ! set | grep '^MYSQL_CNF_FILE=' >/dev/null 2>&1; then
3635	debug "fatal" "(CFG): \$MYSQL_CNF_FILE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3636	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3637	exit $EXIT_ABORT
3638elif [ -z "${MYSQL_CNF_FILE}" ]; then
3639	debug "fatal" "(CFG): \$MYSQL_CNF_FILE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3640	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3641	exit $EXIT_ABORT
3642fi
3643
3644# Resolve symlink?
3645if [ -L "${MYSQL_CNF_FILE}" ]; then
3646	if _TMP="$(get_file_realpath "${MYSQL_CNF_FILE}")" >/dev/null 2>&1; then
3647		debug "trace" "(RUN): \$MYSQL_CNF_FILE is a symlink. Setting target to: ${_TMP}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3648		MYSQL_CNF_FILE="${_TMP}"
3649	else
3650		debug "fatal" "(RUN): Cannot resolve symlink of: $MYSQL_CNF_FILE" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3651		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3652		exit $EXIT_ABORT
3653	fi
3654fi
3655
3656# Check access and chmod
3657if [ ! -f "${MYSQL_CNF_FILE}" ]; then
3658	debug "fatal" "(RUN): MySQL CNF file not found: ${MYSQL_CNF_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3659	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3660	exit $EXIT_ABORT
3661elif [ ! -r "${MYSQL_CNF_FILE}" ]; then
3662	debug "fatal" "(RUN): MySQL CNF file is not readable: ${MYSQL_CNF_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3663	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3664	exit $EXIT_ABORT
3665elif ! compare_chmod "$(get_file_chmod "${MYSQL_CNF_FILE}")" "${_DEFAULT_MYSQL_CNF_CHMOD}" > /dev/null 2>&1 ; then
3666	debug "fatal" "(RUN): MySQL CNF file has dangerous permissions: $(get_file_chmod "${MYSQL_CNF_FILE}")." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3667	debug "fatal" "(HLP): Fix it to ${_DEFAULT_MYSQL_CNF_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3668	debug "fatal" "(HLP): If you are not alone on the machine, the password inside could have been compromised by now." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3669	debug "fatal" "(HLP): If so, change your database password." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3670	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3671	exit $EXIT_ABORT
3672fi
3673
3674# Validate contents
3675if ! _MSG="$(validate_cnf_file "${MYSQL_CNF_FILE}")"; then
3676	debug "fatal" "(RUN): Invalid cnf file." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3677	debug "fatal" "(HLP): ${_MSG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3678	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3679	exit $EXIT_ABORT
3680fi
3681
3682
3683
3684# Check MYSQL_SSL_ENABLE
3685if ! set | grep '^MYSQL_SSL_ENABLE=' >/dev/null 2>&1; then
3686	debug "fatal" "(CFG): \$MYSQL_SSL_ENABLE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3687	debug "fatal" "(HLP): It is not clear whether or not you only allow secure connections." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3688	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3689	exit $EXIT_ABORT
3690elif [ -z "${MYSQL_SSL_ENABLE}" ]; then
3691	debug "fatal" "(CFG): \$MYSQL_SSL_ENABLE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3692	debug "fatal" "(HLP): It is not clear whether or not you only allow secure connections." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3693	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3694	exit $EXIT_ABORT
3695elif [ "${MYSQL_SSL_ENABLE}" = "1" ]; then
3696	if ! set | grep '^MYSQL_SSL_CA_PEM=' >/dev/null 2>&1; then
3697		debug "fatal" "(CFG): \$MYSQL_SSL_CA_PEM variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3698		debug "fatal" "(HLP): It is required for SSL connections" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3699		debug "fatal"  "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3700		exit $EXIT_ABORT
3701	elif [ -z "${MYSQL_SSL_CA_PEM}" ]; then
3702		debug "fatal" "(CFG): \$MYSQL_SSL_CA_PEM variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3703		debug "fatal" "(HLP): It is required for SSL connections" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3704		debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3705		exit $EXIT_ABORT
3706	elif [ ! -f "${MYSQL_SSL_CA_PEM}" ]; then
3707		debug "fatal" "(RUN): \$MYSQL_SSL_CA_PEM=\"$MYSQL_SSL_CA_PEM\" does not exist" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3708		debug "fatal" "(HLP): It is required for SSL connections" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3709		debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3710		exit $EXIT_ABORT
3711	fi
3712
3713	MYSQL_SSL_ARGS="--ssl-ca=${MYSQL_SSL_CA_PEM}"
3714
3715	# MYSQL_SSL_CLIENT_CERT_PEM
3716	if [ -n "${MYSQL_SSL_CLIENT_CERT_PEM-}" ]; then
3717		if [ ! -f "${MYSQL_SSL_CLIENT_CERT_PEM}" ]; then
3718			debug "fatal" "(RUN): \$MYSQL_SSL_CLIENT_CERT_PEM=\"$MYSQL_SSL_CLIENT_CERT_PEM\" does not exist" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3719			debug "fatal" "(HLP): Comment it out or specify the correct path." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3720			debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3721			exit $EXIT_ABORT
3722		fi
3723		MYSQL_SSL_ARGS="${MYSQL_SSL_ARGS} --ssl-cert=${MYSQL_SSL_CLIENT_CERT_PEM}"
3724	fi
3725	# MYSQL_SSL_CLIENT_KEY_PEM
3726	if [ -n "${MYSQL_SSL_CLIENT_KEY_PEM-}" ]; then
3727		if [ ! -f "${MYSQL_SSL_CLIENT_KEY_PEM}" ]; then
3728			debug "fatal" "(RUN): \$MYSQL_SSL_CLIENT_KEY_PEM=\"$MYSQL_SSL_CLIENT_KEY_PEM\" does not exist" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3729			debug "fatal" "(HLP): Comment it out or specify the correct path." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3730			debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3731			exit $EXIT_ABORT
3732		fi
3733		MYSQL_SSL_ARGS="${MYSQL_SSL_ARGS} --ssl-key=${MYSQL_SSL_CLIENT_KEY_PEM}"
3734	fi
3735
3736	debug "info"  "(OPT): MySQL SSL connection enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3737	debug "debug" "(OPT): MySQL SSL arguments: ${MYSQL_SSL_ARGS}." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3738elif [ "${MYSQL_SSL_ENABLE}" = "0" ]; then
3739	MYSQL_SSL_ENABLE=0
3740	MYSQL_SSL_ARGS=""
3741	debug "info" "(OPT): MySQL SSL connection disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3742else
3743	debug "fatal" "(CFG): Wrong value for \$MYSQL_SSL_ENABLE: $MYSQL_SSL_ENABLE" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3744	debug "fatal" "(HLP): It is not clear whether or not you only allow secure connections." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3745	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3746	exit $EXIT_ABORT
3747fi
3748
3749
3750
3751
3752############################################################
3753# MySQL Dump Opts
3754############################################################
3755
3756# MYSQL_OPTS
3757if ! set | grep '^MYSQL_OPTS=' >/dev/null 2>&1; then
3758	debug "warn" "(CFG): \$MYSQL_OPTS variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3759	debug "warn" "(RUN): Setting default to no custom mysqldump options" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3760	MYSQL_OPTS=""
3761	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3762elif [ -z "${MYSQL_SSL_ENABLE}" ]; then
3763	debug "trace" "(CFG): \$MYSQL_OPTS is empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3764	MYSQL_OPTS=""
3765fi
3766
3767debug "trace"  "(CFG): mysqldump custom options: ${MYSQL_OPTS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3768
3769
3770# MYSQL_OPTS_QUICK_MIN_SIZE
3771if ! set | grep '^MYSQL_OPTS_QUICK_MIN_SIZE=' >/dev/null 2>&1; then
3772	debug "warn" "(CFG): \$MYSQL_OPTS_QUICK_MIN_SIZE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3773	debug "warn" "(CFG): Setting default to: ${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3774	MYSQL_OPTS_QUICK_MIN_SIZE=${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}
3775	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3776elif [ -z "${MYSQL_OPTS_QUICK_MIN_SIZE}" ]; then
3777	debug "warn" "(CFG): \$MYSQL_OPTS_QUICK_MIN_SIZE is empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3778	debug "warn" "(CFG): Setting default to: ${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3779	MYSQL_OPTS_QUICK_MIN_SIZE=${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}
3780	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3781elif ! isint "${MYSQL_OPTS_QUICK_MIN_SIZE}" >/dev/null 2>&1; then
3782	debug "warn" "(CFG): Wrong integer value for \$MYSQL_OPTS_QUICK_MIN_SIZE: ${MYSQL_OPTS_QUICK_MIN_SIZE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3783	debug "warn" "(CFG): Setting default to: ${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3784	MYSQL_OPTS_QUICK_MIN_SIZE=${_DEFAULT_MYSQL_OPTS_QUICK_MIN_SIZE}
3785	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3786fi
3787debug "trace"  "(CFG): mysqldump '--quick':      Applied to DB's >= ${MYSQL_OPTS_QUICK_MIN_SIZE} MB" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3788debug "trace"  "(CFG): mysqldump '--skip-quick': Applied to DB's  < ${MYSQL_OPTS_QUICK_MIN_SIZE} MB" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3789
3790
3791############################################################
3792# Bad MySQL Opts
3793############################################################
3794for opt in ${MYSQL_OPTS}; do
3795	for evil in ${MDS_MYSQL_EVIL_OPTS}; do
3796		if echo "${opt}" | grep -e "^${evil}" > /dev/null 2>&1; then
3797			debug "fatal" "(CFG): Insecure mysqldump option found in MYSQL_OPTS: '${opt}'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3798			debug "fatal" "(RUN): Blacklist pattern: '^${evil}'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3799			debug "fatal" "(HLP): Remove it. This option is handled by the tool itself." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3800			debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3801			exit $EXIT_ABORT
3802		fi
3803	done
3804	for bad in ${MDS_MYSQL_BAD_OPTS}; do
3805		if echo "${opt}" | grep -e "^${bad}" > /dev/null 2>&1; then
3806			debug "fatal" "(CFG): Disallowed mysqldump option found in MYSQL_OPTS: '${opt}'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3807			debug "fatal" "(RUN): Blacklist pattern: '^${bad}'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3808			debug "fatal" "(HLP): Remove it. This option can be controlled via the configuration file itself." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3809			debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3810			exit $EXIT_ABORT
3811		fi
3812	done
3813done
3814
3815
3816
3817
3818
3819############################################################
3820# Consistency/Transactions
3821############################################################
3822
3823# CONSISTENT_DUMP_ONLY_INNODB
3824if ! set | grep '^CONSISTENT_DUMP_ONLY_INNODB=' >/dev/null 2>&1; then
3825	debug "warn"  "(CFG): \$CONSISTENT_DUMP_ONLY_INNODB variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3826	debug "warn"  "(RUN): Setting default to: 1 (using '--single-transaction')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3827	CONSISTENT_DUMP_ONLY_INNODB="1"
3828	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3829elif [ -z "${CONSISTENT_DUMP_ONLY_INNODB}" ]; then
3830	debug "warn"  "(CFG): \$CONSISTENT_DUMP_ONLY_INNODB variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3831	debug "warn"  "(RUN): Setting default to: 1 (using '--single-transaction')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3832	CONSISTENT_DUMP_ONLY_INNODB="1"
3833	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3834elif [ "${CONSISTENT_DUMP_ONLY_INNODB}" = "1" ]; then
3835	debug "trace" "(CFG): InnoDB-only:  Dumping consistently across tables (using '--single-transaction')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3836elif [ "${CONSISTENT_DUMP_ONLY_INNODB}" = "0" ]; then
3837	debug "trace" "(CFG): InnoDB-only:  Not dumping consistently across tables (using '--skip-lock-tables') [unsafe]" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3838else
3839	debug "warn"  "(CFG): \$CONSISTENT_DUMP_ONLY_INNODB variable has an invalid value: ${CONSISTENT_DUMP_ONLY_INNODB}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3840	debug "warn"  "(RUN): Setting default to: 1 (using '--single-transaction')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3841	CONSISTENT_DUMP_ONLY_INNODB="1"
3842	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3843fi
3844
3845# CONSISTENT_DUMP_NO_INNODB
3846if ! set | grep '^CONSISTENT_DUMP_NO_INNODB=' >/dev/null 2>&1; then
3847	debug "warn"  "(CFG): \$CONSISTENT_DUMP_NO_INNODB variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3848	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3849	CONSISTENT_DUMP_NO_INNODB="1"
3850	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3851elif [ -z "${CONSISTENT_DUMP_NO_INNODB}" ]; then
3852	debug "warn"  "(CFG): \$CONSISTENT_DUMP_NO_INNODB variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3853	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3854	CONSISTENT_DUMP_NO_INNODB="1"
3855	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3856elif [ "${CONSISTENT_DUMP_NO_INNODB}" = "1" ]; then
3857	debug "trace" "(CFG): InnoDB-none:  Dumping consistently across tables (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3858elif [ "${CONSISTENT_DUMP_NO_INNODB}" = "0" ]; then
3859	debug "trace" "(CFG): InnoDB-none:  Not dumping consistently across tables (using '--skip-lock-tables') [unsafe]" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3860else
3861	debug "warn"  "(CFG): \$CONSISTENT_DUMP_NO_INNODB variable has an invalid value: ${CONSISTENT_DUMP_NO_INNODB}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3862	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3863	CONSISTENT_DUMP_NO_INNODB="1"
3864	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3865fi
3866
3867# CONSISTENT_DUMP_MIXED_INNODB
3868if ! set | grep '^CONSISTENT_DUMP_MIXED_INNODB=' >/dev/null 2>&1; then
3869	debug "warn"  "(CFG): \$CONSISTENT_DUMP_MIXED_INNODB variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3870	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3871	CONSISTENT_DUMP_MIXED_INNODB="1"
3872	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3873elif [ -z "${CONSISTENT_DUMP_MIXED_INNODB}" ]; then
3874	debug "warn" "(CFG): \$CONSISTENT_DUMP_MIXED_INNODB variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3875	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3876	CONSISTENT_DUMP_MIXED_INNODB="1"
3877	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3878elif [ "${CONSISTENT_DUMP_MIXED_INNODB}" = "1" ]; then
3879	debug "trace" "(CFG): InnoDB-mixed: Dumping consistently across tables (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3880elif [ "${CONSISTENT_DUMP_MIXED_INNODB}" = "2" ]; then
3881	debug "trace" "(CFG): InnoDB-mixed: Dumping consistently across tables (using '--single-transaction') [unsafe]" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3882elif [ "${CONSISTENT_DUMP_MIXED_INNODB}" = "0" ]; then
3883	debug "trace" "(CFG): InnoDB-mixed: Not dumping consistently across tables (using '--skip-lock-tables') [unsafe]" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3884else
3885	debug "warn"  "(CFG): \$CONSISTENT_DUMP_MIXED_INNODB variable has an invalid value: ${CONSISTENT_DUMP_MIXED_INNODB}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3886	debug "warn"  "(RUN): Setting default to: 1 (using '--lock-tables')" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3887	CONSISTENT_DUMP_MIXED_INNODB="1"
3888	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3889fi
3890
3891
3892
3893
3894############################################################
3895# IGNORE/REQUIRE
3896############################################################
3897
3898# Ignored databases
3899if ! set | grep '^IGNORE=' >/dev/null 2>&1; then
3900	debug "warn" "(CFG): \$IGNORE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3901	debug "warn" "(HLP): Define \$IGNORE in your config to get rid of this warning" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3902	debug "warn" "(RUN): No database will be ignored" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3903	IGNORE=""
3904	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3905elif [ -z "${IGNORE}" ]; then
3906	debug "trace" "(CFG): \$IGNORE variable is empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3907	debug "trace" "(RUN): No database will be ignored" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3908	IGNORE=""
3909else
3910	debug "trace" "(CFG): Ignored DB's: ${IGNORE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3911fi
3912
3913# Required databases
3914if ! set | grep '^REQUIRE=' >/dev/null 2>&1; then
3915	debug "warn" "(CFG): \$REQUIRE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3916	debug "warn" "(HLP): Define \$REQUIRE in your config to get rid of this warning" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3917	debug "warn" "(RUN): No database will be required" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3918	REQUIRE=""
3919	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3920elif [ -z "${REQUIRE}" ]; then
3921	debug "trace" "(CFG): \$REQUIRE variable is empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3922	debug "trace" "(RUN): No database will explicitly be required" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3923	REQUIRE=""
3924else
3925	debug "trace" "(CFG): Required DB's: ${REQUIRE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3926fi
3927
3928
3929
3930
3931
3932############################################################
3933# Compression
3934############################################################
3935# Check $COMPRESS
3936if ! set | grep '^COMPRESS=' >/dev/null 2>&1; then
3937	debug "warn" "(CFG): \$COMPRESS variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3938	debug "warn" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3939	COMPRESS=0
3940	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3941elif [ -z "${COMPRESS}" ]; then
3942	debug "warn" "(CFG): \$COMPRESS variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3943	debug "warn" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3944	COMPRESS=0
3945	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3946elif [ "${COMPRESS}" = "1" ]; then
3947
3948	# COMPRESS_BIN
3949	if ! set | grep '^COMPRESS_BIN=' >/dev/null 2>&1; then
3950		debug "warn" "(CFG): \$COMPRESS_BIN variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3951		debug "warn" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3952		COMPRESS=0
3953		COMPRESS_BIN=""
3954		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3955	elif [ -z "${COMPRESS_BIN}" ]; then
3956		debug "warn" "(CFG): \$COMPRESS_BIN variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3957		debug "warn" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3958		COMPRESS=0
3959		COMPRESS_BIN=""
3960		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3961	fi
3962
3963	# If compression is still enabled
3964	if [ "${COMPRESS}" = "1" ]; then
3965		# Does COMPRESS_BIN binary exist?
3966		if ! command -v "${COMPRESS_BIN}" > /dev/null 2>&1 ; then
3967			debug "err" "(CFG): ${COMPRESS_BIN} not found. Fix \$COMPRESS_BIN" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3968			debug "err" "(HLP): Fix \$COMPRESS_BIN" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3969			debug "err" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3970			COMPRESS=0
3971			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
3972		fi
3973	fi
3974
3975	# If compression is still enabled
3976	if [ "${COMPRESS}" = "1" ]; then
3977		# COMPRESS_ARG
3978		if ! set | grep '^COMPRESS_ARG=' >/dev/null 2>&1; then
3979			debug "warn" "(CFG): \$COMPRESS_ARG variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3980			debug "warn" "(RUN): Using no command line arguments for ${COMPRESS_BIN}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3981			COMPRESS_ARG=""
3982			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3983		# Can be empty
3984		elif [ -z "${COMPRESS_ARG}" ]; then
3985			debug "trace" "(CFG): No compression arguments specified for ${COMPRESS_BIN}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3986		fi
3987	fi
3988
3989	# If compression is still enabled
3990	if [ "${COMPRESS}" = "1" ]; then
3991		# COMPRESS_ARG
3992		if ! set | grep '^COMPRESS_EXT=' >/dev/null 2>&1; then
3993			debug "warn" "(CFG): \$COMPRESS_EXT variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3994			debug "warn" "(RUN): Using 'compressed' as file extension." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3995			COMPRESS_EXT="compressed"
3996			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
3997		elif [ -z "${COMPRESS_EXT}" ]; then
3998			debug "warn" "(CFG): \$COMPRESS_EXT variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
3999			debug "warn" "(RUN): Using 'compressed' as file extension." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4000			COMPRESS_EXT="compressed"
4001			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4002		fi
4003	fi
4004
4005	# If compression is still enabled
4006	if [ "${COMPRESS}" = "1" ]; then
4007		debug "info"  "(OPT): Compression enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4008		debug "debug" "(OPT): Compression arguments: ${COMPRESS_BIN} ${COMPRESS_ARG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4009	fi
4010
4011elif [ "${COMPRESS}" = "0" ]; then
4012	debug "info" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4013else
4014	debug "warn" "(CFG): Invalid value for \$COMPRESS: ${COMPRESS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4015	debug "warn" "(OPT): Compression disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4016	COMPRESS=0
4017	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4018fi
4019
4020
4021
4022############################################################
4023# Encryption
4024############################################################
4025if ! set | grep '^ENCRYPT=' >/dev/null 2>&1; then
4026	debug "fatal" "(CFG): \$ENCRYPT variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4027	debug "fatal" "(HLP): It is not clear whether or not you only allow encrypted dumps." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4028	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4029	exit $EXIT_ABORT
4030elif [ -z "${ENCRYPT}" ]; then
4031	debug "fatal" "(CFG): \$ENCRYPT variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4032	debug "fatal" "(HLP): It is not clear whether or not you only allow encrypted dumps." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4033	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4034	exit $EXIT_ABORT
4035elif [ "${ENCRYPT}" = "1" ]; then
4036
4037	# OPENSSL_PUBKEY_PEM
4038	if ! set | grep '^OPENSSL_PUBKEY_PEM=' >/dev/null 2>&1; then
4039		debug "fatal" "(CFG): \$OPENSSL_PUBKEY_PEM variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4040		debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4041		exit $EXIT_ABORT
4042	elif [ -z "${OPENSSL_PUBKEY_PEM}" ]; then
4043		debug "fatal" "(CFG): \$OPENSSL_PUBKEY_PEM variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4044		debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4045		exit $EXIT_ABORT
4046	elif [ ! -f "${OPENSSL_PUBKEY_PEM}" ]; then
4047		debug "fatal"  "(RUN): OpenSSL pubkey not found in ${OPENSSL_PUBKEY_PEM}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4048		debug "fatal"  "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4049		exit $EXIT_ABORT
4050	elif [ ! -r "${OPENSSL_PUBKEY_PEM}" ]; then
4051		debug "fatal" "(RUN): OpenSSL pubkey not readable" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4052		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4053		exit $EXIT_ABORT
4054	fi
4055
4056	# OpenSSL Algorithm argument
4057	if ! set | grep '^OPENSSL_ALGO_ARG=' >/dev/null 2>&1; then
4058		debug "warn" "(CFG): \$OPENSSL_ALGO_ARG variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4059		debug "warn" "(RUN): Encryption defaults to: ${_DEFAULT_OPENSSL_ALGO_ARG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4060		OPENSSL_ALGO_ARG="${_DEFAULT_OPENSSL_ALGO_ARG}"
4061		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4062	elif [ -z "${OPENSSL_ALGO_ARG}" ]; then
4063		debug "warn" "(CFG): \$OPENSSL_ALGO_ARG variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4064		debug "warn" "(RUN): Encryption defaults to: ${_DEFAULT_OPENSSL_ALGO_ARG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4065		OPENSSL_ALGO_ARG="${_DEFAULT_OPENSSL_ALGO_ARG}"
4066		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4067	fi
4068
4069	# Test OpenSSL
4070	if ! command -v openssl > /dev/null 2>&1 ; then
4071		debug "fatal" "(RUN): 'openssl' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4072		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4073		exit $EXIT_ABORT
4074	fi
4075	if ! echo "test" | $(which openssl) smime -encrypt -binary -text -outform DER ${OPENSSL_ALGO_ARG} "${OPENSSL_PUBKEY_PEM}" > /dev/null 2>&1 ; then
4076		debug "fatal" "(RUN): openssl encryption test failed. Validate \$OPENSSL_ALGO_ARG" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4077		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4078		exit $EXIT_ABORT
4079	fi
4080
4081	# ENABLE_SMIME_BUG_WARNING
4082	if ! set | grep '^ENABLE_SMIME_BUG_WARNING=' >/dev/null; then
4083		debug "warn" "(CFG): \$ENABLE_SMIME_BUG_WARNING variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4084		debug "warn" "(CFG): Setting \$ENABLE_SMIME_BUG_WARNING=1" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4085		ENABLE_SMIME_BUG_WARNING=1
4086	elif [ -z "${ENABLE_SMIME_BUG_WARNING}" ]; then
4087		debug "warn" "(CFG): \$ENABLE_SMIME_BUG_WARNING variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4088		debug "warn" "(CFG): Setting \$ENABLE_SMIME_BUG_WARNING=1" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4089		ENABLE_SMIME_BUG_WARNING=1
4090	elif [ "${ENABLE_SMIME_BUG_WARNING}" != "0" ] && [ "${ENABLE_SMIME_BUG_WARNING}" != "1" ]; then
4091		debug "warn" "(CFG): \$ENABLE_SMIME_BUG_WARNING variable has a wrong value: '${ENABLE_SMIME_BUG_WARNING}'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4092		debug "warn" "(CFG): Setting \$ENABLE_SMIME_BUG_WARNING=1" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4093		ENABLE_SMIME_BUG_WARNING=1
4094	fi
4095
4096	debug "info"  "(OPT): Encryption enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4097	debug "debug" "(OPT): Encryption algorithm: ${OPENSSL_ALGO_ARG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4098	debug "debug" "(OPT): Encryption pub key: ${OPENSSL_PUBKEY_PEM}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4099
4100elif [ "${ENCRYPT}" = "0" ]; then
4101	debug "info" "(OPT): Encryption disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4102	ENCRYPT="0"
4103else
4104	debug "fatal" "(CFG): Invalid value for \$ENCRYPT: ${ENCRYPT}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4105	debug "fatal" "(HLP): It is not clear whether or not you only allow encrypted dumps." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4106	debug "fatal" "Aborting." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4107	exit $EXIT_ABORT
4108fi
4109
4110
4111
4112############################################################
4113# Deletion
4114############################################################
4115
4116if ! set | grep '^DELETE=' >/dev/null 2>&1; then
4117	debug "warn" "(CFG): \$DELETE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4118	debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4119	DELETE=0
4120	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4121elif [ -z "${DELETE}" ]; then
4122	debug "warn" "(CFG): \$DELETE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4123	debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4124	DELETE=0
4125	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4126elif [ "${DELETE}" = "1"  ]; then
4127
4128	# DELETE_METHOD
4129	if ! set | grep '^DELETE_METHOD=' >/dev/null 2>&1; then
4130		debug "warn" "(CFG): \$DELETE_METHOD variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4131		debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4132		DELETE=0
4133		DELETE_METHOD=""
4134		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4135	elif [ -z "${DELETE_METHOD}" ]; then
4136		debug "warn" "(CFG): \$DELETE_METHOD variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4137		debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4138		DELETE=0
4139		DELETE_METHOD=""
4140		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4141	elif [ "${DELETE_METHOD}" = "tmpwatch" ] && ! command -v tmpwatch > /dev/null 2>&1 ; then
4142		debug "err"  "(RUN): 'tmpwatch' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4143		debug "err"  "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4144		DELETE=0
4145		DELETE_METHOD=""
4146		MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4147	elif [ "${DELETE_METHOD}" = "tmpreaper" ] && ! command -v tmpreaper > /dev/null 2>&1 ; then
4148		debug "err"  "(RUN): 'tmpreaper' not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4149		debug "err"  "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4150		DELETE=0
4151		DELETE_METHOD=""
4152		MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4153	elif [ "${DELETE_METHOD}" != "tmpwatch" ] && [ "${DELETE_METHOD}" != 'tmpreaper' ]; then
4154		debug "err"  "(CFG): \$DELETE_METHOD must be either 'tmpwatch' or 'tmpreaper' in ${CONFIG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4155		debug "err"  "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4156		DELETE=0
4157		DELETE_METHOD=""
4158		MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4159	else
4160
4161		# DELETE_IF_OLDER
4162		if ! set | grep '^DELETE_IF_OLDER=' >/dev/null 2>&1; then
4163			debug "warn" "(CFG): \$DELETE_IF_OLDER variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4164			debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4165			DELETE=0
4166			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4167		elif [ -z "${DELETE_IF_OLDER}" ]; then
4168			debug "warn" "(CFG): \$DELETE_IF_OLDER variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4169			debug "warn" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4170			DELETE=0
4171			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4172		elif ! valid_tmpwatch "${DELETE_IF_OLDER}" > /dev/null 2>&1 ; then
4173			debug "err"  "(CFG): \$DELETE_IF_OLDER does not have a valid ${DELETE_METHOD} value: ${DELETE_IF_OLDER}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4174			debug "err"  "(HLP): See: man ${DELETE_METHOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4175			debug "err"  "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4176			DELETE=0
4177			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4178		fi
4179	fi
4180
4181	# If deletion is still enabled
4182	if [ "${DELETE}" = "1"  ]; then
4183
4184		debug "info"  "(OPT): Deletion enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4185		debug "debug" "(OPT): Deleting files older than $(get_tmpwatch_value "${DELETE_IF_OLDER}") $(get_tmpwatch_unit_name "${DELETE_IF_OLDER}"). Using: ${DELETE_METHOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4186
4187		# DELETE_FORCE
4188		if ! set | grep '^DELETE_FORCE=' >/dev/null 2>&1; then
4189			debug "warn" "(CFG): \$DELETE_FORCE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4190			debug "warn" "(RUN): Setting \$DELETE_FORCE = 0" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4191			DELETE_FORCE=0
4192			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4193		elif [ -z "${DELETE_FORCE}" ]; then
4194			debug "warn" "(CFG): \$DELETE_FORCE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4195			debug "warn" "(RUN): Setting \$DELETE_FORCE = 0" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4196			DELETE_FORCE=0
4197			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4198		elif [ "${DELETE_FORCE}" = "1"  ]; then
4199			debug "trace" "(CFG): ${DELETE_METHOD}: Using '--force' option (deleting read-only files)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4200		elif [ "${DELETE_FORCE}" = "0"  ]; then
4201			debug "trace" "(CFG): ${DELETE_METHOD}: Not forcing (--force) deletion for read-only files" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4202		else
4203			debug "err" "(CFG): Invalid value for \$DELETE_FORCE: ${DELETE_FORCE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4204			debug "err" "(RUN): Setting \$DELETE_FORCE = 0" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4205			DELETE_FORCE=0
4206			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4207		fi
4208	fi
4209
4210elif [ "${DELETE}" = "0"  ]; then
4211	debug "info" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4212else
4213	debug "err" "(CFG): Invalid value for \$DELETE: ${DELETE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4214	debug "err" "(OPT): Deletion disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4215	DELETE=0
4216	MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4217fi
4218
4219
4220
4221
4222
4223############################################################
4224# Nagios
4225############################################################
4226# NAGIOS_LOG
4227if ! set | grep '^NAGIOS_LOG=' >/dev/null 2>&1; then
4228	debug "warn" "(CFG): \$NAGIOS_LOG variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4229	debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4230	NAGIOS_LOG=0
4231	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4232elif [ -z "${NAGIOS_LOG}" ]; then
4233	debug "warn" "(CFG): \$NAGIOS_LOG variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4234	debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4235	NAGIOS_LOG=0
4236	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4237elif [ "${NAGIOS_LOG}" = "1"  ]; then
4238
4239	# NAGIOS_LOG_CHMOD
4240	if ! set | grep '^NAGIOS_LOG_CHMOD=' >/dev/null 2>&1; then
4241		debug "warn" "(CFG): \$NAGIOS_LOG_CHMOD variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4242		debug "warn" "(RUN): Setting default to ${_DEFAULT_NAGIOS_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4243		NAGIOS_LOG_CHMOD="${_DEFAULT_NAGIOS_LOG_CHMOD}"
4244		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4245	elif [ -z "${NAGIOS_LOG_CHMOD}" ]; then
4246		debug "warn" "(CFG): \$NAGIOS_LOG_CHMOD variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4247		debug "warn" "(RUN): Setting default to ${_DEFAULT_NAGIOS_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4248		NAGIOS_LOG_CHMOD="${_DEFAULT_NAGIOS_LOG_CHMOD}"
4249		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4250	elif ! valid_chmod "${NAGIOS_LOG_CHMOD}" > /dev/null 2>&1; then
4251		debug "err"  "(CFG): Invalid chmod value for \$NAGIOS_LOG_CHMOD: ${NAGIOS_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4252		debug "err"  "(RUN): Setting default to ${_DEFAULT_NAGIOS_LOG_CHMOD}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4253		NAGIOS_LOG_CHMOD="${_DEFAULT_NAGIOS_LOG_CHMOD}"
4254		MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4255	fi
4256
4257	# NAGIOS_LOG_FILE
4258	if ! set | grep '^NAGIOS_LOG_FILE=' >/dev/null 2>&1; then
4259		debug "warn" "(CFG): \$NAGIOS_LOG_FILE variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4260		debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4261		NAGIOS_LOG=0
4262		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4263	elif [ -z "${NAGIOS_LOG_FILE}" ]; then
4264		debug "warn" "(CFG): \$NAGIOS_LOG_FILE variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4265		debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4266		NAGIOS_LOG=0
4267		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4268	elif [ ! -f "${NAGIOS_LOG_FILE}" ]; then
4269		debug    "warn" "(RUN): ${NAGIOS_LOG_FILE} not found" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4270		debug_pi "warn" "(RUN): Trying to create..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4271		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4272
4273		if ! touch "${NAGIOS_LOG_FILE}" > /dev/null 2>&1 ; then
4274			debug_i "err" "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4275			debug   "err" "(RUN): Failed to create file ${NAGIOS_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4276			debug   "err" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4277			NAGIOS_LOG=0
4278			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4279		else
4280			debug_i  "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4281			debug    "warn" "(RUN): Created file ${NAGIOS_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4282			debug_pi "warn" "(RUN): Trying to chmod to ${NAGIOS_LOG_CHMOD}..." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4283			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4284
4285			if ! chmod ${NAGIOS_LOG_CHMOD} "${NAGIOS_LOG_FILE}" > /dev/null 2>&1 ; then
4286				debug_i "err"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4287				debug   "err"  "(RUN): Failed to chmod ${NAGIOS_LOG_CHMOD} ${NAGIOS_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4288				debug   "err"  "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4289				NAGIOS_LOG=0
4290				MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4291			else
4292				debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4293			fi
4294		fi
4295	# Check if it has wrong permissions
4296	elif ! compare_chmod "$(get_file_chmod "${NAGIOS_LOG_FILE}")" "${NAGIOS_LOG_CHMOD}" > /dev/null 2>&1 ; then
4297		debug    "warn" "(RUN): Nagios log file has wrong permissions: $(get_file_chmod "${NAGIOS_LOG_FILE}"), but should be: ${NAGIOS_LOG_CHMOD} " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4298		debug_pi "warn" "(RUN): Trying to chmod to ${NAGIOS_LOG_CHMOD}... " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4299		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4300
4301		if ! chmod "${NAGIOS_LOG_CHMOD}" "${NAGIOS_LOG_FILE}" > /dev/null 2>&1 ; then
4302			debug_i "err"  "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4303			debug   "err"  "(RUN): Failed to chmod ${NAGIOS_LOG_CHMOD} ${NAGIOS_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4304			debug   "err"  "(OPT): Nagios plugin log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4305			NAGIOS_LOG=0
4306			MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4307		else
4308			debug_i "warn" "OK\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4309		fi
4310	fi
4311
4312	# Still enabled?
4313	if [ "${NAGIOS_LOG}" = "1"  ]; then
4314		if [ ! -r "${NAGIOS_LOG_FILE}" ]; then
4315			debug "warn" "(RUN): ${NAGIOS_LOG_FILE} not readable" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4316			debug "warn" "(HLP): FIX \NAGIOS_LOG_CHMOD value in config" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4317			debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4318			NAGIOS_LOG=0
4319			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4320		elif [ ! -w "${NAGIOS_LOG_FILE}" ]; then
4321			debug "warn" "(RUN): ${NAGIOS_LOG_FILE} not writeable" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4322			debug "warn" "(HLP): FIX \NAGIOS_LOG_CHMOD value in config" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4323			debug "warn" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4324			NAGIOS_LOG=0
4325			MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4326		else
4327			debug "info"  "(OPT): Nagios log enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4328			debug "debug" "(OPT): Nagios log file: ${NAGIOS_LOG_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4329		fi
4330	fi
4331
4332elif [ "${NAGIOS_LOG}" = "0"  ]; then
4333	debug "info" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4334else
4335	debug "err" "(CFG): Invalid value for \$NAGIOS_LOG: ${NAGIOS_LOG}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4336	debug "err" "(OPT): Nagios log disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4337	DELETE=0
4338	MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4339fi
4340
4341
4342
4343
4344############################################################
4345# Info file
4346############################################################
4347
4348if ! set | grep '^DUMP_FILE_INFO=' >/dev/null 2>&1; then
4349	debug "warn" "(CFG): \$DUMP_FILE_INFO variable is not defined" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4350	debug "warn" "(OPT): Info files disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4351	DUMP_FILE_INFO=0
4352	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4353elif [ -z "${DUMP_FILE_INFO}" ]; then
4354	debug "warn" "(CFG): \$DUMP_FILE_INFO variable should not be empty" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4355	debug "warn" "(OPT): Info files disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4356	DUMP_FILE_INFO=0
4357	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4358elif [ "${DUMP_FILE_INFO}" = "1"  ]; then
4359	debug "info" "(OPT): Info files enabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4360elif [ "${DUMP_FILE_INFO}" = "0"  ]; then
4361	debug "info" "(OPT): Info files disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4362else
4363	debug "warn" "(CFG): Invalid value for \$DUMP_FILE_INFO: ${DUMP_FILE_INFO}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4364	debug "warn" "(OPT): Info files disabled" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4365	DUMP_FILE_INFO=0
4366	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4367fi
4368
4369
4370
4371
4372
4373
4374############################################################
4375# Connection
4376############################################################
4377
4378
4379# Testing MySQL Connection
4380if ! _CONN_ERR="$( mysql_test_connection "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" )"; then
4381	debug "fatal" "(RUN): Cannot connect to mysql database." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4382	debug "fatal" "(RUN): Via: $(which mysql) --defaults-file=${MYSQL_CNF_FILE} ${MYSQL_SSL_ARGS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4383	debug "fatal" "(RUN): SQL: ${_CONN_ERR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4384	debug "fatal" "(HLP): Fix credentials in: ${MYSQL_CNF_FILE}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4385	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4386	exit $EXIT_ABORT
4387else
4388	debug "trace" "(RUN): MySQL connection test successful." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4389fi
4390
4391
4392# Getting MySQL Server Status
4393if ! MYSQL_SERVER_STATUS="$( get_mysql_server_status "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" )"; then
4394	debug "fatal" "(SRV): Cannot retrieve MySQL server status" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4395	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4396	exit $EXIT_ABORT
4397fi
4398
4399
4400# MySQL TCP/IP or Socket connection
4401debug "debug"  "(SRV): MySQL server connection: $( get_mysql_connection_type_info "${MYSQL_SERVER_STATUS}" )" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4402
4403
4404# Testing MySQL for SSL connection
4405MYSQL_SSL_STATUS="$( get_mysql_connection_ssl_info "${MYSQL_SERVER_STATUS}" )"
4406if [ "${MYSQL_SSL_STATUS}" = "Not in use" ]; then
4407	if [ "${MYSQL_SSL_ENABLE}" = "1" ]; then
4408		debug "fatal" "(SRV): MySQL server connection: Not using SSL, but demanded." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4409		debug "fatal" "(HLP): We have already made some plain-text connections" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4410		debug "fatal" "(HLP): It is advised to change your password immediately" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4411		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4412		exit $EXIT_ABORT
4413	else
4414		debug "debug"  "(SRV): MySQL server connection: Not using SSL (plain)." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4415	fi
4416else
4417	debug "debug" "(SRV): MySQL server connection: Using SSL (${MYSQL_SSL_STATUS})" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4418fi
4419
4420# Testing MySQL for Master or Slave
4421if ! MYSQL_SERVER_TYPE="$(get_mysql_server_replication_type "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}")"; then
4422	debug "fatal" "(RUN): Connection error" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4423	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4424	exit $EXIT_ABORT
4425else
4426	debug "debug" "(SRV): MySQL server rep type:   ${MYSQL_SERVER_TYPE}"  "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4427fi
4428
4429
4430# Get MySQL Name and Version
4431MYSQL_SERVER="$( get_mysql_server_name "${MYSQL_SERVER_STATUS}" )"
4432MYSQL_VERSION="$( get_mysql_server_version "${MYSQL_SERVER_STATUS}" )"
4433
4434# Get MySQL Server Hostname and Port
4435MYSQL_HOST="$( get_mysql_server_hostname "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" )"
4436MYSQL_PORT="$( get_mysql_server_port "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" )"
4437
4438debug "debug" "(SRV): MySQL server version:    $( [ "${MYSQL_SERVER}" != "" ] && echo "${MYSQL_SERVER} " )${MYSQL_VERSION}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4439debug "debug" "(SRV): MySQL server hostname:   ${MYSQL_HOST}:${MYSQL_PORT}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4440
4441
4442
4443
4444
4445
4446
4447
4448
4449
4450
4451############################################################
4452# Test mode
4453############################################################
4454if [ "${_ARG_TEST}" = "1" ]; then
4455	debug "info" "(ARG): Exiting program from test mode (--test)." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4456	exit $EXIT_OK
4457fi
4458
4459
4460
4461
4462
4463
4464
4465
4466
4467
4468
4469
4470
4471
4472
4473####################################################################################################
4474####################################################################################################
4475##
4476##  M A I N   E N T R Y   P O I N T   ( R U N )
4477##
4478####################################################################################################
4479####################################################################################################
4480
4481
4482################################################################################
4483#
4484# VARIABLES
4485#
4486################################################################################
4487
4488#
4489# Binaries
4490#
4491BIN_TMPWATCH="$(which "${DELETE_METHOD}" 2>/dev/null)"	# This can be tmpwatch or tmpreaper
4492
4493#
4494# Database counters
4495#
4496DB_CNT_TOTAL=0			# Total numbers of databases
4497DB_CNT_IGNORED=0		# Number of ignored databases (empty or via ignore list)
4498DB_CNT_DUMPED=0			# Number of successfully dumped databases
4499DB_CNT_FAILED=0			# Number of unseccessfull dumped fatabases (failed)
4500DB_CNT_REQ_FAILED=0		# Number of required databases not dumped
4501
4502#
4503# Database lists
4504#
4505DB_LIST_ALL=""			# Newline separated list of all databases
4506DB_LIST_DUMPED=""		# Comma separated list of all dumped databases
4507DB_LIST_IGNORED=""		# Comma separated list of all ignored databases
4508DB_LIST_FAILED=""		# Comma separated list of all failed databases
4509DB_LIST_REQ_FAILED=""	# Comma separated list of required databases not dumped
4510
4511#
4512# Total size of all dumped databases
4513#
4514TOTAL_SIZE_B=0
4515TOTAL_SIZE_MB=0
4516
4517#
4518# Overall Timing
4519#
4520TIME_TOTAL_START=0
4521TIME_TOTAL_DURATION=0
4522
4523
4524
4525#
4526# Nagios Log: Aggregated exit code (0:OK, 1:Warn, 2:ERR, 3:UNKNOWN)
4527#
4528NAGIOS_EXIT_CODE=0
4529
4530
4531
4532#
4533# TODO: Make all vars within 'if' local and small _tmp_bla
4534#
4535#
4536
4537
4538################################################################################
4539#
4540# PRE-PROCESSING
4541#
4542################################################################################
4543
4544
4545
4546############################################################
4547# Create tmp files and folders
4548############################################################
4549
4550# New temporary directory
4551if MY_TMP_DIR="$(create_tmp_dir "${TMP_DIR}/${INFO_NAME}.XXXXXXXXXX" "0700")"; then
4552	debug "trace"  "(RUN): Creating tmp dir:  ${MY_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4553else
4554	debug "fatal" "(RUN): Cannot create tmp dir:  ${MY_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4555	debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4556	exit $EXIT_ABORT
4557fi
4558
4559# Temp file 'tmpwatch/tmpreaper'
4560if [ "${DELETE}" = "1" ]; then
4561	if MY_TMP_FILE_DEL="$(create_tmp_file "${MY_TMP_DIR}/.XXXXXXXXXXXXXXX" "0600")"; then
4562		debug "trace"  "(RUN): Creating tmp file: ${MY_TMP_FILE_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4563	else
4564		debug "fatal" "(RUN): Cannot create tmp file: ${MY_TMP_FILE_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4565		debug "fatal" "Aborting" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4566		exit $EXIT_ABORT
4567	fi
4568fi
4569
4570
4571############################################################
4572# Get all databases
4573############################################################
4574
4575debug_pi "debug" "(SQL): Retrieving list of databases... " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4576
4577# Get all databases
4578DB_LIST_ALL="$( get_mysql_databases "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" )"
4579DB_CNT_TOTAL="$( str_count_lines "${DB_LIST_ALL}" )"
4580
4581debug_i "debug" "${DB_CNT_TOTAL}\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4582
4583
4584
4585
4586
4587################################################################################
4588#
4589# DUMP DATABASES
4590#
4591################################################################################
4592
4593
4594i=0 # Lopp counter
4595TIME_TOTAL_START="$( get_time )"
4596for db in ${DB_LIST_ALL}; do
4597
4598
4599	##########################################################
4600	# VARIABLES
4601
4602	# Increment Loop counter
4603	i=$((i + 1))
4604
4605	# Show progress
4606	# At which database are we right now?
4607	# Left-space-padded " 1/10" counter
4608	_cnt="$(printf "%$(str_len "${DB_CNT_TOTAL}")d/%d" "${i}" "${DB_CNT_TOTAL}")"
4609
4610	# File extension for dump file (.sql, .sql.gz, .sql.gz.enc or .sql.enc)
4611	ext="$( build_file_extension "${ENCRYPT}" "${COMPRESS}" "${COMPRESS_EXT}" )"
4612
4613	# Skip database vars
4614	skip_empty=0
4615	skip_ignored=0
4616
4617
4618
4619
4620
4621	##########################################################
4622	# IGNORE CHECKS
4623
4624
4625	# Empty databases
4626	if mysql_database_is_empty "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" "${db}"; then
4627		skip_empty=1
4628	fi
4629
4630	# Ignored database
4631	if _ignore_pattern="$( database_is_ignored "${IGNORE}" "${db}" )"; then
4632		skip_ignored=1
4633		debug "trace" "(CFG): ${_cnt} Ignoring DB: \"${db}\" by \$IGNORE pattern: \"${_ignore_pattern}\""  "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4634
4635		# Only if ignored database is not required, we can ignore it.
4636		if database_is_required "${REQUIRE}" "${db}"; then
4637			skip_ignored=0
4638			debug "trace" "(CFG): ${_cnt} Required DB: \"${db}\" un-ignored by \$REQUIRE settings"  "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4639		fi
4640	fi
4641
4642
4643	#
4644	# Main case 1 (skipping)
4645	#
4646	if [ "${skip_empty}" = "1" ] || [ "${skip_ignored}" = "1" ]; then
4647
4648		# Case 1/3: Empty AND Ignored
4649		if [ "${skip_empty}" = "1" ] && [ "${skip_ignored}" = "1" ]; then
4650			debug "info" "(SQL): ${_cnt} Skipping: ${db} (DB is empty and ignored)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4651		# Case 2/3: Empty
4652		elif [ "${skip_empty}" = "1" ]; then
4653			debug "info" "(SQL): ${_cnt} Skipping: ${db} (DB is empty)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4654		# Case 3/3:Ignored
4655		else
4656			debug "info" "(SQL): ${_cnt} Skipping: ${db} (DB is ignored)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4657		fi
4658
4659		DB_CNT_IGNORED=$((DB_CNT_IGNORED + 1))
4660		DB_LIST_IGNORED="$( str_join "${DB_LIST_IGNORED}" "," "${db}" )"
4661
4662	#
4663	# Main case 2 (file exists on disk)
4664	#
4665	elif [ -f "${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" ]; then
4666
4667		# Increment counters
4668		DB_CNT_FAILED=$((DB_CNT_FAILED + 1))
4669		MDS_FAIL_COUNT=$((MDS_FAIL_COUNT + 1))
4670
4671		# Add failed db to nagios log
4672		DB_LIST_FAILED="$( str_join "${DB_LIST_FAILED}" "," "${db}" )"
4673
4674		debug "fatal" "(RUN): ${_cnt} Failed:   ${db} cannot be written to disk (file exists: ${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext})" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4675		NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 2)"
4676
4677	#
4678	# Main case 3 (dumping)
4679	#
4680	else
4681
4682		##########################################################
4683		# VARIABLES
4684
4685		# Database size
4686		DB_SIZE_B="$( get_mysql_database_size "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" "${db}" )"
4687		DB_SIZE_MB="$( div "${DB_SIZE_B}" "1048576" )"
4688		DB_SIZE_MB="$( round "${DB_SIZE_MB}" "2" )"
4689
4690		# Total Database size (aggregated db size)
4691		TOTAL_SIZE_B=$( sum "${TOTAL_SIZE_B}" "${DB_SIZE_B}" )
4692
4693		# Number of tables
4694		TBL_CNT_TOTAL="$(  count_total_tables      "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" "${db}" )"
4695		TBL_CNT_INNODB="$( count_innodb_tables     "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" "${db}" )"
4696		TBL_CNT_OTHERS="$( count_non_innodb_tables "${MYSQL_CNF_FILE}" "${MYSQL_SSL_ARGS}" "${db}" )"
4697
4698		debug "trace" "(RUN): ${_cnt} Number of total tables:       ${TBL_CNT_TOTAL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4699		debug "trace" "(RUN): ${_cnt} Number of InnoDB tables:      ${TBL_CNT_INNODB}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4700		debug "trace" "(RUN): ${_cnt} Number of non-InnoDB tables:  ${TBL_CNT_OTHERS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4701
4702
4703		##########################################################
4704		# MYSQLDUMP OPTIONS
4705
4706		#
4707		# CONSISTENCY OPTIONS (By Table Engines)
4708		#
4709		# information_schema and performance schema are special tables, which do not allow locking
4710		if [ "${db}" != "information_schema" ] && [ "${db}" != "performance_schema" ]; then
4711			MYSQL_LOCK_OPTS="$( get_consistency_opts "${CONSISTENT_DUMP_ONLY_INNODB}" "${CONSISTENT_DUMP_MIXED_INNODB}" "${CONSISTENT_DUMP_NO_INNODB}" "${TBL_CNT_INNODB}" "${TBL_CNT_OTHERS}" )"
4712			debug "trace" "(RUN): ${_cnt} Applying consistency setting: ${MYSQL_LOCK_OPTS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4713		else
4714			MYSQL_LOCK_OPTS="--skip-lock-tables"
4715			debug "trace" "(RUN): ${_cnt} \"${db}\" is special and needs '--skip-lock-tables'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4716		fi
4717
4718		#
4719		# SPECIAL OPTIONS (By Virtual Databases)
4720		#
4721		MYSQL_SPECIAL_OPTS=""
4722
4723		# Performance schema does not allow to dump events
4724		# mysqldump: mysqldump  Couldn't execute 'show events'  Access denied for user 'root'@'localhost' to database 'performance_schema' (1044)
4725		if [ "${db}" = "performance_schema" ]; then
4726			MYSQL_SPECIAL_OPTS="--skip-events"
4727			debug "trace" "(RUN): ${_cnt} \"${db}\" cannot be dumped with --events. Adding --skip-events" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4728		fi
4729
4730		#
4731		# QUICK OPTION (--quick/--skip-quick dependent on size)
4732		#
4733		MYSQL_QUICK_OPT="$(echo "${DB_SIZE_MB} ${MYSQL_OPTS_QUICK_MIN_SIZE}" | awk '{print ($1 >= $2) ? "--quick" : "--skip-quick" }')"
4734
4735		#
4736		# FINAL OPTIONS (Build final MySQLDump arguments)
4737		#
4738		MYSQL_ARGUMENTS="--defaults-file=${MYSQL_CNF_FILE} ${MYSQL_SSL_ARGS}"
4739		MYSQLDUMP_ARGUMENTS="${MYSQL_OPTS} ${MYSQL_LOCK_OPTS} ${MYSQL_SPECIAL_OPTS} ${MYSQL_QUICK_OPT}"
4740
4741
4742
4743		##########################################################
4744		# SMIME WARNING
4745		# https://github.com/cytopia/mysqldump-secure/issues/21
4746
4747		# Warn about SMIME bug for files > 1200MB
4748		SMIME_CRITICAL_SIZE_MB="1200"
4749		if [ "${ENCRYPT}" = "1" ] && [ "${ENABLE_SMIME_BUG_WARNING}" = "1" ] && [ "$( printf "%.0f\n" "${DB_SIZE_MB}" )" -gt "${SMIME_CRITICAL_SIZE_MB}" ]; then
4750			debug "warn" "(SQL): ${_cnt} Warning:  Encryption is enabled and database size is > ${SMIME_CRITICAL_SIZE_MB} MB" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4751			debug "warn" "(SQL): ${_cnt} Warning:  Verify that your backup can be decrypted." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4752			debug "warn" "(SQL): ${_cnt} Warning:  This warning can be disabled via 'ENABLE_SMIME_BUG_WARNING=0'" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4753			debug "warn" "(SQL): ${_cnt} Warning:  Read here: https://github.com/cytopia/mysqldump-secure/issues/21" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4754		fi
4755
4756
4757		##########################################################
4758		# MAKE THE BACKUPS
4759
4760		debug_pi "info" "(SQL): ${_cnt} Dumping:  ${db} (${DB_SIZE_MB} MB) " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4761
4762
4763		#
4764		# Stop time (start)
4765		#
4766		starttime="$( get_time )"
4767
4768		#
4769		# Case 1/4 Plain
4770		#
4771		if [ "${COMPRESS}" = "0" ] && [ "${ENCRYPT}" = "0" ];  then
4772
4773			debug_i "debug"  "$( [ "${MYSQL_LOCK_OPTS}" != "" ] && echo "(${MYSQL_LOCK_OPTS}) ")$( [ "${MYSQL_SPECIAL_OPTS}" != "" ] && echo "(${MYSQL_SPECIAL_OPTS}) ")(${MYSQL_QUICK_OPT}) " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4774
4775			# Run Compressed & Encrypted
4776			error_statuses="$(run_mysqldump "0" "${MYSQL_ARGUMENTS} ${MYSQLDUMP_ARGUMENTS}" "${db}" \
4777				"${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" "${DUMP_FILE_CHMOD}" \
4778				"${COMPRESS_BIN}" "${COMPRESS_ARG}" \
4779				"${OPENSSL_ALGO_ARG}" "${OPENSSL_PUBKEY_PEM}" \
4780				"${MY_TMP_DIR}"
4781			)"
4782		#
4783		# Case 2/4 Compressed
4784		#
4785		elif [ "${COMPRESS}" = "1" ] && [ "${ENCRYPT}" = "0" ];  then
4786
4787			debug_i "debug"  "(compressed) $( [ "${MYSQL_LOCK_OPTS}" != "" ] && echo "(${MYSQL_LOCK_OPTS}) ")$( [ "${MYSQL_SPECIAL_OPTS}" != "" ] && echo "(${MYSQL_SPECIAL_OPTS}) ")(${MYSQL_QUICK_OPT}) " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4788
4789			# Run Compressed & Encrypted
4790			error_statuses="$(run_mysqldump "1" "${MYSQL_ARGUMENTS} ${MYSQLDUMP_ARGUMENTS}" "${db}" \
4791				"${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" "${DUMP_FILE_CHMOD}" \
4792				"${COMPRESS_BIN}" "${COMPRESS_ARG}" \
4793				"${OPENSSL_ALGO_ARG}" "${OPENSSL_PUBKEY_PEM}" \
4794				"${MY_TMP_DIR}"
4795			)"
4796		#
4797		# Case 3/4 Encrypted
4798		#
4799		elif [ "${COMPRESS}" = "0" ] && [ "${ENCRYPT}" = "1" ];  then
4800
4801			debug_i "debug"  "(encrypted) $( [ "${MYSQL_LOCK_OPTS}" != "" ] && echo "(${MYSQL_LOCK_OPTS}) ")$( [ "${MYSQL_SPECIAL_OPTS}" != "" ] && echo "(${MYSQL_SPECIAL_OPTS}) ")(${MYSQL_QUICK_OPT}) " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4802
4803			# Run Compressed & Encrypted
4804			error_statuses="$(run_mysqldump "2" "${MYSQL_ARGUMENTS} ${MYSQLDUMP_ARGUMENTS}" "${db}" \
4805				"${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" "${DUMP_FILE_CHMOD}" \
4806				"${COMPRESS_BIN}" "${COMPRESS_ARG}" \
4807				"${OPENSSL_ALGO_ARG}" "${OPENSSL_PUBKEY_PEM}" \
4808				"${MY_TMP_DIR}"
4809			)"
4810		#
4811		# Case 4/4 Compressed && Encrypted
4812		#
4813		elif [ "${COMPRESS}" = "1" ] && [ "${ENCRYPT}" = "1" ];  then
4814
4815			debug_i "debug"  "(compressed) (encrypted) $( [ "${MYSQL_LOCK_OPTS}" != "" ] && echo "(${MYSQL_LOCK_OPTS}) " )$( [ "${MYSQL_SPECIAL_OPTS}" != "" ] && echo "(${MYSQL_SPECIAL_OPTS}}) ")(${MYSQL_QUICK_OPT}) " "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4816
4817			# Run Compressed & Encrypted
4818			error_statuses="$(run_mysqldump "3" "${MYSQL_ARGUMENTS} ${MYSQLDUMP_ARGUMENTS}" "${db}" \
4819				"${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" "${DUMP_FILE_CHMOD}" \
4820				"${COMPRESS_BIN}" "${COMPRESS_ARG}" \
4821				"${OPENSSL_ALGO_ARG}" "${OPENSSL_PUBKEY_PEM}" \
4822				"${MY_TMP_DIR}"
4823			)"
4824		#
4825		# Case 5/4: WRONG OPTIONS
4826		#
4827		else
4828			debug "fatal" "(???) Internal Error. Wrong mysqldump choice." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4829			_abort_on_internal_error
4830		fi
4831
4832		#
4833		# Stop time (get duration)
4834		#
4835		duration="$( get_duration "${starttime}" )"
4836
4837
4838
4839		#
4840		# Pipefail Errors
4841		#
4842		_dump_failed=0
4843		if ! MY_ERRORS="$(mysqldump_pipefail_errors "${error_statuses}")"; then
4844			_dump_failed=1
4845
4846			debug_i "fatal" "Failed\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4847			debug   "fatal" "(RUN): ${_cnt} Error dumping ${db}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4848
4849			if ! MY_WARNINGS="$(mysqldump_pipefail_warnings "${error_statuses}")"; then
4850				debug "warn" "(RUN): ${_cnt} Warning dumping ${db}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4851				debug "warn" "${MY_WARNINGS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4852				MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4853			fi
4854			debug  "fatal"  "${MY_ERRORS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4855
4856			DB_CNT_FAILED=$((DB_CNT_FAILED + 1))
4857			MDS_FAIL_COUNT=$((MDS_FAIL_COUNT + 1))
4858			NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 2)"
4859			DB_LIST_FAILED="$( str_join "${DB_LIST_FAILED}" "," "${db}" )"
4860		#
4861		# Pipefail OK
4862		#
4863		else
4864			_dump_failed=0
4865
4866			debug_i "ok"    "${duration} sec ($(get_file_size "${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}" "m") MB)\n" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4867			debug   "trace" "(RUN): ${_cnt} Dump File: ${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}"  "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4868
4869			if ! MY_WARNINGS="$(mysqldump_pipefail_warnings "${error_statuses}")"; then
4870				debug "warn" "(RUN): ${_cnt} Warning dumping ${db}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4871				debug "warn" "${MY_WARNINGS}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4872				MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4873			fi
4874
4875			DB_CNT_DUMPED=$((DB_CNT_DUMPED + 1))
4876			DB_LIST_DUMPED="$( str_join "${DB_LIST_DUMPED}" "," "${db}" )"
4877		fi
4878
4879
4880
4881		#
4882		# Success Handler
4883		#
4884		if [ "${_dump_failed}" = "0" ]; then
4885
4886			#
4887			# If all was good, remove required db from list
4888			#
4889			REQUIRE="$( str_remove_word "${REQUIRE}" "${db}" )"
4890
4891
4892			#
4893			# Write file info?
4894			#
4895			if [ "${DUMP_FILE_INFO}" = "1" ]; then
4896
4897				write_info_file "${DUMP_DIR}" "${DUMP_FILE_PRE}${db}${ext}" "${DUMP_FILE_CHMOD}" \
4898					"${db}" "${DB_SIZE_B}" "${TBL_CNT_TOTAL}" "${MYSQLDUMP_ARGUMENTS}" "${duration}" \
4899					"${COMPRESS}" "${COMPRESS_BIN}" "${COMPRESS_ARG}" \
4900					"${ENCRYPT}" "${OPENSSL_ALGO_ARG}" "${OPENSSL_PUBKEY_PEM}" \
4901					"${MYSQL_ARGUMENTS}" "${MYSQL_SSL_ENABLE}" "${MYSQL_SSL_STATUS}" \
4902					"${MYSQL_SERVER_STATUS}" "${MYSQL_HOST}" "${MYSQL_PORT}" "${MYSQL_SERVER_TYPE}" "${MYSQL_SERVER}" "${MYSQL_VERSION}"
4903
4904				if [ "$?" != "0" ]; then
4905					debug "err"   "(RUN): ${_cnt} Could not write info File: ${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}.info" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4906					MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4907				else
4908					debug "trace" "(RUN): ${_cnt} Info File: ${DUMP_DIR}/${DUMP_FILE_PRE}${db}${ext}.info" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4909				fi
4910
4911			fi
4912		fi
4913	fi
4914done
4915TIME_TOTAL_DURATION="$( get_duration "${TIME_TOTAL_START}" )"
4916
4917
4918
4919
4920################################################################################
4921#
4922# POST PROCESSING
4923#
4924################################################################################
4925
4926
4927############################################################
4928# (CFG) Check required databases
4929############################################################
4930
4931for req in ${REQUIRE}; do
4932	debug "err" "(RUN): Required database: \"${req}\" has not been dumped." "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4933	MDS_FAIL_COUNT=$((MDS_FAIL_COUNT + 1))
4934	DB_CNT_REQ_FAILED=$((DB_CNT_REQ_FAILED + 1))
4935	DB_LIST_REQ_FAILED="$( str_join "${DB_LIST_REQ_FAILED}" "," "${req}" )"
4936	NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 2)"
4937done
4938
4939
4940
4941
4942############################################################
4943# (OPT) TMPWATCH (Delete old files)
4944############################################################
4945TMPWATCH_NUM_DEL="0"
4946TMPWATCH_NUM_IGN="0"
4947
4948if [ "${DELETE}" = "1" ]; then
4949
4950	# Force deletion?
4951	if [ "${DELETE_FORCE}" = "1" ]; then FORCE_ARG="--force"; else FORCE_ARG=""; fi
4952
4953	# Verbosity
4954	if [ "${DELETE_METHOD}" = "tmpwatch" ]; then TMPWATCH_OPTS="-vv"; else TMPWATCH_OPTS="--verbose=3 --showdeleted"; fi
4955
4956	TMPWATCH_RUN="$(${BIN_TMPWATCH} ${FORCE_ARG} -m "${DELETE_IF_OLDER}" "${TMPWATCH_OPTS}" "${DUMP_DIR}/" 2> "${MY_TMP_FILE_DEL}")"
4957	TMPWATCH_ERRNO="$?"
4958	TMPWATCH_ERROR="$( cat "${MY_TMP_FILE_DEL}" )"
4959
4960	if [ "${TMPWATCH_ERRNO}" != "0" ]; then
4961		debug "err"  "(RUN): ${DELETE_METHOD} exit code: ${TMPWATCH_ERRNO}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4962		debug "err"  "(RUN): ${DELETE_METHOD} error: ${TMPWATCH_ERROR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4963		MDS_ERROR_COUNT=$((MDS_ERROR_COUNT + 1))
4964		NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 1)"
4965	elif [ "${TMPWATCH_ERROR}" != "" ]; then
4966		debug "warn" "(RUN): ${DELETE_METHOD} exit code: ${TMPWATCH_ERRNO}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4967		debug "warn" "(RUN): ${DELETE_METHOD} error: ${TMPWATCH_ERROR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4968		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4969		NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 1)"
4970	fi
4971
4972	# Number removed/skipped files
4973	TMPWATCH_NUM_DEL="$( echo "${TMPWATCH_RUN}" | grep -ci 'Removing file' )"
4974	TMPWATCH_NUM_IGN="$( echo "${TMPWATCH_RUN}" | grep -ci 'skipped:' )"
4975
4976	# Output of removed/skipped files
4977	TMPWATCH_TXT_DEL="$( echo "${TMPWATCH_RUN}" | grep -i 'Removing file' )"
4978	TMPWATCH_TXT_IGN="$( echo "${TMPWATCH_RUN}" | grep -i 'skipped:' )"
4979
4980	# Number of deleted files and the command itself
4981	debug  "info"  "(RUN): Deleting files older than $(get_tmpwatch_value "${DELETE_IF_OLDER}") $(get_tmpwatch_unit_name "${DELETE_IF_OLDER}") ... ${TMPWATCH_NUM_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4982	debug  "trace" "(CFG): ${BIN_TMPWATCH} ${FORCE_ARG} -m ${DELETE_IF_OLDER} ${TMPWATCH_OPTS} ${DUMP_DIR}/" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4983
4984
4985	# Some files have been skipped!
4986	if [ "${TMPWATCH_NUM_IGN}" != "0" ] || [ "${TMPWATCH_TXT_IGN}" != "" ]; then
4987		debug "warn" "(RUN): ${DELETE_METHOD}: ${TMPWATCH_NUM_IGN} files could not be deleted:" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4988		debug "warn" "${TMPWATCH_TXT_IGN}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4989		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
4990		NAGIOS_EXIT_CODE="$(merge_exit_codes "${NAGIOS_EXIT_CODE}" 1)"
4991	fi
4992
4993	# Show deleted files
4994	debug "info|(RUN): ${DELETE_METHOD}: " "${TMPWATCH_TXT_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4995
4996	# Show full trace output
4997	debug "trace|(RUN): ${DELETE_METHOD}: " "${TMPWATCH_RUN}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
4998fi
4999
5000
5001
5002############################################################
5003# (OPT) Nagios Plugin Log
5004############################################################
5005
5006if [ "${NAGIOS_LOG}" = "1" ]; then
5007
5008	debug "debug" "(RUN): Writing nagios log file" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5009
5010	{
5011		echo "[state]";
5012		echo "success = ${NAGIOS_EXIT_CODE}";
5013		echo "lastbak = ${TIME_TOTAL_START}";
5014		echo "message = ";
5015		echo "missing = ${DB_LIST_REQ_FAILED}";
5016		echo;
5017		echo "[options]";
5018		echo "opt_log = ${LOG}";
5019		echo "opt_com = ${COMPRESS}";
5020		echo "opt_enc = ${ENCRYPT}";
5021		echo "opt_del = ${DELETE}";
5022		echo;
5023		echo "[messages]";
5024		echo "msg_dbs = ${DB_CNT_DUMPED}";
5025		echo "msg_ign = ${DB_CNT_IGNORED}";
5026		echo "msg_err = ${DB_CNT_FAILED}";
5027		echo "msg_meg = ${TOTAL_SIZE_MB}";
5028		echo "msg_sec = ${TIME_TOTAL_DURATION}";
5029		echo "msg_del = ${TMPWATCH_NUM_DEL}";
5030		echo;
5031		echo "[tmpwatch]";
5032	} > "${NAGIOS_LOG_FILE}"
5033
5034	if [ "${DELETE}" = "1" ]; then
5035		{
5036			echo "del_time = ${DELETE_IF_OLDER}";
5037			echo "del_del  = ${TMPWATCH_NUM_DEL}";	# how many files deleted
5038			echo "del_skp  = ${TMPWATCH_NUM_IGN}";	# how many files skipped (due to unable to delete)
5039		} >> "${NAGIOS_LOG_FILE}"
5040	else
5041		{
5042			echo "del_time = 0";
5043			echo "del_del  = 0";	# how many files deleted
5044			echo "del_skp  = 0";	# how many files skipped (due to unable to delete)
5045		} >> "${NAGIOS_LOG_FILE}"
5046	fi
5047
5048	{
5049		echo;
5050		echo "[stats]";
5051		echo "db_dumped  = ${DB_LIST_DUMPED}";
5052		echo "db_error   = ${DB_LIST_FAILED}";
5053		echo "db_ignored = ${DB_LIST_IGNORED}";
5054		echo;
5055		echo "[misc]";
5056		echo "version = ${INFO_VERSION}";	# mysqldump-secure version (for checking against latest)
5057	} >> "${NAGIOS_LOG_FILE}"
5058fi
5059
5060
5061
5062############################################################
5063# Delete temporary files
5064############################################################
5065
5066#
5067# Delete tmp files/folders in reverse order
5068#
5069if [ "${DELETE}" = "1" ]; then
5070	if rm "${MY_TMP_FILE_DEL}" 2>/dev/null; then
5071		debug "trace" "(RUN): Deleting tmp file: ${MY_TMP_FILE_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5072	else
5073		debug "warn"  "(RUN): Cannot delete tmp file: ${MY_TMP_FILE_DEL}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5074		MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
5075	fi
5076fi
5077
5078if rm -rf "${MY_TMP_DIR}" 2>/dev/null; then
5079	debug "trace" "(RUN): Deleting tmp dir:  ${MY_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5080else
5081	debug "warn"  "(RUN): Cannot delete tmp dir:  ${MY_TMP_DIR}" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5082	MDS_WARNING_COUNT=$((MDS_WARNING_COUNT + 1))
5083fi
5084
5085
5086
5087############################################################
5088# Exit
5089############################################################
5090
5091
5092# Human readable output of TOTAL_SIZE (MegaBytes)
5093TOTAL_SIZE_MB="$( div "${TOTAL_SIZE_B}" "1048576" )"
5094TOTAL_SIZE_MB="$( round "${TOTAL_SIZE_MB}" "2" )"
5095
5096debug "debug" "(RUN): Dumping finished (OK: ${DB_CNT_DUMPED} dbs, IGN: ${DB_CNT_IGNORED} dbs, ERR: ${DB_CNT_FAILED}, TOTAL: ${DB_CNT_TOTAL})" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5097debug "debug" "(RUN): Took ${TIME_TOTAL_DURATION} seconds" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5098debug "debug" "(RUN): Total size dumped: ${TOTAL_SIZE_MB} MB" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5099
5100
5101
5102if [ "${MDS_FAIL_COUNT}" != "0" ]; then
5103	if [ "${MDS_FAIL_COUNT}" = "1" ]; then
5104		debug "fatal" "Finished with ${MDS_FAIL_COUNT} Failures. ${DB_CNT_FAILED} failed backups (${DB_CNT_REQ_FAILED} required dbs missing)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5105	else
5106		debug "fatal" "Finished with ${MDS_FAIL_COUNT} Failures. ${DB_CNT_FAILED} failed backups (${DB_CNT_REQ_FAILED} required dbs missing)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5107	fi
5108	exit $EXIT_FAIL
5109elif [ "${MDS_ERROR_COUNT}" != "0" ]; then
5110	if [ "${MDS_ERROR_COUNT}" = "1" ]; then
5111		debug "err"  "Finished with ${MDS_ERROR_COUNT} error. (Backups done successfully)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5112	else
5113		debug "err"  "Finished with ${MDS_ERROR_COUNT} errors. (Backups done successfully)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5114	fi
5115	exit $EXIT_ERROR
5116elif [ "${MDS_WARNING_COUNT}" != "0" ]; then
5117	if [ "${MDS_WARNING_COUNT}" = "1" ]; then
5118		debug "warn"  "Finished with ${MDS_WARNING_COUNT} warning. (Backups done successfully)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5119	else
5120		debug "warn"  "Finished with ${MDS_WARNING_COUNT} warnings. (Backups done successfully)" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5121	fi
5122	exit $EXIT_WARNING
5123else
5124	debug "ok" "Finished successfully" "${OUT_VERBOSITY}" "${LOG_VERBOSITY}" "${LOG_FILE}"
5125	exit $EXIT_OK
5126fi
5127