#!/bin/ksh
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# bos72V src/bos/usr/bin/svcmd/ldd/ldd.sh 1.8.1.5 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2001,2020 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)32        1.8.1.5  src/bos/usr/bin/svcmd/ldd/ldd.sh, uw7cmds, bos72V, v2020_10A1 2/17/20 01:26:34
#
#
#  Usage: ldd [ -Llibpath ] executable 

DSPMSG=/usr/bin/dspmsg
BASENAME=/usr/bin/basename
RM=/usr/bin/rm
DUMP=/usr/bin/dump

function display_usage
{
	$DSPMSG -s 1 sysvldd.cat 1 'Usage: ldd [ -Llibpath ] executable\n' 1>&2
	exit 2
}

stack_limit=4096 # Maximum array size permitted on ksh

errors=0

whoami=$($BASENAME $0)

# gather options
Libpath_opt=
while getopts :L: opt
do
	case $opt in
	L)	Libpath_opt=$OPTARG;;
	?)	display_usage;;
	esac
done

shift $(($OPTIND - 1))

# Print usage if the number of arguments are not equal to 1.
if [ $# -ne 1 ]
then
	display_usage
fi

trap 'cleanup' 0 1 2 15

# Delete temporary files
cleanup()
{
	$RM -rf $LDD_DIR $LOADED_FILE
        exit $1
}

# Make sure a file is an executable XCOFF file.
# Return value: 0 if file is executable XCOFF
#		1 otherwise
function chk_file
{
	if [ \! -s $1 ]
	then
		$DSPMSG -s 1 sysvldd.cat 2 \
		'ldd: %s: File does not exist or is empty.\n' $1 1>&2
		return 1
	fi

	if LANG=C $DUMP -o $1 2>/dev/null | /usr/bin/grep "^$1\[" >/dev/null
	then	
		$DSPMSG -s 1 sysvldd.cat 3 \
		'ldd: %s: File is an archive.\n' $1 1>&2
		return 1
	fi

	if [ $(LANG=C $DUMP -o $1 2>/dev/null | /usr/bin/wc -l) = 0 ]
	then	
		$DSPMSG -s 1 sysvldd.cat 4 \
		'ldd: %s: File is not an executable XCOFF file.\n' $1 1>&2
		return 1
	fi

	return 0
}

# Determine the LIBPATH information from XCOFF loader section.
function get_libpath
{
	LANG=C $DUMP -Hp $1 |  grep -e "^0 " | cut -c8-
}

# Determine the Libraries used -- from XCOFF loader section.
# Arguments:	$1: Directory name of object to be loaded
#		$2: Name of object being loaded
#		$3: Member name of object
function get_libs
{
	f=$1/$2

	if [ \! -z "$3" ]
	then
		(cd $LDD_DIR/extract;
		$RM -f $LDD_DIR/extract/* 2>/dev/null
		if [[ $f = /* ]]
		then
			/usr/bin/ar x $f $3;
		else
			/usr/bin/ar x $OLDPWD/$f $3;
		fi;)
		f=$LDD_DIR/extract/$3
	fi

	LANG=C $DUMP -Hp $f \
	| /usr/bin/awk $DBG '
	/^0 /	{
		look=1;
		Libpath=$NF
		next;
		}
	look==0 {next;}
		{	print Libpath
			if (substr($0, 8, 1) != " ")
				printf "%s\n%s\n%s\n", $2, $3, $4
			else
				printf "\n%s\n%s\n", $2, $3
		}'
}

# Find a particular object by searching a list of directories.
# Arguments:	$1: Libpath information from object requesting object
#		$2: Directory name of object to be loaded
#		$3: Basename of object to be loaded
# Returns 1 if object cannot be found.  Sets global variables object_dir,
#		and object_base
find_object ()
{
	object_dir=''
	saved_ifs=$IFS
	IFS=":"
	for f in ${2:-$Libpath_dirs:$1}
	do
		if [ -f $f/$3 ]
		then
			object_dir=$f
			object_base=$3
			break;
		fi
	done

	IFS=$saved_ifs
	if [ -z "$object_dir" ]
	then
		return 1
	else
		return 0
	fi
}

# Calls find_object internally to locate the objects.
load_object()
{
	Mem=${new_mem:+($new_mem)}
	Dir=${new_dir:+$new_dir/}

	if [ -z "$new_mem" ]
	then
		if [[ "$new_dir" = / && "$new_base" = unix ]]
		then
			if [ "$unix_loaded" != 1 ]
			then
				print "\t /unix"
				unix_loaded=1
			fi
			return 1
		elif [ -z "$new_dir" ]
		then
			if [ "$new_base" = . ]
			then
				return 1
			elif [ "$new_base" = .. ]
			then
				return 1
			fi
		fi
	fi

	if find_object "$new_libpath" "$new_dir" "$new_base" "$new_mem"
	then	:
	else
		$DSPMSG -s 1 sysvldd.cat 5 'Cannot find %s\n' $Dir$new_base$Mem 1>&2
		errors=1
		return 2
	fi

	f="$object_dir/$object_base$Mem"
	saved_ifs=$IFS
	IFS=":"
	fbase="$object_dir/$object_base"
	fs=$(/usr/bin/df $fbase | /usr/bin/sed -n -e '2{s/ .*$//p;q;}')
	inode=$(/bin/ls -i $fbase | /usr/bin/awk '{print $1;}')

	if /usr/bin/grep -s "^$fs $inode $new_mem\$" $LOADED_FILE > /dev/null
	then
		return 1		# Already loaded
	fi

	print "$fs $inode $new_mem" >> $LOADED_FILE
	IFS=$saved_ifs

	if [ -z "$Dir" ]
	then	
		print '\t' "$f"
        elif [ ! `$BASENAME $f` == `$BASENAME $filename` ]; then
               print '\t' "$f"
	fi
	return 0
}

# Calls get_libs internally to get the list of libraries used by the binary.
list_libraries ()
{
    while ((low_index <= load_index))
    do
	new_libpath=${libpath[low_index]}
	new_dir=${dirs[low_index]}
	new_base=${bases[low_index]}
	new_mem=${mems[low_index]}
	((low_index+=1))

	saved_ifs=$IFS
	IFS=""

	if load_object
	then	get_libs "$object_dir" "$object_base" "$new_mem" |
		while	read libpath
		do
			IFS=$saved_ifs
			read lib
			if [ "$lib" != / ]; then lib=${lib%/}; fi
			read base
			read mem

			((load_index+=1))
			if ((load_index>=$stack_limit))
			then
				$DSPMSG -s 1 sysvldd.cat 7 'Stack Overflow\n' 1>&2
				exit 3
			fi
			libpath[$load_index]=$libpath
			dirs[$load_index]=$lib
			bases[$load_index]=$base
			mems[$load_index]=$mem

		done
	fi

	if ((low_index>=$stack_limit))
	then	
		$DSPMSG -s 1 sysvldd.cat 7 'Stack Overflow\n' 1>&2
		exit 3
	fi

    done
}

###########################################################
########################## Main ###########################

# First command line operand is the file being checked.
filename=$1

typeset -i low_index=0
typeset -i load_index=0

if [ -z "$TMPDIR" ]
then	
	TMPDIR=/tmp/tmpdir$$
	LDD_DIR=$TMPDIR
else	
	LDD_DIR=$TMPDIR/ldd$$
fi

/usr/bin/mkdir -p $LDD_DIR/extract 2>/dev/null
LOADED_FILE=$TMPDIR/loaded$$

###### Defect 1020236 , Based on the input file , OBJECT_MODE is exported so that proper library will be picked ######

if LC_ALL=C /usr/bin/file $filename 2>/dev/null | /usr/bin/grep "64-bit XCOFF" >/dev/null
then
      export OBJECT_MODE=64
else
      export OBJECT_MODE=32
fi

if chk_file	$filename
then	
	:
else	
	exit 2
fi

Libpath_dirs=$(get_libpath $filename)

#Remove trailing white space.
Libpath_dirs="$(echo "${Libpath_dirs}" | sed -e 's/[[:space:]]*$//')"

Libpath_dirs=${Libpath_opt:-$LIBPATH}:$Libpath_dirs:

bases[0]=$($BASENAME $filename)
d=${filename%${bases[0]}}
if [ "$d" != "/" ]
then	
	d=${d%/}
	if [ -z "$d" -o "$d" = "$filename" ]; then d='.'; fi
fi
dirs[0]=$d
member[0]=''
> $LOADED_FILE		# Create or truncate file.

$DSPMSG -s 1 sysvldd.cat 6 '%s needs:\n' $filename

list_libraries

#Cleanup of temporary files
$RM -rf $LDD_DIR $LOADED_FILE

exit $errors