Browse Source

netdata/packaging/installer: netdata-installer.sh script (and subscripts) refactoring wrap-up (#5736)

* remove dead quickfix

* unify global variable naming

* do not use double negation

* simplify setcap detection

* simplify logic of setting capabilities to apps.plugin

* always set group in chown

* simplify parameter parsing and banner notifications

* use built-in command for checking program availability

* lint functions.sh

* fix errors returned by shellcheck

* remove unused functions and use portable_service

* move user management functions closer together and remove "check" functions to reduce levels of indirection

* extract add_netdata_user_and_group and move it into installers for better code readability

* improve readability by not using global variable holding number of processors

* move netdata.conf file creation into one function

* revert migration to portable_service

* Less verbose setcap

* remove TODOs

* do not show output when not needed

* fix checking for group existence

* fix variable name

* netdata/packaging/installer: Dont spill out unnecessary output in stdout/stderr, it may confuse our users

The second commit was a follow up cleanup on nits.

* access: change codeowner

* Revert "access: change codeowner"

This reverts commit 6ee51ccae960584d5b1b7c243f5aabf046a99eff.
sorry, wrong repo

* netdata/packaging/installer: bug fix - do not use pidof as the name of the helper method

1) rename to safe_pidof, which is actually more accurate and describe what this method serves for (safe pid detection)
2) Renaming it also avoids the bug introduced by the usage of , that resulted in endless nested calls of the BASH method pidif
   (Refer to command -v usage)
Paul Katsoulakis 6 years ago
parent
commit
c8d2e6c7d3

+ 198 - 284
netdata-installer.sh

@@ -1,43 +1,47 @@
 #!/usr/bin/env bash
 # SPDX-License-Identifier: GPL-3.0-or-later
-# shellcheck disable=SC1090,SC1091,SC1117,SC2002,SC2034,SC2044,SC2046,SC2086,SC2129,SC2162,SC2166,SC2181
+# shellcheck disable=SC2046,SC2086,SC2166
 
 export PATH="${PATH}:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
 uniquepath() {
 	local path=""
-	while read; do
+	while read -r; do
 		if [[ ! ${path} =~ (^|:)"${REPLY}"(:|$) ]]; then
-			[ ! -z "${path}" ] && path="${path}:"
+			[ -n "${path}" ] && path="${path}:"
 			path="${path}${REPLY}"
 		fi
-	done < <(echo "${PATH}" | tr ":" "\n")
+	done < <(echo "${PATH}" | tr ":" "\\n")
 
-	[ ! -z "${path}" ] && [[ ${PATH} =~ /bin ]] && [[ ${PATH} =~ /sbin ]] && export PATH="${path}"
+	[ -n "${path}" ] && [[ ${PATH} =~ /bin ]] && [[ ${PATH} =~ /sbin ]] && export PATH="${path}"
 }
 uniquepath
 
-netdata_source_dir="$(pwd)"
-installer_dir="$(dirname "${0}")"
+PROGRAM="$0"
+NETDATA_SOURCE_DIR="$(pwd)"
+INSTALLER_DIR="$(dirname "${PROGRAM}")"
 
-if [ "${netdata_source_dir}" != "${installer_dir}" -a "${installer_dir}" != "." ]; then
-	echo >&2 "Warning: you are currently in '${netdata_source_dir}' but the installer is in '${installer_dir}'."
+if [ "${NETDATA_SOURCE_DIR}" != "${INSTALLER_DIR}" ] && [ "${INSTALLER_DIR}" != "." ]; then
+	echo >&2 "Warning: you are currently in '${NETDATA_SOURCE_DIR}' but the installer is in '${INSTALLER_DIR}'."
 fi
 
 # -----------------------------------------------------------------------------
 # reload the user profile
 
+# shellcheck source=/dev/null
 [ -f /etc/profile ] && . /etc/profile
 
 # make sure /etc/profile does not change our current directory
-cd "${netdata_source_dir}" || exit 1
+cd "${NETDATA_SOURCE_DIR}" || exit 1
 
 # -----------------------------------------------------------------------------
 # load the required functions
 
-if [ -f "${installer_dir}/packaging/installer/functions.sh" ]; then
-	source "${installer_dir}/packaging/installer/functions.sh" || exit 1
+if [ -f "${INSTALLER_DIR}/packaging/installer/functions.sh" ]; then
+	# shellcheck source=packaging/installer/functions.sh
+	source "${INSTALLER_DIR}/packaging/installer/functions.sh" || exit 1
 else
-	source "${netdata_source_dir}/packaging/installer/functions.sh" || exit 1
+	# shellcheck source=packaging/installer/functions.sh
+	source "${NETDATA_SOURCE_DIR}/packaging/installer/functions.sh" || exit 1
 fi
 
 download() {
@@ -74,199 +78,164 @@ CFLAGS="${CFLAGS--O2}"
 [ "z${CFLAGS}" = "z-O3" ] && CFLAGS="-O2"
 
 # keep a log of this command
-printf "\n# " >>netdata-installer.log
+# shellcheck disable=SC2129
+printf "\\n# " >>netdata-installer.log
 date >>netdata-installer.log
 printf 'CFLAGS="%s" ' "${CFLAGS}" >>netdata-installer.log
-printf "%q " "$0" "${@}" >>netdata-installer.log
-printf "\n" >>netdata-installer.log
+printf "%q " "${PROGRAM}" "${@}" >>netdata-installer.log
+printf "\\n" >>netdata-installer.log
 
-REINSTALL_PWD="${PWD}"
 REINSTALL_COMMAND="$(
-	printf "%q " "$0" "${@}"
-	printf "\n"
+	printf "%q " "${PROGRAM}" "${@}"
+	printf "\\n"
 )"
 # remove options that shown not be inherited by netdata-updater.sh
 REINSTALL_COMMAND="${REINSTALL_COMMAND// --dont-wait/}"
 REINSTALL_COMMAND="${REINSTALL_COMMAND// --dont-start-it/}"
-[ "${REINSTALL_COMMAND:0:1}" != "." -a "${REINSTALL_COMMAND:0:1}" != "/" -a -f "./${0}" ] && REINSTALL_COMMAND="./${REINSTALL_COMMAND}"
-
-# shellcheck disable=SC2230
-setcap="$(which setcap 2>/dev/null || command -v setcap 2>/dev/null)"
-
-ME="$0"
-DONOTSTART=0
-DONOTWAIT=0
-AUTOUPDATE=0
-NETDATA_PREFIX=
-LIBS_ARE_HERE=0
-NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}"
-RELEASE_CHANNEL="nightly"
-
-usage() {
-	netdata_banner "installer command line options"
-	cat <<USAGE
-
-${ME} <installer options>
-
-Valid <installer options> are:
-
-   --install /PATH/TO/INSTALL
-
-        If you give: --install /opt
-        netdata will be installed in /opt/netdata
-
-   --dont-start-it
-
-        Do not (re)start netdata.
-        Just install it.
-
-   --dont-wait
-
-        Do not wait for the user to press ENTER.
-        Start immediately building it.
-
-   --auto-update | -u
-
-        Install netdata-updater to cron,
-        to update netdata automatically once per day
-
-   --stable-channel
-
-        Auto-updater will update netdata only when new release is published
-        in GitHub release pages. This results in less frequent updates.
-        Default: Use packages from GCS (nightly release channel).
-
-   --enable-plugin-freeipmi
-   --disable-plugin-freeipmi
+if [ "${REINSTALL_COMMAND:0:1}" != "." ] && [ "${REINSTALL_COMMAND:0:1}" != "/" ] && [ -f "./${PROGRAM}" ]; then
+	REINSTALL_COMMAND="./${REINSTALL_COMMAND}"
+fi
 
-        Enable/disable the FreeIPMI plugin.
-        Default: enable it when libipmimonitoring is available.
+banner_nonroot_install() {
+	cat <<NONROOTNOPREFIX
 
-   --enable-plugin-nfacct
-   --disable-plugin-nfacct
+  ${TPUT_RED}${TPUT_BOLD}Sorry! This will fail!${TPUT_RESET}
 
-        Enable/disable the nfacct plugin.
-        Default: enable it when libmnl and libnetfilter_acct are available.
+  You are attempting to install netdata as non-root, but you plan
+  to install it in system paths.
 
-   --enable-plugin-xenstat
-   --disable-plugin-xenstat
+  Please set an installation prefix, like this:
 
-        Enable/disable the xenstat plugin.
-        Default: enable it when libxenstat and libyajl are available.
+      $PROGRAM ${@} --install /tmp
 
-   --enable-lto
-   --disable-lto
+  or, run the installer as root:
 
-        Enable/disable Link-Time-Optimization
-        Default: enabled
+      sudo $PROGRAM ${@}
 
-   --disable-x86-sse
+  We suggest to install it as root, or certain data collectors will
+  not be able to work. Netdata drops root privileges when running.
+  So, if you plan to keep it, install it as root to get the full
+  functionality.
 
-        Disable SSE instructions
-        Default: enabled
+NONROOTNOPREFIX
+}
 
-   --zlib-is-really-here
-   --libs-are-really-here
+banner_root_notify() {
+	cat <<NONROOT
 
-        If you get errors about missing zlib,
-        or libuuid but you know it is available,
-        you have a broken pkg-config.
-        Use this option to allow it continue
-        without checking pkg-config.
+  ${TPUT_RED}${TPUT_BOLD}IMPORTANT${TPUT_RESET}:
+  You are about to install netdata as a non-root user.
+  Netdata will work, but a few data collection modules that
+  require root access will fail.
 
-   --disable-telemetry
+  If you installing netdata permanently on your system, run
+  the installer like this:
 
-        Use this flag to opt-out from our anonymous telemetry progam.
+     ${TPUT_YELLOW}${TPUT_BOLD}sudo $PROGRAM ${@}${TPUT_RESET}
 
-   --disable-go
+NONROOT
+}
 
-        Flag to disable installation of go.d.plugin
+usage() {
+	netdata_banner "installer command line options"
+	cat <<HEREDOC
+
+USAGE: ${PROGRAM} [options]
+       where options include:
+
+  --install <path>           Install netdata in <path>. Ex. --install /opt will put netdata in /opt/netdata
+  --dont-start-it            Do not (re)start netdata after installation
+  --dont-wait                Run installation in non-interactive mode
+  --auto-update or -u        Install netdata-updater in cron to update netdata automatically once per day
+  --stable-channel           Use packages from GitHub release pages instead of GCS (nightly updates).
+                             This results in less frequent updates.
+  --disable-go               Disable installation of go.d.plugin.
+  --enable-plugin-freeipmi   Enable the FreeIPMI plugin. Default: enable it when libipmimonitoring is available.
+  --disable-plugin-freeipmi
+  --enable-plugin-nfacct     Enable nfacct plugin. Default: enable it when libmnl and libnetfilter_acct are available.
+  --disable-plugin-nfacct
+  --enable-plugin-xenstat    Enable the xenstat plugin. Default: enable it when libxenstat and libyajl are available
+  --disable-plugin-xenstat   Disable the xenstat plugin.
+  --enable-lto               Enable Link-Time-Optimization. Default: enabled
+  --disable-lto
+  --disable-x86-sse          Disable SSE instructions. By default SSE optimizations are enabled.
+  --zlib-is-really-here or
+  --libs-are-really-here     If you get errors about missing zlib or libuuid but you know it is available, you might
+                             have a broken pkg-config. Use this option to proceed without checking pkg-config.
+  --disable-telemetry        Use this flag to opt-out from our anonymous telemetry progam.
 
 Netdata will by default be compiled with gcc optimization -O2
 If you need to pass different CFLAGS, use something like this:
 
-  CFLAGS="<gcc options>" ${ME} <installer options>
+  CFLAGS="<gcc options>" ${PROGRAM} [options]
 
-For the installer to complete successfully, you will need
-these packages installed:
+For the installer to complete successfully, you will need these packages installed:
 
-   gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel)
-   uuid-dev (or libuuid-devel)
+  gcc make autoconf automake pkg-config zlib1g-dev (or zlib-devel) uuid-dev (or libuuid-devel)
 
 For the plugins, you will at least need:
 
-   curl, bash v4+, python v2 or v3, node.js
+  curl, bash v4+, python v2 or v3, node.js
 
-USAGE
+HEREDOC
 }
 
-while [ ! -z "${1}" ]; do
-	if [ "$1" = "--install" ]; then
-		NETDATA_PREFIX="${2}/netdata"
-		shift 2
-	elif [ "$1" = "--zlib-is-really-here" -o "$1" = "--libs-are-really-here" ]; then
-		LIBS_ARE_HERE=1
-		shift 1
-	elif [ "$1" = "--dont-start-it" ]; then
-		DONOTSTART=1
-		shift 1
-	elif [ "$1" = "--dont-wait" ]; then
-		DONOTWAIT=1
-		shift 1
-	elif [ "$1" = "--auto-update" -o "$1" = "-u" ]; then
-		AUTOUPDATE=1
-		shift 1
-	elif [ "$1" = "--stable-channel" ]; then
-		RELEASE_CHANNEL="stable"
-		shift 1
-	elif [ "$1" = "--enable-plugin-freeipmi" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-freeipmi/} --enable-plugin-freeipmi"
-		shift 1
-	elif [ "$1" = "--disable-plugin-freeipmi" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-freeipmi/} --disable-plugin-freeipmi"
-		shift 1
-	elif [ "$1" = "--enable-plugin-nfacct" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-nfacct/} --enable-plugin-nfacct"
-		shift 1
-	elif [ "$1" = "--disable-plugin-nfacct" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-nfacct/} --disable-plugin-nfacct"
-		shift 1
-    elif [ "$1" = "--enable-plugin-xenstat" ]; then
-        NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-xenstat/} --enable-plugin-xenstat"
-        shift 1
-    elif [ "$1" = "--disable-plugin-xenstat" ]; then
-        NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-xenstat/} --disable-plugin-xenstat"
-        shift 1
-	elif [ "$1" = "--enable-lto" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-lto/} --enable-lto"
-		shift 1
-	elif [ "$1" = "--disable-lto" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-lto/} --disable-lto"
-		shift 1
-	elif [ "$1" = "--disable-x86-sse" ]; then
-		NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse"
-		shift 1
-	elif [ "$1" = "--disable-telemetry" ]; then
-		NETDATA_DISABLE_TELEMETRY=1
-		shift 1
-	elif [ "$1" = "--disable-go" ]; then
-		NETDATA_DISABLE_GO=1
-		shift 1
-	elif [ "$1" = "--help" -o "$1" = "-h" ]; then
-		usage
-		exit 1
-	else
-		echo >&2
-		echo >&2 "ERROR:"
-		echo >&2 "I cannot understand option '$1'."
-		usage
-		exit 1
-	fi
+DONOTSTART=0
+DONOTWAIT=0
+AUTOUPDATE=0
+NETDATA_PREFIX=
+LIBS_ARE_HERE=0
+NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS-}"
+RELEASE_CHANNEL="nightly"
+while [ -n "${1}" ]; do
+	case "${1}" in
+		"--zlib-is-really-here") LIBS_ARE_HERE=1;;
+		"--libs-are-really-here") LIBS_ARE_HERE=1;;
+		"--dont-start-it") DONOTSTART=1;;
+		"--dont-wait") DONOTWAIT=1;;
+		"--auto-update"|"-u") AUTOUPDATE=1;;
+		"--stable-channel") RELEASE_CHANNEL="stable";;
+		"--enable-plugin-freeipmi")  NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-freeipmi/} --enable-plugin-freeipmi";;
+		"--disable-plugin-freeipmi") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-freeipmi/} --disable-plugin-freeipmi";;
+		"--enable-plugin-nfacct") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-nfacct/} --enable-plugin-nfacct";;
+		"--disable-plugin-nfacct") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-nfacct/} --disable-plugin-nfacct";;
+		"--enable-plugin-xenstat") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-plugin-xenstat/} --enable-plugin-xenstat";;
+		"--disable-plugin-xenstat") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-plugin-xenstat/} --disable-plugin-xenstat";;
+		"--enable-lto") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--enable-lto/} --enable-lto";;
+		"--disable-lto") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-lto/} --disable-lto";;
+		"--disable-x86-sse") NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//--disable-x86-sse/} --disable-x86-sse";;
+		"--disable-telemetry") NETDATA_DISABLE_TELEMETRY=1;;
+		"--disable-go") NETDATA_DISABLE_GO=1;;
+		"--install")
+			NETDATA_PREFIX="${2}/netdata"
+			shift 1
+			;;
+		"--help"|"-h")
+			usage
+			exit 1
+			;;
+		*)
+			run_failed "I cannot understand option '$1'."
+			usage
+			exit 1
+			;;
+		esac
+	shift 1
 done
 
 # replace multiple spaces with a single space
 NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS//  / }"
 
+if [ "${UID}" -ne 0 ]; then
+	if [ -z "${NETDATA_PREFIX}" ]; then
+		netdata_banner "wrong command line options!"
+		banner_nonroot_install "${@}"
+		exit 1
+	else
+		banner_root_notify "${@}"
+	fi
+fi
+
 netdata_banner "real-time performance monitoring, done right!"
 cat <<BANNER1
 
@@ -295,49 +264,6 @@ cat <<BANNER3
 
 BANNER3
 
-if [ "${UID}" -ne 0 ]; then
-	if [ -z "${NETDATA_PREFIX}" ]; then
-		netdata_banner "wrong command line options!"
-		cat <<NONROOTNOPREFIX
-
-  ${TPUT_RED}${TPUT_BOLD}Sorry! This will fail!${TPUT_RESET}
-
-  You are attempting to install netdata as non-root, but you plan
-  to install it in system paths.
-
-  Please set an installation prefix, like this:
-
-      $0 ${@} --install /tmp
-
-  or, run the installer as root:
-
-      sudo $0 ${@}
-
-  We suggest to install it as root, or certain data collectors will
-  not be able to work. Netdata drops root privileges when running.
-  So, if you plan to keep it, install it as root to get the full
-  functionality.
-
-NONROOTNOPREFIX
-		exit 1
-
-	else
-		cat <<NONROOT
-
-  ${TPUT_RED}${TPUT_BOLD}IMPORTANT${TPUT_RESET}:
-  You are about to install netdata as a non-root user.
-  Netdata will work, but a few data collection modules that
-  require root access will fail.
-
-  If you installing netdata permanently on your system, run
-  the installer like this:
-
-     ${TPUT_YELLOW}${TPUT_BOLD}sudo $0 ${@}${TPUT_RESET}
-
-NONROOT
-	fi
-fi
-
 have_autotools=
 if [ "$(type autoreconf 2>/dev/null)" ]; then
 	autoconf_maj_min() {
@@ -381,13 +307,16 @@ EOF
 fi
 
 if [ ${DONOTWAIT} -eq 0 ]; then
-	if [ ! -z "${NETDATA_PREFIX}" ]; then
-		eval "read >&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata to \'\001${TPUT_CYAN}\002${NETDATA_PREFIX}\001${TPUT_YELLOW}\002\'\001${TPUT_RESET}\002 > ' -e -r REPLY"
-		[ $? -ne 0 ] && exit 1
+	if [ -n "${NETDATA_PREFIX}" ]; then
+		echo -n "${TPUT_BOLD}${TPUT_GREEN}Press ENTER to build and install netdata to '${TPUT_CYAN}${NETDATA_PREFIX}${TPUT_YELLOW}'${TPUT_RESET} > "
 	else
-		eval "read >&2 -ep \$'\001${TPUT_BOLD}${TPUT_GREEN}\002Press ENTER to build and install netdata to your system\001${TPUT_RESET}\002 > ' -e -r REPLY"
-		[ $? -ne 0 ] && exit 1
+		echo -n "${TPUT_BOLD}${TPUT_GREEN}Press ENTER to build and install netdata to your system${TPUT_RESET} > "
+	fi
+	read -ern1
+	if [ "$REPLY" != '' ]; then
+		exit 1
 	fi
+
 fi
 
 build_error() {
@@ -466,7 +395,7 @@ run make clean
 # -----------------------------------------------------------------------------
 progress "Compile netdata"
 
-run make -j${SYSTEM_CPUS} || exit 1
+run make -j$(find_processors) || exit 1
 
 # -----------------------------------------------------------------------------
 progress "Migrate configuration files for node.d.plugin and charts.d.plugin"
@@ -506,7 +435,7 @@ fi
 # -----------------------------------------------------------------------------
 
 # shellcheck disable=SC2230
-md5sum="$(which md5sum 2>/dev/null || command -v md5sum 2>/dev/null || command -v md5 2>/dev/null)"
+md5sum="$(command -v md5sum 2>/dev/null || command -v md5 2>/dev/null)"
 
 deleted_stock_configs=0
 if [ ! -f "${NETDATA_PREFIX}/etc/netdata/.installer-cleanup-of-stock-configs-done" ]; then
@@ -583,9 +512,19 @@ run find ./system/ -type f -a \! -name \*.in -a \! -name Makefile\* -a \! -name
 # -----------------------------------------------------------------------------
 progress "Add user netdata to required user groups"
 
-homedir="${NETDATA_PREFIX}/var/lib/netdata"
-[ ! -z "${NETDATA_PREFIX}" ] && homedir="${NETDATA_PREFIX}"
-add_netdata_user_and_group "${homedir}" || run_failed "The installer does not run as root."
+NETDATA_WANTED_GROUPS="docker nginx varnish haproxy adm nsd proxy squid ceph nobody"
+NETDATA_ADDED_TO_GROUPS=""
+if [ "${UID}" -eq 0 ]; then
+	portable_add_group netdata || :
+	portable_add_user netdata "${NETDATA_PREFIX}/var/lib/netdata" || :
+
+	for g in ${NETDATA_WANTED_GROUPS}; do
+		# shellcheck disable=SC2086
+		portable_add_user_to_group ${g} netdata && NETDATA_ADDED_TO_GROUPS="${NETDATA_ADDED_TO_GROUPS} ${g}"
+	done
+else
+	run_failed "The installer does not run as root."
+fi
 
 # -----------------------------------------------------------------------------
 progress "Install logrotate configuration for netdata"
@@ -621,14 +560,14 @@ else
 	NETDATA_USER="${USER}"
 	ROOT_USER="${NETDATA_USER}"
 fi
-NETDATA_GROUP="$(id -g -n ${NETDATA_USER})"
+NETDATA_GROUP="$(id -g -n "${NETDATA_USER}")"
 [ -z "${NETDATA_GROUP}" ] && NETDATA_GROUP="${NETDATA_USER}"
 
 # the owners of the web files
 NETDATA_WEB_USER="$(config_option "web" "web files owner" "${NETDATA_USER}")"
 NETDATA_WEB_GROUP="${NETDATA_GROUP}"
-if [ "${UID}" = "0" -a "${NETDATA_USER}" != "${NETDATA_WEB_USER}" ]; then
-	NETDATA_WEB_GROUP="$(id -g -n ${NETDATA_WEB_USER})"
+if [ "${UID}" = "0" ] && [ "${NETDATA_USER}" != "${NETDATA_WEB_USER}" ]; then
+	NETDATA_WEB_GROUP="$(id -g -n "${NETDATA_WEB_USER}")"
 	[ -z "${NETDATA_WEB_GROUP}" ] && NETDATA_WEB_GROUP="${NETDATA_WEB_USER}"
 fi
 NETDATA_WEB_GROUP="$(config_option "web" "web files group" "${NETDATA_WEB_GROUP}")"
@@ -733,7 +672,7 @@ run chmod 755 "${NETDATA_LOG_DIR}"
 
 # --- plugins ----
 
-if [ ${UID} -eq 0 ]; then
+if [ "${UID}" -eq 0 ]; then
 	# find the admin group
 	admin_group=
 	test -z "${admin_group}" && getent group root >/dev/null 2>&1 && admin_group="root"
@@ -741,47 +680,38 @@ if [ ${UID} -eq 0 ]; then
 	test -z "${admin_group}" && admin_group="${NETDATA_GROUP}"
 
 	run chown "${NETDATA_USER}:${admin_group}" "${NETDATA_LOG_DIR}"
-	run chown -R root "${NETDATA_PREFIX}/usr/libexec/netdata"
+	run chown -R "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata"
 	run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type d -exec chmod 0755 {} \;
 	run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type f -exec chmod 0644 {} \;
 	run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type f -a -name \*.plugin -exec chmod 0755 {} \;
 	run find "${NETDATA_PREFIX}/usr/libexec/netdata" -type f -a -name \*.sh -exec chmod 0755 {} \;
 
 	if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin" ]; then
-		setcap_ret=1
-		if ! iscontainer; then
-			if [ ! -z "${setcap}" ]; then
-				run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-				run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-				run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
-				setcap_ret=$?
-			fi
-
-			if [ ${setcap_ret} -eq 0 ]; then
-				# if we managed to setcap
-				# but we fail to execute apps.plugin
-				# trigger setuid to root
-				"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin" -t >/dev/null 2>&1
-				setcap_ret=$?
+		run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+		capabilities=0
+		if ! iscontainer && command -v setcap 1>/dev/null 2>&1; then
+			run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
+			if run setcap cap_dac_read_search,cap_sys_ptrace+ep "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"; then
+				# if we managed to setcap, but we fail to execute apps.plugin setuid to root
+				"${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin" -t >/dev/null 2>&1 && capabilities=1 || capabilities=0
 			fi
 		fi
 
-		if [ ${setcap_ret} -ne 0 ]; then
+		if [ $capabilities -eq 0 ]; then
 			# fix apps.plugin to be setuid to root
-			run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
 			run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/apps.plugin"
 		fi
 	fi
 
 	if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin" ]; then
-		run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
+		run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
 		run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/freeipmi.plugin"
 	fi
 
-    if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin" ]; then
-        run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin"
-        run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin"
-    fi
+	if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin" ]; then
+		run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin"
+		run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/nfacct.plugin"
+	fi
 
     if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/xenstat.plugin" ]; then
         run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/xenstat.plugin"
@@ -789,12 +719,12 @@ if [ ${UID} -eq 0 ]; then
     fi
 
 	if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network" ]; then
-		run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network"
+		run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network"
 		run chmod 4750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network"
 	fi
 
 	if [ -f "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh" ]; then
-		run chown root "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh"
+		run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh"
 		run chmod 0550 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/cgroup-network-helper.sh"
 	fi
 
@@ -841,8 +771,8 @@ install_go() {
 		download "https://github.com/netdata/go.d.plugin/releases/download/$GO_PACKAGE_VERSION/$GO_PACKAGE_BASENAME" "${tmp}/$GO_PACKAGE_BASENAME"
 
 		download "https://github.com/netdata/go.d.plugin/releases/download/$GO_PACKAGE_VERSION/config.tar.gz" "${tmp}/config.tar.gz"
-		grep "${GO_PACKAGE_BASENAME}\$" "${installer_dir}/packaging/go.d.checksums" > "${tmp}/sha256sums.txt" 2>/dev/null
-		grep "config.tar.gz" "${installer_dir}/packaging/go.d.checksums" >> "${tmp}/sha256sums.txt" 2>/dev/null
+		grep "${GO_PACKAGE_BASENAME}\$" "${INSTALLER_DIR}/packaging/go.d.checksums" > "${tmp}/sha256sums.txt" 2>/dev/null
+		grep "config.tar.gz" "${INSTALLER_DIR}/packaging/go.d.checksums" >> "${tmp}/sha256sums.txt" 2>/dev/null
 
 		# Checksum validation
 		if ! (cd "${tmp}" && sha256sum -c "sha256sums.txt"); then
@@ -857,8 +787,8 @@ install_go() {
 		run chown -R "${ROOT_USER}:${NETDATA_GROUP}" "${NETDATA_STOCK_CONFIG_DIR}"
 
 		run mv "${tmp}/$GO_PACKAGE_BASENAME" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/go.d.plugin"
-		if [ ${UID} -eq 0 ]; then
-			run chown root:${NETDATA_GROUP} "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/go.d.plugin"
+		if [ "${UID}" -eq 0 ]; then
+			run chown "root:${NETDATA_GROUP}" "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/go.d.plugin"
 		fi
 		run chmod 0750 "${NETDATA_PREFIX}/usr/libexec/netdata/plugins.d/go.d.plugin"
 	fi
@@ -866,11 +796,6 @@ install_go() {
 }
 install_go
 
-# --- fix #1292 bug ---
-
-[ -d "${NETDATA_PREFIX}/usr/libexec" ] && run chmod a+rX "${NETDATA_PREFIX}/usr/libexec"
-[ -d "${NETDATA_PREFIX}/usr/share/netdata" ] && run chmod a+rX "${NETDATA_PREFIX}/usr/share/netdata"
-
 # -----------------------------------------------------------------------------
 progress "Install netdata at system init"
 
@@ -880,28 +805,23 @@ install_netdata_service || run_failed "Cannot install netdata init service."
 # -----------------------------------------------------------------------------
 # check if we can re-start netdata
 
+# TODO(paulfantom): Creation of configuration file should be handled by a build system. Additionally we shouldn't touch configuration files in /etc/netdata/...
 started=0
 if [ ${DONOTSTART} -eq 1 ]; then
-	generate_netdata_conf "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" "http://localhost:${NETDATA_PORT}/netdata.conf"
-
+	create_netdata_conf "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
 else
-	restart_netdata ${NETDATA_PREFIX}/usr/sbin/netdata "${@}"
-	if [ $? -ne 0 ]; then
-		echo >&2
-		echo >&2 "SORRY! FAILED TO START NETDATA!"
-		echo >&2
-		exit 1
+	if ! restart_netdata "${NETDATA_PREFIX}/usr/sbin/netdata" "${@}"; then
+		fatal "Cannot start netdata!"
 	fi
 
 	started=1
-	echo >&2 "OK. NetData Started!"
-	echo >&2
-
-	# -----------------------------------------------------------------------------
-	# save a config file, if it is not already there
-
-	download_netdata_conf "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf" "http://localhost:${NETDATA_PORT}/netdata.conf"
+	run_ok "netdata started!"
+	create_netdata_conf "${NETDATA_PREFIX}/etc/netdata/netdata.conf" "http://localhost:${NETDATA_PORT}/netdata.conf"
+fi
+if [ "${UID}" -eq 0 ]; then
+        run chown "${NETDATA_USER}" "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
 fi
+run chmod 0664 "${NETDATA_PREFIX}/etc/netdata/netdata.conf"
 
 if [ "$(uname)" = "Linux" ]; then
 	# -------------------------------------------------------------------------
@@ -941,7 +861,7 @@ KSM2
 	}
 
 	if [ -f "/sys/kernel/mm/ksm/run" ]; then
-		if [ $(cat "/sys/kernel/mm/ksm/run") != "1" ]; then
+		if [ "$(cat "/sys/kernel/mm/ksm/run")" != "1" ]; then
 			ksm_is_available_but_disabled
 		fi
 	else
@@ -1044,17 +964,11 @@ if [ "${AUTOUPDATE}" = "1" ]; then
 			fi
 			progress "Installing new netdata-updater in cron"
 
-			rm ${installer_dir}/netdata-updater.sh || : #TODO(paulfantom): this workaround should be removed after v1.13.0-rc1. It just needs to be propagated
-
 			rm -f "${crondir}/netdata-updater"
-			if [ -f "${installer_dir}/packaging/installer/netdata-updater.sh" ]; then
-				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${installer_dir}/packaging/installer/netdata-updater.sh" > ${crondir}/netdata-updater || exit 1
-				 #TODO(paulfantom): Following line is a workaround and should be removed after v1.13.0-rc1. It just needs time to be propagated.
-				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${installer_dir}/packaging/installer/netdata-updater.sh" > ${installer_dir}/netdata-updater.sh || exit 1
+			if [ -f "${INSTALLER_DIR}/packaging/installer/netdata-updater.sh" ]; then
+				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${INSTALLER_DIR}/packaging/installer/netdata-updater.sh" > "${crondir}/netdata-updater" || exit 1
 			else
-				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${netdata_source_dir}/packaging/installer/netdata-updater.sh" > ${crondir}/netdata-updater || exit 1
-				 #TODO(paulfantom): Following line is a workaround and should be removed after v1.13.0-rc1. It just needs time to be propagated.
-				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${netdata_source_dir}/packaging/installer/netdata-updater.sh" > ${installer_source_dir}/netdata-updater.sh || exit 1
+				sed "s|THIS_SHOULD_BE_REPLACED_BY_INSTALLER_SCRIPT|${NETDATA_USER_CONFIG_DIR}/.environment|" "${NETDATA_SOURCE_DIR}/packaging/installer/netdata-updater.sh" > "${crondir}/netdata-updater" || exit 1
 			fi
 
 			chmod 0755 ${crondir}/netdata-updater
@@ -1067,7 +981,7 @@ if [ "${AUTOUPDATE}" = "1" ]; then
 fi
 
 # Save environment variables
-cat <<EOF > ${NETDATA_USER_CONFIG_DIR}/.environment
+cat <<EOF > "${NETDATA_USER_CONFIG_DIR}/.environment"
 # Created by installer
 PATH="${PATH}"
 CFLAGS="${CFLAGS}"
@@ -1083,7 +997,7 @@ EOF
 
 # Opt-out from telemetry program
 if [ -n "${NETDATA_DISABLE_TELEMETRY+x}" ]; then
-	touch ${NETDATA_USER_CONFIG_DIR}/.opt-out-from-anonymous-statistics
+	touch "${NETDATA_USER_CONFIG_DIR}/.opt-out-from-anonymous-statistics"
 fi
 
 # -----------------------------------------------------------------------------

+ 159 - 280
packaging/installer/functions.sh

@@ -5,19 +5,6 @@
 # make sure we have a UID
 [ -z "${UID}" ] && UID="$(id -u)"
 
-# -----------------------------------------------------------------------------
-# checking the availability of commands
-
-which_cmd() {
-	# shellcheck disable=SC2230
-	which "${1}" 2>/dev/null || command -v "${1}" 2>/dev/null
-}
-
-check_cmd() {
-	which_cmd "${1}" >/dev/null 2>&1 && return 0
-	return 1
-}
-
 # -----------------------------------------------------------------------------
 
 setup_terminal() {
@@ -50,7 +37,7 @@ setup_terminal() {
 	# Is stderr on the terminal? If not, then fail
 	test -t 2 || return 1
 
-	if check_cmd tput; then
+	if command -v tput 1>/dev/null 2>&1; then
 		if [ $(($(tput colors 2>/dev/null))) -ge 8 ]; then
 			# Enable colors
 			TPUT_RESET="$(tput sgr 0)"
@@ -117,19 +104,20 @@ netdata_banner() {
 # -----------------------------------------------------------------------------
 # portable service command
 
-service_cmd="$(which_cmd service)"
-rcservice_cmd="$(which_cmd rc-service)"
-systemctl_cmd="$(which_cmd systemctl)"
+service_cmd="$(command -v service 2>/dev/null)"
+rcservice_cmd="$(command -v rc-service 2>/dev/null)"
+systemctl_cmd="$(command -v systemctl 2>/dev/null)"
 service() {
+
 	local cmd="${1}" action="${2}"
 
-	if [ ! -z "${systemctl_cmd}" ]; then
+	if [ -n "${systemctl_cmd}" ]; then
 		run "${systemctl_cmd}" "${action}" "${cmd}"
 		return $?
-	elif [ ! -z "${service_cmd}" ]; then
+	elif [ -n "${service_cmd}" ]; then
 		run "${service_cmd}" "${cmd}" "${action}"
 		return $?
-	elif [ ! -z "${rcservice_cmd}" ]; then
+	elif [ -n "${rcservice_cmd}" ]; then
 		run "${rcservice_cmd}" "${cmd}" "${action}"
 		return $?
 	fi
@@ -139,9 +127,9 @@ service() {
 # -----------------------------------------------------------------------------
 # portable pidof
 
-pidof_cmd="$(which_cmd pidof)"
-pidof() {
-	if [ ! -z "${pidof_cmd}" ]; then
+safe_pidof() {
+	local pidof_cmd="$(command -v pidof 2>/dev/null)"
+	if [ -n "${pidof_cmd}" ]; then
 		${pidof_cmd} "${@}"
 		return $?
 	else
@@ -154,39 +142,21 @@ pidof() {
 }
 
 # -----------------------------------------------------------------------------
-# portable delete recursively interactively
-
-portable_deletedir_recursively_interactively() {
-	if [ ! -z "$1" -a -d "$1" ]; then
-		if [ "$(uname -s)" = "Darwin" ]; then
-			echo >&2
-			read >&2 -p "Press ENTER to recursively delete directory '$1' > "
-			echo >&2 "Deleting directory '$1' ..."
-			run rm -R "$1"
-		else
-			echo >&2
-			echo >&2 "Deleting directory '$1' ..."
-			run rm -I -R "$1"
-		fi
-	else
-		echo "Directory '$1' does not exist."
-	fi
-}
-
-# -----------------------------------------------------------------------------
-
-export SYSTEM_CPUS=1
-portable_find_processors() {
+find_processors() {
+	local cpus
 	if [ -f "/proc/cpuinfo" ]; then
 		# linux
-		SYSTEM_CPUS=$(grep -c ^processor /proc/cpuinfo)
+		cpus=$(grep -c ^processor /proc/cpuinfo)
 	else
 		# freebsd
-		SYSTEM_CPUS=$(sysctl hw.ncpu 2>/dev/null | grep ^hw.ncpu | cut -d ' ' -f 2)
+		cpus=$(sysctl hw.ncpu 2>/dev/null | grep ^hw.ncpu | cut -d ' ' -f 2)
+	fi
+	if [ -z "${cpus}" ] || [ $((cpus)) -lt 1 ]; then
+		echo 1
+	else
+		echo "${cpus}"
 	fi
-	[ -z "${SYSTEM_CPUS}" -o $((SYSTEM_CPUS)) -lt 1 ] && SYSTEM_CPUS=1
 }
-portable_find_processors
 
 # -----------------------------------------------------------------------------
 fatal() {
@@ -248,145 +218,10 @@ run() {
 	return ${ret}
 }
 
-getent_cmd="$(which_cmd getent)"
-portable_check_user_exists() {
-	local username="${1}" found=
-
-	if [ ! -z "${getent_cmd}" ]; then
-		"${getent_cmd}" passwd "${username}" >/dev/null 2>&1
-		return $?
-	fi
-
-	found="$(cut -d ':' -f 1 </etc/passwd | grep "^${username}$")"
-	[ "${found}" = "${username}" ] && return 0
-	return 1
-}
-
-portable_check_group_exists() {
-	local groupname="${1}" found=
-
-	if [ ! -z "${getent_cmd}" ]; then
-		"${getent_cmd}" group "${groupname}" >/dev/null 2>&1
-		return $?
-	fi
-
-	found="$(cut -d ':' -f 1 </etc/group | grep "^${groupname}$")"
-	[ "${found}" = "${groupname}" ] && return 0
-	return 1
-}
-
-portable_check_user_in_group() {
-	local username="${1}" groupname="${2}" users=
-
-	if [ ! -z "${getent_cmd}" ]; then
-		users="$(getent group "${groupname}" | cut -d ':' -f 4)"
-	else
-		users="$(grep "^${groupname}:" </etc/group | cut -d ':' -f 4)"
-	fi
-
-	[[ ",${users}," =~ ,${username}, ]] && return 0
-	return 1
-}
-
-portable_add_user() {
-	local username="${1}" homedir="${2}"
-
-	[ -z "${homedir}" ] && homedir="/tmp"
-
-	portable_check_user_exists "${username}"
-	[ $? -eq 0 ] && echo >&2 "User '${username}' already exists." && return 0
-
-	echo >&2 "Adding ${username} user account with home ${homedir} ..."
-
-	# shellcheck disable=SC2230
-	local nologin="$(which nologin 2>/dev/null || command -v nologin 2>/dev/null || echo '/bin/false')"
-
-	# Linux
-	if check_cmd useradd; then
-		run useradd -r -g "${username}" -c "${username}" -s "${nologin}" --no-create-home -d "${homedir}" "${username}" && return 0
-	fi
-
-	# FreeBSD
-	if check_cmd pw; then
-		run pw useradd "${username}" -d "${homedir}" -g "${username}" -s "${nologin}" && return 0
-	fi
-
-	# BusyBox
-	if check_cmd adduser; then
-		run adduser -h "${homedir}" -s "${nologin}" -D -G "${username}" "${username}" && return 0
-	fi
-
-	echo >&2 "Failed to add ${username} user account !"
-
-	return 1
-}
-
-portable_add_group() {
-	local groupname="${1}"
-
-	portable_check_group_exists "${groupname}"
-	[ $? -eq 0 ] && echo >&2 "Group '${groupname}' already exists." && return 0
-
-	echo >&2 "Adding ${groupname} user group ..."
-
-	# Linux
-	if check_cmd groupadd; then
-		run groupadd -r "${groupname}" && return 0
-	fi
-
-	# FreeBSD
-	if check_cmd pw; then
-		run pw groupadd "${groupname}" && return 0
-	fi
-
-	# BusyBox
-	if check_cmd addgroup; then
-		run addgroup "${groupname}" && return 0
-	fi
-
-	echo >&2 "Failed to add ${groupname} user group !"
-	return 1
-}
-
-portable_add_user_to_group() {
-	local groupname="${1}" username="${2}"
-
-	portable_check_group_exists "${groupname}"
-	[ $? -ne 0 ] && echo >&2 "Group '${groupname}' does not exist." && return 1
-
-	# find the user is already in the group
-	if portable_check_user_in_group "${username}" "${groupname}"; then
-		# username is already there
-		echo >&2 "User '${username}' is already in group '${groupname}'."
-		return 0
-	else
-		# username is not in group
-		echo >&2 "Adding ${username} user to the ${groupname} group ..."
-
-		# Linux
-		if check_cmd usermod; then
-			run usermod -a -G "${groupname}" "${username}" && return 0
-		fi
-
-		# FreeBSD
-		if check_cmd pw; then
-			run pw groupmod "${groupname}" -m "${username}" && return 0
-		fi
-
-		# BusyBox
-		if check_cmd addgroup; then
-			run addgroup "${username}" "${groupname}" && return 0
-		fi
-
-		echo >&2 "Failed to add user ${username} to group ${groupname} !"
-		return 1
-	fi
-}
-
 iscontainer() {
 	# man systemd-detect-virt
-	local cmd=$(which_cmd systemd-detect-virt)
-	if [ ! -z "${cmd}" -a -x "${cmd}" ]; then
+	local cmd=$(command -v systemd-detect-virt 2>/dev/null)
+	if [ -n "${cmd}" ] && [ -x "${cmd}" ]; then
 		"${cmd}" --container >/dev/null 2>&1 && return 0
 	fi
 
@@ -394,15 +229,15 @@ iscontainer() {
 	# http://stackoverflow.com/a/37016302
 	local pid=$(cat /proc/1/sched 2>/dev/null | head -n 1 | {
 		IFS='(),#:' read name pid th threads
-		echo $pid
+		echo "$pid"
 	})
-	if [ ! -z "${pid}" ]; then
+	if [ -n "${pid}" ]; then
 		pid=$(( pid + 0 ))
 		[ ${pid} -gt 1 ] && return 0
 	fi
 
 	# lxc sets environment variable 'container'
-	[ ! -z "${container}" ] && return 0
+	[ -n "${container}" ] && return 0
 
 	# docker creates /.dockerenv
 	# http://stackoverflow.com/a/25518345
@@ -425,23 +260,23 @@ issystemd() {
 
 	# if there is no systemctl command, it is not systemd
 	# shellcheck disable=SC2230
-	systemctl=$(which systemctl 2>/dev/null || command -v systemctl 2>/dev/null)
+	systemctl=$(command -v systemctl 2>/dev/null)
 	[ -z "${systemctl}" -o ! -x "${systemctl}" ] && return 1
 
 	# if pid 1 is systemd, it is systemd
 	[ "$(basename $(readlink /proc/1/exe) 2>/dev/null)" = "systemd" ] && return 0
 
 	# if systemd is not running, it is not systemd
-	pids=$(pidof systemd 2>/dev/null)
+	pids=$(safe_pidof systemd 2>/dev/null)
 	[ -z "${pids}" ] && return 1
 
 	# check if the running systemd processes are not in our namespace
 	myns="$(readlink /proc/self/ns/pid 2>/dev/null)"
 	for p in ${pids}; do
-		ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)"
+		ns="$(readlink "/proc/${p}/ns/pid" 2>/dev/null)"
 
 		# if pid of systemd is in our namespace, it is systemd
-		[ ! -z "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0
+		[ -n "${myns}" ] && [ "${myns}" = "${ns}" ] && return 0
 	done
 
 	# else, it is not systemd
@@ -460,7 +295,7 @@ install_non_systemd_init() {
 		key=$(</etc/redhat-release)
 	fi
 
-	if [ -d /etc/init.d -a ! -f /etc/init.d/netdata ]; then
+	if [ -d /etc/init.d ] && [ ! -f /etc/init.d/netdata ]; then
 		if [[ ${key} =~ ^(gentoo|alpine).* ]]; then
 			echo >&2 "Installing OpenRC init file..."
 			run cp system/netdata-openrc /etc/init.d/netdata &&
@@ -468,10 +303,7 @@ install_non_systemd_init() {
 				run rc-update add netdata default &&
 				return 0
 
-		elif [ "${key}" = "debian-7" \
-			-o "${key}" = "ubuntu-12.04" \
-			-o "${key}" = "ubuntu-14.04" \
-			]; then
+		elif [ "${key}" = "debian-7" ] || [ "${key}" = "ubuntu-12.04" ] || [ "${key}" = "ubuntu-14.04" ]; then
 			echo >&2 "Installing LSB init file..."
 			run cp system/netdata-lsb /etc/init.d/netdata &&
 				run chmod 755 /etc/init.d/netdata &&
@@ -551,10 +383,10 @@ install_netdata_service() {
 			local ret=$?
 
 			if [ ${ret} -eq 0 ]; then
-				if [ ! -z "${service_cmd}" ]; then
+				if [ -n "${service_cmd}" ]; then
 					NETDATA_START_CMD="service netdata start"
 					NETDATA_STOP_CMD="service netdata stop"
-				elif [ ! -z "${rcservice_cmd}" ]; then
+				elif [ -n "${rcservice_cmd}" ]; then
 					NETDATA_START_CMD="rc-service netdata start"
 					NETDATA_STOP_CMD="rc-service netdata stop"
 				fi
@@ -582,10 +414,10 @@ pidisnetdata() {
 stop_netdata_on_pid() {
 	local pid="${1}" ret=0 count=0
 
-	pidisnetdata ${pid} || return 0
+	pidisnetdata "${pid}" || return 0
 
-	printf >&2 "Stopping netdata on pid ${pid} ..."
-	while [ ! -z "$pid" -a ${ret} -eq 0 ]; do
+	printf >&2 "Stopping netdata on pid %s ..." "${pid}"
+	while [ -n "$pid" ] && [ ${ret} -eq 0 ]; do
 		if [ ${count} -gt 45 ]; then
 			echo >&2 "Cannot stop the running netdata on pid ${pid}."
 			return 1
@@ -593,7 +425,7 @@ stop_netdata_on_pid() {
 
 		count=$((count + 1))
 
-		run kill ${pid} 2>/dev/null
+		run kill "${pid}" 2>/dev/null
 		ret=$?
 
 		test ${ret} -eq 0 && printf >&2 "." && sleep 2
@@ -619,11 +451,11 @@ netdata_pids() {
 	for p in \
 		$(cat /var/run/netdata.pid 2>/dev/null) \
 		$(cat /var/run/netdata/netdata.pid 2>/dev/null) \
-		$(pidof netdata 2>/dev/null); do
-		ns="$(readlink /proc/${p}/ns/pid 2>/dev/null)"
+		$(safe_pidof netdata 2>/dev/null); do
+		ns="$(readlink "/proc/${p}/ns/pid" 2>/dev/null)"
 
-		if [ -z "${myns}" -o -z "${ns}" -o "${myns}" = "${ns}" ]; then
-			pidisnetdata ${p} && echo "${p}"
+		if [ -z "${myns}" ] || [ -z "${ns}" ] || [ "${myns}" = "${ns}" ]; then
+			pidisnetdata "${p}" && echo "${p}"
 		fi
 	done
 }
@@ -631,6 +463,7 @@ netdata_pids() {
 stop_all_netdata() {
 	local p
 	for p in $(netdata_pids); do
+		# shellcheck disable=SC2086
 		stop_netdata_on_pid ${p}
 	done
 }
@@ -651,7 +484,7 @@ restart_netdata() {
 		stop_all_netdata
 		service netdata restart && started=1
 
-		if [ ${started} -eq 1 -a -z "$(netdata_pids)" ]; then
+		if [ ${started} -eq 1 ] && [ -z "$(netdata_pids)" ]; then
 			echo >&2 "Ooops! it seems netdata is not started."
 			started=0
 		fi
@@ -661,7 +494,7 @@ restart_netdata() {
 		fi
 	fi
 
-	if [ ${started} -eq 1 -a -z "$(netdata_pids)" ]; then
+	if [ ${started} -eq 1 ] && [ -z "$(netdata_pids)" ]; then
 		echo >&2 "Hm... it seems netdata is still not started."
 		started=0
 	fi
@@ -681,7 +514,7 @@ restart_netdata() {
 # install netdata logrotate
 
 install_netdata_logrotate() {
-	if [ ${UID} -eq 0 ]; then
+	if [ "${UID}" -eq 0 ]; then
 		if [ -d /etc/logrotate.d ]; then
 			if [ ! -f /etc/logrotate.d/netdata ]; then
 				run cp system/netdata.logrotate /etc/logrotate.d/netdata
@@ -699,103 +532,149 @@ install_netdata_logrotate() {
 }
 
 # -----------------------------------------------------------------------------
-# download netdata.conf
+# create netdata.conf
 
-fix_netdata_conf() {
-	local owner="${1}"
+create_netdata_conf() {
+	local path="${1}" url="${2}"
 
-	if [ "${UID}" -eq 0 ]; then
-		run chown "${owner}" "${filename}"
-	fi
-	run chmod 0664 "${filename}"
-}
-
-generate_netdata_conf() {
-	local owner="${1}" filename="${2}" url="${3}"
-
-	if [ ! -s "${filename}" ]; then
-		cat >"${filename}" <<EOFCONF
-# netdata can generate its own config.
-# Get it with:
-#
-# wget -O ${filename} "${url}"
-#
-# or
-#
-# curl -s -o ${filename} "${url}"
-#
-EOFCONF
-		fix_netdata_conf "${owner}"
+	if [ -s "${path}" ]; then
+		return 0
 	fi
-}
 
-download_netdata_conf() {
-	local owner="${1}" filename="${2}" url="${3}"
-
-	if [ ! -s "${filename}" ]; then
-		echo >&2
-		echo >&2 "-------------------------------------------------------------------------------"
-		echo >&2
+	if [ -n "$url" ]; then
 		echo >&2 "Downloading default configuration from netdata..."
 		sleep 5
 
-		# remove a possibly obsolete download
-		[ -f "${filename}.new" ] && rm "${filename}.new"
+		# remove a possibly obsolete configuration file
+		[ -f "${path}.new" ] && rm "${path}.new"
 
 		# disable a proxy to get data from the local netdata
 		export http_proxy=
 		export https_proxy=
 
-		# try curl
-		run curl -s -o "${filename}.new" "${url}"
-		ret=$?
-
-		if [ ${ret} -ne 0 -o ! -s "${filename}.new" ]; then
-			# try wget
-			run wget -O "${filename}.new" "${url}"
-			ret=$?
+		if command -v curl 1>/dev/null 2>&1; then
+			run curl -sSL --connect-timeout 10 --retry 3 "${url}" >"${path}.new"
+		elif command -v wget 1>/dev/null 2>&1; then
+			run wget -T 15 -O - "${url}" >"${path}.new"
 		fi
 
-		if [ ${ret} -eq 0 -a -s "${filename}.new" ]; then
-			run mv "${filename}.new" "${filename}"
-			run_ok "New configuration saved for you to edit at ${filename}"
+		if [ -s "${path}.new" ]; then
+			run mv "${path}.new" "${path}"
+			run_ok "New configuration saved for you to edit at ${path}"
 		else
-			[ -f "${filename}.new" ] && rm "${filename}.new"
+			[ -f "${path}.new" ] && rm "${path}.new"
 			run_failed "Cannnot download configuration from netdata daemon using url '${url}'"
-
-			generate_netdata_conf "${owner}" "${filename}" "${url}"
+			url=''
 		fi
+	fi
 
-		fix_netdata_conf "${owner}"
+	if [ -z "$url" ]; then
+		echo "# netdata can generate its own config which is available at 'http://<netdata_ip>/netdata.conf'" >"${path}"
+		echo "# You can download it with command like: 'wget -O ${path} http://localhost:19999/netdata.conf'" >>"${path}"
 	fi
+
 }
 
-# -----------------------------------------------------------------------------
-# add netdata user and group
+portable_add_user() {
+	local username="${1}" homedir="${2}"
 
-NETDATA_WANTED_GROUPS="docker nginx varnish haproxy adm nsd proxy squid ceph nobody"
-NETDATA_ADDED_TO_GROUPS=""
-add_netdata_user_and_group() {
-	local homedir="${1}" g
+	[ -z "${homedir}" ] && homedir="/tmp"
+
+    # Check if user exists
+	if cut -d ':' -f 1 </etc/passwd | grep "^${username}$" 1>/dev/null 2>&1; then
+        echo >&2 "User '${username}' already exists."
+        return 0
+    fi
 
-	if [ ${UID} -eq 0 ]; then
-		portable_add_group netdata || return 1
-		portable_add_user netdata "${homedir}" || return 1
+	echo >&2 "Adding ${username} user account with home ${homedir} ..."
 
-		for g in ${NETDATA_WANTED_GROUPS}; do
-			portable_add_user_to_group ${g} netdata && NETDATA_ADDED_TO_GROUPS="${NETDATA_ADDED_TO_GROUPS} ${g}"
-		done
+	# shellcheck disable=SC2230
+	local nologin="$(command -v nologin >/dev/null 2>&1 || echo '/bin/false')"
 
-		[ ~netdata = / ] && cat <<USERMOD
+	# Linux
+	if command -v useradd 1>/dev/null 2>&1; then
+		run useradd -r -g "${username}" -c "${username}" -s "${nologin}" --no-create-home -d "${homedir}" "${username}" && return 0
+	fi
 
-The netdata user has its home directory set to /
-You may want to change it, using this command:
+	# FreeBSD
+	if command -v pw 1>/dev/null 2>&1; then
+		run pw useradd "${username}" -d "${homedir}" -g "${username}" -s "${nologin}" && return 0
+	fi
 
-# usermod -d "${homedir}" netdata
+	# BusyBox
+	if command -v adduser 1>/dev/null 2>&1; then
+		run adduser -h "${homedir}" -s "${nologin}" -D -G "${username}" "${username}" && return 0
+	fi
 
-USERMOD
-		return 0
+	echo >&2 "Failed to add ${username} user account !"
+
+	return 1
+}
+
+portable_add_group() {
+	local groupname="${1}"
+
+    # Check if group exist
+	if cut -d ':' -f 1 </etc/group | grep "^${groupname}$" 1>/dev/null 2>&1; then
+        echo >&2 "Group '${groupname}' already exists."
+        return 0
+    fi
+
+	echo >&2 "Adding ${groupname} user group ..."
+
+	# Linux
+	if command -v groupadd 1>/dev/null 2>&1; then
+		run groupadd -r "${groupname}" && return 0
 	fi
 
+	# FreeBSD
+	if command -v pw 1>/dev/null 2>&1; then
+		run pw groupadd "${groupname}" && return 0
+	fi
+
+	# BusyBox
+	if command -v addgroup 1>/dev/null 2>&1; then
+		run addgroup "${groupname}" && return 0
+	fi
+
+	echo >&2 "Failed to add ${groupname} user group !"
 	return 1
 }
+
+portable_add_user_to_group() {
+	local groupname="${1}" username="${2}"
+
+    # Check if group exist
+	if ! cut -d ':' -f 1 </etc/group | grep "^${groupname}$" >/dev/null 2>&1; then
+        echo >&2 "Group '${groupname}' does not exist."
+        return 1
+    fi
+
+    # Check if user is in group
+	if [[ ",$(grep "^${groupname}:" </etc/group | cut -d ':' -f 4)," =~ ,${username}, ]]; then
+		# username is already there
+		echo >&2 "User '${username}' is already in group '${groupname}'."
+		return 0
+	else
+		# username is not in group
+		echo >&2 "Adding ${username} user to the ${groupname} group ..."
+
+		# Linux
+		if command -v usermod 1>/dev/null 2>&1; then
+			run usermod -a -G "${groupname}" "${username}" && return 0
+		fi
+
+		# FreeBSD
+		if command -v pw 1>/dev/null 2>&1; then
+			run pw groupmod "${groupname}" -m "${username}" && return 0
+		fi
+
+		# BusyBox
+		if command -v addgroup 1>/dev/null 2>&1; then
+			run addgroup "${username}" "${groupname}" && return 0
+		fi
+
+		echo >&2 "Failed to add user ${username} to group ${groupname} !"
+		return 1
+	fi
+}

+ 27 - 19
packaging/makeself/install-or-update.sh

@@ -71,18 +71,27 @@ fi
 # -----------------------------------------------------------------------------
 progress "Add user netdata to required user groups"
 
-NETDATA_USER="root"
-NETDATA_GROUP="root"
-add_netdata_user_and_group "/opt/netdata"
-if [ $? -eq 0 ]
-    then
-    NETDATA_USER="netdata"
-    NETDATA_GROUP="netdata"
+NETDATA_WANTED_GROUPS="docker nginx varnish haproxy adm nsd proxy squid ceph nobody"
+NETDATA_ADDED_TO_GROUPS=""
+if [ "${UID}" -eq 0 ]; then
+        if ! portable_add_group netdata; then
+		run_failed "Failed to add netdata group"
+		NETDATA_GROUP="root"
+        fi
+        if ! portable_add_user netdata "/opt/netdata"; then
+		run_failed "Failed to add netdata user"
+		NETDATA_USER="root"
+        fi
+
+        for g in ${NETDATA_WANTED_GROUPS}; do
+                # shellcheck disable=SC2086
+                portable_add_user_to_group ${g} netdata && NETDATA_ADDED_TO_GROUPS="${NETDATA_ADDED_TO_GROUPS} ${g}" || run_failed "Failed to add netdata user to secondary groups"
+        done
 else
-    run_failed "Failed to add netdata user and group"
+	run_failed "Failed to add netdata user and group"
+        run_failed "The installer does not run as root."
 fi
 
-
 # -----------------------------------------------------------------------------
 progress "Check SSL certificates paths"
 
@@ -206,20 +215,19 @@ fi
 
 # -----------------------------------------------------------------------------
 
-if [ ${STARTIT} -eq 1 ]
-then
+if [ ${STARTIT} -eq 0 ]; then
+    create_netdata_conf "/opt/netdata/etc/netdata/netdata.conf"
+    netdata_banner "is installed now!"
+else
     progress "starting netdata"
 
-    restart_netdata "/opt/netdata/bin/netdata"
-    if [ $? -eq 0 ]
-        then
-        download_netdata_conf "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf"
+    if ! restart_netdata "/opt/netdata/bin/netdata"; then
+        create_netdata_conf "/opt/netdata/etc/netdata/netdata.conf"
         netdata_banner "is installed and running now!"
     else
-        generate_netdata_conf "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf"
+        create_netdata_conf "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf"
         netdata_banner "is installed now!"
     fi
-else
-    generate_netdata_conf "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf" "http://localhost:19999/netdata.conf"
-    netdata_banner "is installed now!"
 fi
+run chown "${NETDATA_USER}:${NETDATA_GROUP}" "/opt/netdata/etc/netdata/netdata.conf"
+run chmod 0664 "/opt/netdata/etc/netdata/netdata.conf"

+ 1 - 1
packaging/makeself/jobs/50-bash-4.4.18.install.sh

@@ -38,7 +38,7 @@ run ./configure \
 
 
 run make clean
-run make -j${SYSTEM_CPUS}
+run make -j$(find_processors)
 
 cat >examples/loadables/Makefile <<EOF
 all:

+ 1 - 1
packaging/makeself/jobs/50-curl-7.60.0.install.sh

@@ -25,7 +25,7 @@ run ./configure \
 run sed -i -e "s/curl_LDFLAGS =/curl_LDFLAGS = -all-static/" src/Makefile
 
 run make clean
-run make -j${SYSTEM_CPUS}
+run make -j$(find_processors)
 run make install
 
 if [ ${NETDATA_BUILD_WITH_DEBUG} -eq 0 ]

+ 1 - 1
packaging/makeself/jobs/50-fping-4.2.install.sh

@@ -20,7 +20,7 @@ install:
 EOF
 
 run make clean
-run make -j${SYSTEM_CPUS}
+run make -j$(find_processors)
 run make install
 
 if [ ${NETDATA_BUILD_WITH_DEBUG} -eq 0 ]