diff --git a/groups/231.native_packages_etc.group b/groups/231.native_packages_etc.group
index 4a0f47e..ec04c03 100644
--- a/groups/231.native_packages_etc.group
+++ b/groups/231.native_packages_etc.group
@@ -175,7 +175,7 @@ fi;
 : ${PKG_ICECAST_VERSION:=2.4.99.2-283};
 : ${PKG_ICECAST_URL:=https://people.xiph.org/~epirat/Icecast/icecast-${PKG_ICECAST_VERSION}.tar.gz};
 : ${PKG_ICECAST_CONFIGURE_ARGS_EXTRA:="--without-speex"};
-: ${PKG_IMAGEMAGICK_DEPENDS:="curl"};
+: ${PKG_IMAGEMAGICK_DEPENDS:="curl xz"};
 : ${PKG_IMAGEMAGICK_SHA256SUM:=67859f9cba97f2c06b5e416898216e49216be00c7cba3dd89896e49331aef96d};
 : ${PKG_IMAGEMAGICK_VERSION:=7.0.9-12};
 : ${PKG_IMAGEMAGICK_URL:=https://imagemagick.org/download/releases/ImageMagick-${PKG_IMAGEMAGICK_VERSION}.tar.xz};
diff --git a/subr/build_init.subr b/subr/build_init.subr
index 0a4e9cf..53327ac 100644
--- a/subr/build_init.subr
+++ b/subr/build_init.subr
@@ -78,7 +78,7 @@ buildp_init_env() {
 	if ex_rtl_check_path_vars "${DEFAULT_CHECK_PATH_VARS}"; then
 		export PATH="${PREFIX}/bin${PATH:+:${PATH}}";
 	else
-		: $((_rc+=(6-1)));
+		: $((_rc+=(9-1)));
 	fi;
 	return "${_rc}";
 };
@@ -96,7 +96,7 @@ buildp_init_files() {
 		ex_rtl_fileop mkdir "${PREFIX_RPM}";
 	fi;
 	if [ -e "${DEFAULT_BUILD_STATUS_IN_PROGRESS_FNAME}" ]; then
-		_rc=8; _status="Error: another build targeting this architecture and build type is currently in progress.";
+		_rc=11; _status="Error: another build targeting this architecture and build type is currently in progress.";
 	else
 		touch "${DEFAULT_BUILD_STATUS_IN_PROGRESS_FNAME}";
 		if [ -e "${DEFAULT_BUILD_LOG_FNAME}" ]; then
@@ -143,10 +143,12 @@ buildp_init_getopts() {
 	done;
 	while [ ${#} -gt 0 ]; do
 	case "${1}" in
-	*=*)	ex_rtl_set_var_unsafe "${1%%=*}" "${1#*=}"; ;;
-	*)	BUILD_GROUPS="${BUILD_GROUPS:+${BUILD_GROUPS} }${1}"; ;;
+	*=*)		ex_rtl_set_var_unsafe "${1%%=*}" "${1#*=}"; ;;
+	[^a-zA-Z]*)	_rc=1; _status="Error: build group names must start with [a-zA-Z]."; ;;
+	*[^_a-zA-Z]*)	_rc=2; _status="Error: build group names must not contain [^_a-zA-Z]."; ;;
+	*)		BUILD_GROUPS="${BUILD_GROUPS:+${BUILD_GROUPS} }${1}"; ;;
 	esac; shift; done;
-	return 0;
+	return "${_rc}";
 };
 
 buildp_init_prereqs() {
@@ -157,9 +159,11 @@ buildp_init_prereqs() {
 			mkdir mkfifo mv openssl paste patch pgrep pkill		\
 			printf readlink rm sed seq shuf sort stat tail		\
 			tar test touch tr wget xz >/dev/null; then
-		_rc=1; _status="Error: missing prerequisite package(s).";
+		_rc=3; _status="Error: missing prerequisite package(s).";
 	elif ! awk -V 2>/dev/null | grep -q "^GNU Awk "; then
-		_rc=2; _status="Error: awk(1) in \$PATH must be GNU Awk.";
+		_rc=4; _status="Error: awk(1) in \$PATH must be GNU Awk.";
+	elif ! sed --version 2>/dev/null | grep -q "^GNU sed "; then
+		_rc=5; _status="Error: sed(1) in \$PATH must be GNU sed.";
 	fi;
 	return "${_rc}";
 };
@@ -174,9 +178,9 @@ buildp_init_type() {
 	else
 		if [ "${BUILD}" != debug ]\
 		&& [ "${BUILD}" != release ]; then
-			_rc=3; _status="Error: unknown build type \`${BUILD}'.";
+			_rc=6; _status="Error: unknown build type \`${BUILD}'.";
 		fi;
-		_rc=4; _status="Error: invalid architecture \`${ARCH}'.";
+		_rc=7; _status="Error: invalid architecture \`${ARCH}'.";
 	fi;
 	return "${_rc}";
 };
@@ -199,16 +203,16 @@ buildp_init_vars() {
 		fi;
 	done;
 	if [ -z "${PREFIX}" ]; then
-		_rc=5; _status="Error: \${PREFIX} empty or unset.";
+		_rc=8; _status="Error: \${PREFIX} empty or unset.";
 	fi;
 	return "${_rc}";
 };
 
 build_fini() {
-	: $((BUILD_TIMES_SECS="$(ex_rtl_date %s)"-"${BUILD_TIMES_SECS}"));
-	: $((BUILD_TIMES_HOURS="${BUILD_TIMES_SECS}"/3600));
-	: $((BUILD_TIMES_MINUTES=("${BUILD_TIMES_SECS}"%3600)/60));
-	: $((BUILD_TIMES_SECS=("${BUILD_TIMES_SECS}"%3600)%60));
+	: $((BUILD_TIMES_SECS=$(ex_rtl_date %s)-${BUILD_TIMES_SECS}));
+	: $((BUILD_TIMES_HOURS=${BUILD_TIMES_SECS}/3600));
+	: $((BUILD_TIMES_MINUTES=(${BUILD_TIMES_SECS}%3600)/60));
+	: $((BUILD_TIMES_SECS=(${BUILD_TIMES_SECS}%3600)%60));
 	if [ -f "${DEFAULT_BUILD_STATUS_IN_PROGRESS_FNAME}" ]; then
 		ex_rtl_fileop rm ${DEFAULT_BUILD_STATUS_IN_PROGRESS_FNAME};
 	fi;
diff --git a/subr/ex_rtl_complex.subr b/subr/ex_rtl_complex.subr
index 560b35b..4b8da0a 100644
--- a/subr/ex_rtl_complex.subr
+++ b/subr/ex_rtl_complex.subr
@@ -27,6 +27,17 @@ ex_rtl_clean_env() {
 	ex_rtl_unset_vars $(ex_rtl_lfilter "${_env_vars}" "${_env_vars_except}");
 };
 
+ex_rtl_kill_tree() {
+	local _pid="${1}" _signal="TERM" _pid_child="" _pid_top="";
+	for _pid_top in $(pgrep -P "${_pid}"); do
+		for _pid_child in $(pgrep -P "${_pid_top}" 2>/dev/null); do
+			_pids_killed="${_pids_killed:+${_pids_killed} }${_pid_child}"; kill "-${_signal}" "${_pid_child}"
+			2>/dev/null;
+		done;
+		_pids_killed="${_pids_killed:+${_pids_killed} }${_pid_top}"; kill "-${_signal}" "${_pid_top}" 2>/dev/null;
+	done;
+};
+
 ex_rtl_lfilter() {
 	local _list="${1}" _filter="${2}" _lnew="" _litem="" _litem_filter="" _filterfl="";
 	if [ -z "${_filter}" ]; then
diff --git a/subr/ex_rtl_log.subr b/subr/ex_rtl_log.subr
index 2ed295b..460c899 100644
--- a/subr/ex_rtl_log.subr
+++ b/subr/ex_rtl_log.subr
@@ -2,6 +2,17 @@
 # set -o noglob is assumed.
 #
 
+: ${DEFAULT_LOG_MSG_FAIL_COLOUR:=91};
+: ${DEFAULT_LOG_MSG_INFO_COLOUR:=93};
+: ${DEFAULT_LOG_MSG_INF2_COLOUR:=33};
+: ${DEFAULT_LOG_MSG_SUCC_COLOUR:=92};
+: ${DEFAULT_LOG_MSG_SUC2_COLOUR:=32};
+: ${DEFAULT_LOG_MSG_VNFO_COLOUR:=96};
+: ${DEFAULT_LOG_MSG_VUCC_COLOUR:=90};
+: ${DEFAULT_LOG_MSG_VVFO_COLOUR:=96};
+: ${DEFAULT_LOG_MSG_VVVO_COLOUR:=96};
+: ${DEFAULT_LOG_MSG_VVVV_COLOUR:=96};
+
 exp_rtl_log_printf() {
 	local _attrs="${1}" _msg=""; shift; _msg="$(printf "${@}")";
 	if [ "${BUILD_IS_PARENT:-0}" -eq 1 ]; then