summaryrefslogtreecommitdiffstats
path: root/core/includes/binutil.inc
blob: 7ca92f3aa326e62c567aab7a857c1284ae537ead (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
#!/bin/bash
#
# Common functions to copy binaries and their dependancies.
#
############################################################
#	This will parse the output of ldd on given binaries
#	and echo the location of these libs to STDOUT
#	The output of this function has to be used in some
#	way, it only echos!
#
# About local search:
#	It is required that we can search for the dynamic
#	libraries in a specific directory, namely the one
#	where we (potentially) built the binary. If a
#	corresponding library is found, it should take
#	precedence over ones found on the system.
#	This can be done by using the '-l' switch, see below.
#
############################################################
# We use a blacklist mechanism to exclude common libraries.
# This improves runtime quite a bit...
declare -rg BLACKLIST="ld-linux linux-gate linux-vdso libc.so"


# replace ' ' by '|' in the blacklist, so grep can use it directly.
CURRENT_BLACKLIST=$(echo ${BLACKLIST} | sed 's/ /\\|/g')

# Initialise flag and path for local search
LOCALSEARCH=0
LOCALSEARCHDIR=""

DONEDONE=$(mktemp)
echo "-----------------------" > "$DONEDONE"

############################################################
#
# Usage:
#	get_dynamic_dependencies [-l <searchdir>] <binary_list>
# 	  * the list must be seperated by spaces
#	  * the search for lib needed by a binary can be done locally,
#	    using the -l <searchdir> option
#
# Ouput:
#	 Will simply echo list of required libraries

get_dynamic_dependencies() {
	# check if local search is activated by the '-l' switch
	# if so the following argument is the path.
	if [ "x$1" == "x-l" ]; then
		local LOCALSEARCH=1
		shift
		[ ! -d "$1" ] && perror "Directory '$1' does not exist, exiting."
		local LOCALSEARCHDIR="$1"
		shift
	fi
	
	# main loop over the list of binaries
	while [ $# != 0 ]; do
		local BINARY="$1"
		shift
		[ -f "$BINARY" ] || continue
		
		# now run ldd on it and save the output in $LDD_OUT
		local LDD_OUT="ldd_output"
		if ldd "$BINARY" > "$LDD_OUT"; then
			# Case 1: file is a dynamic executable
			for LIB in $(grep -v "${CURRENT_BLACKLIST}${REQUIRED_LDD_BLACKLIST}" "$LDD_OUT" | awk '{print $1 $2 $3}'); do
				# split the entry into an array, ex:
				# libm.so.6 => /lib/libm.so.6 would be split into:
				# LIBLINK[0]   LIBLINK[1]
				local LIBLINK=(${LIB//=>/ })
				# call helper function to find the correct lib
				lib_search
			done
			#TODO: check if "statically linked" is output
		else
			# Case 2: not a dynamic, do nothing
			pdebug "\t\t\t(Not a dynamic.)"
		fi
		rm -f -- "$LDD_OUT"
	done
	
}

############################################################
#
# Usage:
#	lib_search
#
# Output:
#	List of the path including any possible symbolic links
#	of the found libraries.
#
# Note: This function takes no argument. It takes the library
#	to look for from the local array LIBLINK.
#	If the local was activated in get_dynamic_dependencies
#	this will search for the library in LOCALSEARCHDIR first.
#	If its not found, then it will look system-wide.
lib_search() {
	
	# if activated, start by searching the lib locally
	if [ "x$LOCALSEARCH" == "x1" ]; then
		cd "$LOCALSEARCHDIR"
		local LOCAL_MATCHES=$(find . -name "${LIBLINK[0]}") # | awk -F '.' '{print $1}')".so\*)
		cd - >/dev/null
		if [ "x${LOCAL_MATCHES}" != "x" ]; then
			for LOCALLIB in ${LOCAL_MATCHES}; do
				grep -q "^${LOCALLIB}\$" "$DONEDONE" && continue
				echo "${LOCALLIB}" >> "$DONEDONE"
				get_link_chain "${LOCALSEARCHDIR}/${LOCALLIB}" "${LOCALSEARCHDIR}"
				get_dynamic_dependencies -l "${LOCALSEARCHDIR}" "${LOCALLIB}"
			done
			# found the libs, we are done
			return
		fi
		# mark local search as done
	fi
	
	# search the lib on the system since it was not found earlier
	if [ -n "${LIBLINK[1]}" ] && [ "x${LIBLINK[1]}" != "xnot" ]; then
		grep -q "^${LIBLINK[1]}\$" "$DONEDONE" && return
		echo "${LIBLINK[1]}" >> "$DONEDONE"
		# get chain of symlink for that lib
		get_link_chain "${LIBLINK[1]}"
	else
		pwarning "\t\tLib '${LIBLINK[0]}' from required dir '$ENTRY' neither found in build directory nor on this system."
		pwarning "\t\tIf this lib is not supplied by another module, this module will probably fail in your final system"
	fi
}
############################################################
#
# Usage:
#	get_link_chain <link> [prefix]
#	  * <link> must be in absolute form-
#	  * [prefix] is the prefix to strip from the ouput.
#
# Output:
#	 Lists the symlink chain until a hardlink is found.
#
get_link_chain() {
	
	# sanity checks
	[[ "$1" == /* ]] || perror "get_link_chain() requires absolute paths, given: $1"
	if [ ! -e "$1" -a ! -L "$1" ]; then
		perror "get_link_chain: '$1' does not exist"
	fi
	local PREFIX=
	if [ $# == 2 ] ; then
		[ -d "$2" ] || perror "get_link_chain: '$2' is not a directory. Local search can't work..."
		# got a prefix
		local PREFIX=$(dirname "$(canonicalize "$2/foo")")
		[ -d "$PREFIX" ] || perror "Could not canonicalize $2"
		[[ "$PREFIX" == */ ]] || PREFIX="$PREFIX/"
	fi
	
	# canonalize
	local LINK=$(canonicalize "$1")
	
	local CHAIN="$LINK"
	
	# write the first link in the chain
	if [ "x$PREFIX" != "x" ]; then
		if [ "x${LINK#$PREFIX}" == "x${LINK}" ]; then
			# prefix was not in the link
			echo "$LINK"
		else
			# prefix was in the link
			echo ./"${LINK#$PREFIX}"
		fi
	else
		# no prefix, copy like it is
		echo "$LINK"
	fi
	
	# now we check for symlinks
	local TRY=0
	while [ -L "$LINK" ] && [ $TRY -lt 10 ]; do
		let TRY=TRY+1
		
		# save the directory prefix
		CURRENTDIR=$(dirname "${LINK}")
		# first follow the link
		local NEWLINK=$(readlink "$LINK")
		[ -z "$NEWLINK" -o "$NEWLINK" = "$LINK" ] && break
		LINK=$NEWLINK
		CHAIN+=" -> $LINK"
		# $LINK can be absolute or relative, check cases
		[[ "$LINK" == /* ]] || LINK=$(canonicalize "$CURRENTDIR"/"${LINK}")
		# write the first link in the chain
		if [ "x$PREFIX" != "x" ]; then
			if [ "x${LINK#$PREFIX}" == "x${LINK}" ]; then
				# prefix was not in the link
				if [ ! -e "$LINK" ]; then
					[ -e "$PREFIX/$LINK" ] && echo "./$LINK"
				else
					echo "$LINK"
				fi
			else
				# prefix was in the link
				echo ./"${LINK#$PREFIX}"
			fi
		else
			# no prefix, copy like it is
			echo "$LINK"
		fi
	done
	pdebug "\t\t$CHAIN"
}
############################################################
#
# Usage:
#	list_basic_libs
#
# Output:
#	list the path of following basic system libraries:
#	- libc.so, ld-linux.so
#
list_basic_libs() {
	for i in $(ldd ${SHELL}); do
		[ $(echo $i | grep '^/' | grep -c ld) -eq 1 -o  $(echo $i | grep '^/' | grep -c libc.so) -eq 1 ] && get_link_chain $i
	done
}