#!/bin/sh

# Shell script with utilities for the modules of scc.
# Copyright (C) 2001-2004 Open Challenge B.V.
# Copyright (C) 2004-2005 OpenEyeT Professional Services.
# Copyright (C) 2005-2009 QNH.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING.
# If not, write to the Free Software Foundation,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# Contact information: http://scc.qnh-infrastructure.nl/index.html 

# This is a system module of scc, to call it separately in the
# proper environment, use: scc-collect -i -e <module_name>

# SCC-release:	1.9.28
# file-version:	$Revision: 1.89 $

set -u

export TMP_FILE=${SCC_TMP}/scc_utils_$$

# Use the following utilities for SunOS.
AWK=awk
if [ -x /usr/xpg4/bin/awk ]
then
	alias awk=/usr/xpg4/bin/awk
	AWK=/usr/xpg4/bin/awk
fi
if [ -x /usr/xpg4/bin/grep ]
then
	alias grep=/usr/xpg4/bin/grep
fi
if [ -x /usr/xpg4/bin/id ]
then
	alias id=/usr/xpg4/bin/id
fi
if [ -x /usr/xpg4/bin/df ]
then
	alias df=/usr/xpg4/bin/df
fi
if [ -x /usr/xpg4/bin/tail ]
then
	alias tail=/usr/xpg4/bin/tail
fi
if [ -x /usr/xpg4/bin/tr ]
then
	alias tr=/usr/xpg4/bin/tr
fi
export AWK

# PuppyLinux does not provide cksum, replace the functionality by a (limited) function
cksum_exe="$(which cksum 2>/dev/null)"
if [ ! -x "${cksum_exe}" ]
then
	cksum()
	{
		if [ $# -eq 0 ]
		then
			wc -c -w
		else
			count="$(wc -c -w <"${1}")"
			echo "${count} ${1}"
		fi
	}
fi

# Use a binary character '\001' as separator for sed substitute statements to avoid clashes.
if [ -z "${sed_sep:-}" ]
then
	sed_sep=$(awk 'END { printf( "%c", 1 ) }' /dev/null)
	export sed_sep
fi

# On a Mandrake MNF the command "file" is absent.
# In that case we ignore the check for binary contents of files.
bin_file_check="yes"
file_exe="$(which file 2>/dev/null)"
if [ ! -x "${file_exe}" ]
then
	bin_file_check=""
fi

# On some systems the command fstyp is missing. Provide a  limited version for the syntax: fstyp -v <fs>
fstyp_exe="$(which fstyp 2>/dev/null)"
if [ ! -x "${fstyp_exe}" ]
then
	# Calling syntax is: fstyp -v <fs>
	fstyp()
	{
		awk	'{
				if ( $2 == fs )
				{
					print $3;
				}
			}' fs="${2}" /etc/fstab 2>/dev/null
	}
fi

# Add help-info to the snapshot.
# Syntax: scc_help_info <class>
# <class> can start with "fix:", "var:", "hlp:" or no prefix at all.
# Help-info is on stdin. Typical a here-document.
scc_help_info()
{
	case "${1}" in
	fix:*|var:*)	utils_h_class="hlp:${1#*:}"
			;;
	hlp:*)		utils_h_class="${1}"
			;;
	*)		utils_h_class="hlp:${1}"
			;;
	esac

	sed -e "s@^@${utils_h_class}@"

	return 0;
}

# Add the contents of the file to the snapshot.
# Syntax: scc_check_file [ --xml ] <file> <prefix> [ <comment-char> ]
# Return:	0	file is present
# 		1	file is absent
scc_check_file()
{
	xml=0
	if [ "X${1}" = "X--xml" ]
	then
		# Force ignore of comments in XML-files that do not start with <xml>.
		xml=1
		shift 1
	fi

	if [ $# -lt 2 -o $# -gt 3 ]
	then
		echo "Syntax error, use: scc_check_file [ --xml ] <file> <prefix> [ <comment-char> ]" >&2
		for arg in $@
		do
			echo "argument: ${arg}" >&2
		done
		return 1
	fi

	# Avoid unbound variable errors when comment is not an argument of this function.
	if [ $# -eq 2 ]
	then
		set "${1}" "${2}" ""
	fi

	check=${2%%::*}
	if [ "${check}" = "${2}" ]
	then
		echo "improper prefix: ${2}, missing '::'" >&2
	fi

	if [ -f "${1}" ]
	then
		# Binary files do not look nice in the snapshots. Use file
		# to avoid files with binary data.
		# List with exceptions:
		# - file thinks that some files in /proc are empty
		#   so, do process empty files
		# - on HP-UX: /etc/default/fs: nettl binary Log file -version 17217
		# - RH uses: empty
		# - SunOS uses: empty file
		utils_action=1;
		if [ -n "${bin_file_check}" ]
		then
			f_type="$(file "${1}" 2>/dev/null | head -n 1)"
			case "${f_type}" in
			*International?Language*)	utils_action=-1;;	# Ignore multibyte characterset files
			*cannot?open*)			utils_action=-1;;	# Ignore NFS-errors.
			*ASCII?text,*)			;;
			*text)				;;
			*empty)				;;
			*empty?file)			;;
			*executable?*?script)		;;
			*script?text?executable)	;;
			*LILO*)				;;
			*shell?script*)			;;
			*symbolic?link?to*)		;;
			/etc/default/fs*)		;;
			*vmware*text*)			;;
			*xml*)				;;
			*XML*)				;;
			*)				utils_action=0;;
			esac
		fi

		if [ ${utils_action} -gt 0 ]
		then
			utils_class="${2}"
			if [ "${1}" != "${1%%:*}" ]		# Filename contains ":"
			then
				# The filename is probably part of the classification.
				# Replace ":" with "_" to avoid confusion with the class-separator.
				utils_new_name="$(echo "${1##*/}" | sed -e 's/:/_/g')"
				utils_class="$(echo "${2}" | sed -e "s@${1##*/}@${utils_new_name}@")"
			fi

			# Ignore comment and blank lines.
			comment_regexp="$(echo "${3:-}" | sed -e 's@/@\\/@g')"		# escape / to avoid conflicts with regexp delimiter of awk.
			${AWK} 'BEGIN {
					squelch = 0;
				}

				# Keep the interpreter line.
				/^#!\//	{ print p $0; next }

				# Check if this is a XML file
				/^<\?xml version/ {
						if ( NR == 1 )
						{
							xml = 1
						}
					}

				# Ignore lines in non-XML files starting with comment char
				/^[ 	]*'"${comment_regexp}"'/ {
						if ( xml == 0 && c != "" )
						{
							next;
						}
					}

				# General processing.
					{
						# Print non-empty non-XML lines
						if ( xml == 0 )
						{
							# This will also remove trailing blanks
							sub(/[ 	]*$/, "");
							if ( $0 != "" )
							{
								print p $0;
							}
							next
						}

						# every line that passes this point, is an xml file,
						# no further checks on xml var needed
						line = $0;
						pline = "";
						while ( line != "" )
						{
							if ( squelch == 0 )
							{
								# it seems we need to print something,
								# check for beginning of comment
								x = index (line, "<!--")
								if ( x > 0 )
								{
									pline = pline substr( line, 1, x - 1 );
									line = substr( line, x + 4 );
									squelch = 1;
								}
								else
								{
									pline = pline line;
									line = "";
								}
							}
							if ( squelch == 1 )
							{
								# it seems we are squelching comment,
								# check for end of that
								x = index( line, "-->" );
								if ( x > 0 )
								{
									line = substr( line, x + 3 );
									squelch = 0;
								}
								else
								{
									line = "";
								}
							}
						}
						sub(/[ 	]*$/, "", pline );
						if ( pline != "" )
						{
							print p pline;
						}
						next
					}'	c="${3}"		\
						p="${utils_class}"	\
						xml=${xml}		\
						"${1}"

			comment=" and lines starting with character: ${3}"
			if [ -z "${3}" ]
			then
				comment=""
			fi

			scc_help_info "${utils_class}" <<-_X_
				Contents of file: ${1}
				Ignore blank lines${comment}
			_X_

			return 0;	# indicate logging of data in file.
		elif [ ${utils_action} -eq 0 ]
		then
			# Sometimes the file command tries to interpret too much.
			# Add a comment-line to get the result: data
			echo "fix:general::scc_check_file ignored non-ASCII file ${f_type}"
		fi
	fi

	return 1;			# indicate skip of (absent) file.
} 

# Encrypt stdin
# Syntax: scc_crypt
scc_crypt()
{
	# Encrypt stdin.
	{
		# The variable crypt_key is initalized during the first run of scc.
		# Adding this data avoids that the identical critical data on other systems
		# have the same md5sum on scc-srv. Indicated by Esther Hanko and Ronald van der Meer.
		echo "${crypt_key}"
		cat -
		echo "${crypt_key}"
	}				|
	if [ -x /usr/bin/md5sum ]
	then
		/usr/bin/md5sum	|
		sed -e 's/ .*//'
	elif [ -x /sbin/md5 ]
	then
		/sbin/md5
	elif [ -x /usr/bin/crypt ]
	then
		/usr/bin/crypt "${crypt_key}"	|
		cksum				|
		sed -e 's/ .*//'
	else
		# no encryption available, ignore data
		cat >/dev/null
	fi

	return 0;
}

# Add profiling data
# Syntax: scc_timing <message>
scc_timing()
{
	utils_now=$(date '+%H.%M.%S')
	utils_hour=${utils_now%%.*}
	utils_min=${utils_now%.*}
	utils_min=${utils_min#*.}
	utils_sec=${utils_now##*.}

	utils_tick_cur=$(( ${utils_sec#0} + ( 60 * ${utils_min#0} ) + ( 3600 * ${utils_hour#0} ) ))

	if [ ${utils_tick_cur} -lt ${tick_prev} ]
	then
		# Correction when previous measurement was yesterday.
		utils_runtime=$(( ${utils_tick_cur} + ( 24 * 3600 ) - ${tick_prev} ))
	else
		utils_runtime=$(( ${utils_tick_cur} - ${tick_prev} ))
	fi
	total_time=$(( ${total_time} + ${utils_runtime} ))
	printf "var:profiling::%s: %4d : %4d :%s\n" ${utils_now} ${utils_runtime} ${total_time} "${1}"

	tick_prev=${utils_tick_cur};

	return;
}

# Reformat the output of ls -l, replace the time by the year.
# The first 6 months after modification, the time is shown.
# After 6 months, the year is shown. Avoid unnessary differences between snapshots.
month_now=$(date '+%m')
year_now=$(date '+%Y')
scc_ls()
{
	awk '{ if ( NF > 8 ) print }'		|
	sed	-e 's/ Jan / 01 /'	\
		-e 's/ Feb / 02 /'	\
		-e 's/ Mar / 03 /'	\
		-e 's/ Apr / 04 /'	\
		-e 's/ May / 05 /'	\
		-e 's/ Jun / 06 /'	\
		-e 's/ Jul / 07 /'	\
		-e 's/ Aug / 08 /'	\
		-e 's/ Sep / 09 /'	\
		-e 's/ Oct / 10 /'	\
		-e 's/ Nov / 11 /'	\
		-e 's/ Dec / 12 /'		|
	${AWK} '{
		if ( $8 ~ "^[0-9][0-9][0-9][0-9]$" )
		{
			year=$8
		}
		else
		{
			year=j
			if ( $6 > m )
			{
				year--;
			}
		}
		printf( "%s:%s:%s:%s:%s:%d-%02d-%02d:%s %s %s\n",
			$1, $2, $3, $4, $5, year, $6, $7, $9, $10, $11 );
	}' j=${year_now} m=${month_now}

	return;
}

# Retrieve the Oracle SID's 
# Requires:
#	${ORATAB}
# Syntax:
#	scc_oracle_sids
# Output:
#	<user> <sid> <home>
scc_oracle_sids ()
{
	if [ -f "${ORATAB:-}" ]
	then
		# Use the oratab to determine a list of ORACLE_SID and ORACLE_HOME
		sed	-e 's/:/ /'		\
			-e 's/:.*//'		\
			-e 's/[#*].*//'		\
			-e '/^[ 	]*$/d'	\
				${ORATAB}			|
		while read sid home
		do
			# Retrieve the oracle user from the process list.
			# On AIX a space is appended to the processname (indicated by Rick Veenstra).
			user="$(grep "ora_pmon_${sid} *$" ${PROC_FILE} | awk 'NR == 1 { print $1 }')"
			if [ -n "${user}" ]
			then
				echo "${user} ${sid} ${home}"
			fi
		done
	else
		# No oratab, try a default ORACLE_HOME and retrieve user/sid combination(s) from the process list.
		# To be extended later:
		# - according to OFA: /*/app/oracle/product/[89]* /*/app/oracle/product/10*/db*
		# - how do we combine the homes with the SID's when there are several homes and SID's?
		for dir in /opt/oracle
		do
			if [ -x "${dir}/bin/sqlplus" ]
			then
				sed -n	-e 's/^[ 	]*//'			\
					-e "s|[ 	]*$| ${dir}|"		\
					-e 's/[ 	].*ora_pmon_/ /p'	\
						<${PROC_FILE}
			fi
		done
	fi			|
	sort -u -f -k 2

	return;
}

# Perform oracle query
# Requires: ${ORACLE_HOME} and ${ORACLE_USER}
# Syntax:
# - scc_oracle_query <sql-statement>
# - scc_oracle_query <query-file>
scc_oracle_query ()
{
	# This routine only works for Oracle 7.3 and later!
	ORA_USE_PROFILE=${ORA_USE_PROFILE:-0}

	# We create a shellscript that will be interpreted.
	# The structure of the shellscript contains a nested here-document:
	# su ${ORACLE_USER} <<EOF_SU
	# svrmgrl or sqlplus <<EOF_QRY
	# query statements
	# EOF_QRY
	# EOF_SU
	{
		# Oracle users with /bin/csh als default shell, use a different syntax to set the library path.
		utils_ora_shell="$(awk -F: '/^'"${ORACLE_USER}"':/	{ print $NF }' /etc/passwd)"
		case "${utils_ora_shell}" in
		*csh)	utils_lib_cmd="setenv LD_LIBRARY_PATH ${ORACLE_HOME}/lib;"
			;;
		*)	utils_lib_cmd="LD_LIBRARY_PATH=${ORACLE_HOME}/lib; export LD_LIBRARY_PATH;"
			;;
		esac

		if [ ${ORA_USE_PROFILE} -eq 1 ]
		then
			echo "su - ${ORACLE_USER} 2>/dev/null <<EOF_SU"
		else
			echo "su ${ORACLE_USER} 2>/dev/null <<EOF_SU"
		fi

		# Supply the query by means of a nested here-document.
		if [ -x ${ORACLE_HOME}/bin/svrmgrl -a -z "${force_sqlplus_query:-}" ]
		then
			echo "${ORACLE_HOME}/bin/svrmgrl <<EOF_QRY"
			echo "connect internal"
		else
			echo "${utils_lib_cmd}"
			echo "${ORACLE_HOME}/bin/sqlplus /nolog <<EOF_QRY"
			echo "connect / as sysdba"
			echo "set linesize 32000;"
			echo "set pagesize 32000;"
		fi

		if [ $# -eq 1 -a -f "${1}" ]
		then
			sed -e 's/\$/\\\\\\$/g' "${1}"	# query is supplied by means of a file
		else
			echo "$*"			# query is supplied by means of the command-line
		fi			|
		tr -d "\012"
		# Reduce multiline queries to single line to avoid continuation prompts (2> ...) in the output.
		echo ""				# add one CR

		echo "exit"
		echo "EOF_QRY"
		echo "EOF_SU"

		# the output of the script above, executed by sh below MUST be redirected
		# to the TMP file, because of strange behavior of Oracle 7 svrmgrl
	} | sh >${TMP_FILE} 2>/dev/null

	if [ -z "${force_sqlplus_query:-}" ]
	then
		grep -l "^no rows selected" ${TMP_FILE} >/dev/null 2>/dev/null
		if [ $? -ne 0 ]
		then
			sed	-e 's/SVRMGR> //'			\
				-e 's/SQL> //g'				\
				-e '1,/^Connected.$/d'			\
				-e '/^Server Manager complete/d'	\
				-e '/^Disconnected from Oracle/,$d'	\
				-e '/^[ 	]*$/d'			\
				-e 's/[ 	]*$//'			\
				-e '/^1 row selected/d'			\
				-e '/^no rows selected/d'		\
				-e '/^[0123456789]* rows selected/d' ${TMP_FILE}
		fi
	else
		cat ${TMP_FILE}
	fi

	rm ${TMP_FILE}

	return 0;
}

# Record Linux distribution
# Syntax:
# - no arguments: set variable SCC_LINUX_DISTRO
# - <class>: show contents of release file of Linux distribution
scc_linux_distro()
{
	export SCC_LINUX_DISTRO=""

	# Usually we trust /etc/lsb-release, however some distro record their base-distro in that file.
	# Check the following distro's first.
	while read file distro
	do
		if [ -f "${file}" ]
		then
			export SCC_LINUX_DISTRO="${distro}"
			if [ $# -eq 1 ]
			then
				echo "${1} file:${file}"
				if [ -x "${file}" ]
				then
					"${file}" 2>/dev/null
				else
					cat "${file}"
				fi				|
				sed -e "s@^@${1} details:@"
			fi
			return 0
		fi
	done <<-_X_
		/etc/sabayon-edition	sabayon
	_X_

	# Now for the default file.
	LSB_FILE=/etc/lsb-release
	if [ -f ${LSB_FILE} ]
	then
		SCC_LINUX_DISTRO="$(sed -n -e 's/.*DISTRIB_ID=//p' "${LSB_FILE}")"
		if [ $# -eq 1 ]
		then
			echo "${1} file:${LSB_FILE}"
			sed -e "s@^@${1} details:@" "${LSB_FILE}"
		fi
		return 0
	fi

	if [ -f /etc/dreamlinux/dreaminstalled -a -f /usr/local/etc/dli.yaml ]
	then
		SCC_LINUX_DISTRO="DreamLinux"
		if [ $# -eq 1 ]
		then
			echo "${1} file:/usr/local/etc/dli.yaml"
			sed -n -e "s@^dl_version@${1} details:dl_version@p" /usr/local/etc/dli.yaml
		fi
		return 0
	fi

	# Several distro's are based on others and have more than one release/version file.
	# First check for derived distro's and stop after the first match.
	while read file distro
	do
		if [ -f "${file}" ]
		then
			export SCC_LINUX_DISTRO="${distro}"
			if [ $# -eq 1 ]
			then
				echo "${1} file:${file}"
				if [ -x "${file}" ]
				then
					"${file}" 2>/dev/null
				else
					cat "${file}"
				fi				|
				sed -e "s@^@${1} details:@"
			fi
			return 0
		fi
	done <<-_X_
		/etc/sun-release		SunJDS
		/etc/mepis-release		mepis
		/etc/yellowdog-release		yellowdog
		/etc/mandriva-release		mandriva
		/etc/mandrakelinux-release	mandrake
		/etc/pclinuxos-release		pclinuxos
		/etc/zenwalk-version		zenwalk
		/etc/altlinux-release		AltLinux
		/etc/tinyme-release		tinyme
		/etc/arch-release		archlinux
		/usr/bin/crux			CRUX
		/usr/share/doc/dsl/release.txt	DSL
		/etc/GoboLinuxVersion		GoboLinux
		/etc/SLOX-release		SLOX
		/etc/slax-version		slax
		/etc/vector-version		vector
		/usr/bin/deli			deli
		/etc/arch-release		archlinux
		/etc/debian_version		debian
		/etc/engarde-release		engarde
		/etc/fedora-release		fedora
		/etc/gentoo-release		gentoo
		/etc/lunar.release		lunar
		/etc/mandrake-release		mandrake
		/etc/linuxmint/info		Mint
		/etc/pardus-release		pardus
		/etc/redhat-release		redhat
		/etc/slackware-version		slackware
		/etc/SuSE-release		SuSe
		/etc/turbolinux-release		turbolinux
		/etc/UnitedLinux-release	UnitedLinux
	_X_

	# And now some distro's that require some extra work to determine the details.

	# Check for Feather: no version (at the moment)
	if [ -f /usr/local/bin/feather-custom-install ]
	then
		export SCC_LINUX_DISTRO=feather
		if [ $# -eq 1 ]
		then
			echo "${1} file:/usr/local/bin/feather-custom-install"
		fi
		return 0
	fi

	# Check for PuppyLinux
	puppy_file="/etc/puppy"
	if [ -f /etc/puppyversion ]
	then
		puppy_file=/etc/puppyversion
	fi
	if [ -z "${SCC_LINUX_DISTRO}" -a -f "${puppy_file}" ]
	then
		export SCC_LINUX_DISTRO=PuppyLinux
		if [ $# -eq 1 ]
		then
			echo "${1} file:${puppy_file}"
			echo "${1} details:$(head -n 1 "${puppy_file}")"
		fi
		return 0
	fi

	# Check for ttylinux:
	tty_file=/etc/rc.d/rc.sysinit
	if [ -z "${SCC_LINUX_DISTRO}" -a -f "${tty_file}" ]
	then
		# Example data:
		# echo -e "\t\t\t-=#\tttylinux 5.3\t#=-"
		grep -l ttylinux "${tty_file}" 2>/dev/null >/dev/null
		if [ $? -eq 0 ]
		then
			export SCC_LINUX_DISTRO=ttylinux
			if [ $# -eq 1 ]
			then
				echo "${1} file:${tty_file}"
				echo "${1} details:ttylinux $(sed -n -e 's/.*ttylinux //p' "${tty_file}" | sed -e 's/[^0-9.]//g')"
			fi
		fi
	fi

	return 0;
}

# On some systems, there is no "strings", replace the functionality by a function.
strings_exe="$(which strings 2>/dev/null)"
if [ ! -x "${strings_exe}" ]
then
	strings()
	{
		# Replace all binary nuls by a linefeed to avoid lines that are too long.
		# Then delete all non-printables.
		if [ $# -eq 0 ]
		then
			tr -s "\000" "\012"
		else
			tr -s "\000" "\012" <$1
		fi							|
		tr -d -c "[_a-zA-Z0-9 \011\-/=\.\"\012]"

		return 0;
	}
fi

# Use the following utilities for SunOS.
if [ -x /usr/ccs/bin/what ]
then
	alias what=/usr/ccs/bin/what
else
	# On a RH73 Workstation, there is no "what", replace the functionality by a function.
	utils_what_exe="$(which what 2>/dev/null)"
	if [ ! -x "${utils_what_exe}" ]
	then
		what()
		{
			if [ -r "${1}" ]
			then
				echo "${1}:"
				strings "${1}"		|
				sed -n -e 's/^@(#)/	/p'

				return 0;
			else
				echo "can't open ${1}"

				return 1
			fi
		}
	fi
fi

# Add PPID to output of BusyBox ps
# Syntax:
# - no arguments
busybox_ps()
{
	# BusyBox ps does not show PPID.
	# Get all PPID's from the status files in /proc and add them to the output of ps.
	ps >${TMP_FILE}

	find /proc -name status 2>/dev/null				|
	grep "^/proc/[0-9]*/status"					|
	xargs awk '/^PPid|^Pid/	{ print "awk", $0 }' 2>/dev/null	|
	awk	'/^awk Pid/	{ pid = $3; next		}
		/^awk PPid/	{ ppid[ pid ] = $3; next	}
		/^  PID/	{
					printf( "%s", substr( $0, 0, 14 ) );
					printf( "%6s", "PPID" );
					printf( "%s\n", substr( $0, 15 ) );
					next;
				}
				{
					printf( "%s", substr( $0, 0, 14 ) );
					printf( "%6s", ppid[ $1 ] );
					printf( "%s\n", substr( $0, 15 ) );
				}' - ${TMP_FILE}

	rm -f ${TMP_FILE}

	return;
}

# Check whether program is implemented by busybox.
# Currently only works for programs in /bin
# Syntax:
# - program to check
# Return value:
# - 0 program NOT implemented by busybox
# - 1 program implemented by busybox
busybox_check()
{
	if [ -x /bin/busybox ]
	then
		# Program is either a symbolic or hardlink to /bin/busybox.
		prog_e="$(which ${1} 2>/dev/null)"
		if [ -f "${prog_e}" ]
		then
			if [ -h "${prog_e}" ]
			then
				# Check whether the file links to program busybox.
				target="$(ls -l "${prog_e}" | sed -e 's@.*[     ][      ]*@@' -e 's@.*/@@')"
				if [ "${target}" = "busybox" ]
				then
					return 1;		# Program is symbolic link to /bin/busybox
				fi
			else
				# Check for identical inodes (hard link).
				b_i="$(ls -li /bin/busybox | awk '{ print $1 }')"
				p_i="$(ls -li "${prog_e}" | awk '{ print $1 }')"
				if [ "${b_i}" -eq "${p_i}" ]
				then
					return 1;		# Program is a hard link to busybox.
				fi
			fi
		fi
	fi

	return 0;
}

# Do not exit
