1 |
Author: grobian |
2 |
Date: 2009-10-28 19:38:53 +0000 (Wed, 28 Oct 2009) |
3 |
New Revision: 14745 |
4 |
|
5 |
Modified: |
6 |
main/branches/prefix/bin/misc-functions.sh |
7 |
main/branches/prefix/pym/portage/__init__.py |
8 |
main/branches/prefix/pym/portage/dbapi/vartree.py |
9 |
Log: |
10 |
Add preserve-libs support for AIX' XCOFF, patch by Michael Haubenwallner |
11 |
|
12 |
Modified: main/branches/prefix/bin/misc-functions.sh |
13 |
=================================================================== |
14 |
--- main/branches/prefix/bin/misc-functions.sh 2009-10-28 19:27:43 UTC (rev 14744) |
15 |
+++ main/branches/prefix/bin/misc-functions.sh 2009-10-28 19:38:53 UTC (rev 14745) |
16 |
@@ -436,6 +436,114 @@ |
17 |
PORTAGE_QUIET=${tmp_quiet} |
18 |
fi |
19 |
|
20 |
+ if [[ ${CHOST} == *-aix* ]] && ! hasq binchecks ${RESTRICT}; then |
21 |
+ local tmp_quiet=${PORTAGE_QUIET} |
22 |
+ local queryline deplib |
23 |
+ local insecure_rpath_list= undefined_symbols_list= |
24 |
+ |
25 |
+ # display warnings when using stricter because we die afterwards |
26 |
+ if has stricter ${FEATURES} ; then |
27 |
+ unset PORTAGE_QUIET |
28 |
+ fi |
29 |
+ |
30 |
+ rm -f "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 |
31 |
+ find "${ED}" -not -type d -exec \ |
32 |
+ "${EPREFIX}/usr/bin/aixdll-query" '{}' FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS ';' \ |
33 |
+ > "${T}"/needed 2>/dev/null |
34 |
+ |
35 |
+ # Symlinking archive libraries is not a good idea on aix, |
36 |
+ # as there is nothing like "soname" on pure filesystem level. |
37 |
+ # So we create a copy instead of the symlink. |
38 |
+ local prev_FILE= |
39 |
+ while read queryline |
40 |
+ do |
41 |
+ local FILE= MEMBER= FLAGS= FORMAT= RUNPATH= DEPLIBS= |
42 |
+ eval ${queryline} |
43 |
+ |
44 |
+ if [[ ${prev_FILE} != ${FILE} ]]; then |
45 |
+ prev_FILE=${FILE} |
46 |
+ if [[ -n ${MEMBER} || " ${FLAGS} " == *" SHROBJ "* ]] && [[ -h ${FILE} ]]; then |
47 |
+ local target=$(readlink "${FILE}") |
48 |
+ if [[ ${target} == /* ]]; then |
49 |
+ target=${D}${target} |
50 |
+ else |
51 |
+ target=${FILE%/*}/${target} |
52 |
+ fi |
53 |
+ rm -f "${FILE}" || die "cannot prune ${FILE#${ED}}" |
54 |
+ cp -f "${target}" "${FILE}" || die "cannot copy ${target#${ED}} to ${FILE#${ED}}" |
55 |
+ fi |
56 |
+ fi |
57 |
+ done <"${T}"/needed |
58 |
+ |
59 |
+ prev_FILE= |
60 |
+ while read queryline |
61 |
+ do |
62 |
+ local FILE= MEMBER= FLAGS= FORMAT= RUNPATH= DEPLIBS= |
63 |
+ eval ${queryline} |
64 |
+ |
65 |
+ if [[ ${prev_FILE} != ${FILE} ]]; then |
66 |
+ # Save NEEDED information for the archive library stub |
67 |
+ echo "${FORMAT##* }${FORMAT%%-*};${FILE#${D%/}};${FILE##*/};;" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 |
68 |
+ fi |
69 |
+ |
70 |
+ # Make sure we disallow insecure RUNPATH's |
71 |
+ # Don't want paths that point to the tree where the package was built |
72 |
+ # (older, broken libtools would do this). Also check for null paths |
73 |
+ # because the loader will search $PWD when it finds null paths. |
74 |
+ # And we really want absolute paths only. |
75 |
+ if [[ -n $(echo ":${RUNPATH}:" | grep -E "(${PORTAGE_BUILDDIR}|::|:[^/])") ]]; then |
76 |
+ insecure_rpath_list="${insecure_rpath_list}\n${FILE}" |
77 |
+ fi |
78 |
+ |
79 |
+ # Although we do have runtime linking, we don't want undefined symbols. |
80 |
+ # AIX does indicate this by needing either '.' or '..' |
81 |
+ local needed=${FILE##*/} |
82 |
+ for deplib in ${DEPLIBS}; do |
83 |
+ eval deplib=${deplib} |
84 |
+ if [[ ${deplib} == '.' || ${deplib} == '..' ]]; then |
85 |
+ undefined_symbols_list="${undefined_symbols_list}\n${FILE}" |
86 |
+ else |
87 |
+ needed="${needed},${deplib}" |
88 |
+ fi |
89 |
+ done |
90 |
+ |
91 |
+ FILE=${FILE#${D%/}} |
92 |
+ |
93 |
+ [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]" |
94 |
+ # Save NEEDED information |
95 |
+ echo "${FORMAT##* }${FORMAT%%-*};${FILE}${MEMBER};${FILE##*/}${MEMBER};${RUNPATH};${needed}" >> "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 |
96 |
+ done <"${T}"/needed |
97 |
+ |
98 |
+ if [[ -n ${undefined_symbols_list} ]]; then |
99 |
+ vecho -ne '\a\n' |
100 |
+ eqawarn "QA Notice: The following files contain undefined symbols." |
101 |
+ eqawarn " Please file a bug about this at http://bugs.gentoo.org/" |
102 |
+ eqawarn " with 'prefix' as the maintaining herd of the package." |
103 |
+ eqawarn "${undefined_symbols_list}" |
104 |
+ vecho -ne '\a\n' |
105 |
+ fi |
106 |
+ |
107 |
+ if [[ -n ${insecure_rpath_list} ]] ; then |
108 |
+ vecho -ne '\a\n' |
109 |
+ eqawarn "QA Notice: The following files contain insecure RUNPATH's" |
110 |
+ eqawarn " Please file a bug about this at http://bugs.gentoo.org/" |
111 |
+ eqawarn " with 'prefix' as the maintaining herd of the package." |
112 |
+ eqawarn "${insecure_rpath_list}" |
113 |
+ vecho -ne '\a\n' |
114 |
+ if [[ -n ${x} ]] || has stricter ${FEATURES} ; then |
115 |
+ insecure_rpath=1 |
116 |
+ fi |
117 |
+ fi |
118 |
+ |
119 |
+ if [[ ${insecure_rpath} -eq 1 ]] ; then |
120 |
+ die "Aborting due to serious QA concerns with RUNPATH/RPATH" |
121 |
+ elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} ; then |
122 |
+ die "Aborting due to QA concerns: ${die_msg}" |
123 |
+ fi |
124 |
+ |
125 |
+ PORTAGE_QUIET=${tmp_quiet} |
126 |
+ fi |
127 |
+ |
128 |
local unsafe_files=$(find "${ED}" -type f '(' -perm -2002 -o -perm -4002 ')') |
129 |
if [[ -n ${unsafe_files} ]] ; then |
130 |
eqawarn "QA Notice: Unsafe files detected (set*id and world writable)" |
131 |
@@ -862,6 +970,167 @@ |
132 |
mtree -e -p "${EROOT}" -U -k flags < "${T}/bsdflags.mtree" &> /dev/null |
133 |
} |
134 |
|
135 |
+preinst_aix() { |
136 |
+ if [[ ${CHOST} != *-aix* ]] || hasq binchecks ${RESTRICT}; then |
137 |
+ return 0 |
138 |
+ fi |
139 |
+ local ar strip |
140 |
+ if type ${CHOST}-ar >/dev/null 2>&1 && type ${CHOST}-strip >/dev/null 2>&1; then |
141 |
+ ar=${CHOST}-ar |
142 |
+ strip=${CHOST}-strip |
143 |
+ elif [[ ${CBUILD} == "${CHOST}" ]] && type ar >/dev/null 2>&1 && type strip >/dev/null 2>&1; then |
144 |
+ ar=ar |
145 |
+ strip=strip |
146 |
+ elif [[ -x /usr/ccs/bin/ar && -x /usr/ccs/bin/strip ]]; then |
147 |
+ ar=/usr/ccs/bin/ar |
148 |
+ strip=/usr/ccs/bin/strip |
149 |
+ else |
150 |
+ die "cannot find where to use 'ar' and 'strip' from" |
151 |
+ fi |
152 |
+ |
153 |
+ local archive prev_archive= archives=() |
154 |
+ while read archive; do |
155 |
+ archive=${archive#*;} |
156 |
+ archive=${archive%%;*} |
157 |
+ if [[ ${archive} == *'['*']' ]]; then |
158 |
+ archive=${archive%[*} |
159 |
+ [[ ${prev_archive} == ${archive} ]] && continue |
160 |
+ prev_archive=${archive} |
161 |
+ archives[${#archives[@]}]=${archive#${EPREFIX}/} |
162 |
+ fi |
163 |
+ done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 |
164 |
+ unset prev_archive |
165 |
+ |
166 |
+ local libmetadir members preservemembers member contentmember chmod400files=() prunedirs=() |
167 |
+ for archive in "${archives[@]}"; do |
168 |
+ libmetadir=${ED}${archive%/*}/.${archive##*/} |
169 |
+ [[ ! -e ${libmetadir} ]] || rm -rf "${libmetadir}" || die "cannot prune ${libmetadir}" |
170 |
+ mkdir "${libmetadir}" || die "cannot create ${libmetadir}" |
171 |
+ pushd "${libmetadir}" >/dev/null || die "cannot cd to ${libmetadir}" |
172 |
+ ${ar} -X32_64 -x "${ED}${archive}" || die "cannot unpack ${archive}" |
173 |
+ members=" $(echo *) " |
174 |
+ preservemembers= |
175 |
+ if [[ -e ${EROOT}${archive} ]]; then |
176 |
+ for member in $(${ar} -X32_64 -t "${EROOT}${archive}"); do |
177 |
+ [[ ${members} == *" ${member} "* ]] && continue |
178 |
+ preservemembers="${preservemembers} ${member}" |
179 |
+ done |
180 |
+ if [[ -n ${preservemembers} ]]; then |
181 |
+ einfo "preserving (on spec)${preservemembers}" |
182 |
+ ${ar} -X32_64 -x "${EROOT}${archive}" ${preservemembers} || die "cannot extract ${preservemembers} from ${EROOT}${archive}" |
183 |
+ chmod u+w ${preservemembers} || die "cannot chmod${preservedmembers}" |
184 |
+ ${strip} -X32_64 -e ${preservemembers} || die "cannot strip${preservemembers}" |
185 |
+ ${ar} -X32_64 -q "${ED}${archive}" ${preservemembers} || die "cannot update ${archive}" |
186 |
+ eend $? |
187 |
+ fi |
188 |
+ fi |
189 |
+ for member in ${members}; do |
190 |
+ contentmember="${archive%/*}/.${archive##*/}[${member}]" |
191 |
+ # portage does os.lstat() on merged files every now |
192 |
+ # and then, so keep stamp-files for archive members |
193 |
+ # around to get the preserve-libs feature working. |
194 |
+ { echo "Please leave this file alone, it is an important helper" |
195 |
+ echo "for portage to implement the 'preserve-libs' feature on AIX." |
196 |
+ } > "${ED}${contentmember}" || die "cannot create ${contentmember}" |
197 |
+ chmod400files[${#chmod400files[@]}]=${ED}${contentmember} |
198 |
+ done |
199 |
+ popd >/dev/null || die "cannot leave ${libmetadir}" |
200 |
+ prunedirs[${#prunedirs[@]}]=${libmetadir} |
201 |
+ done |
202 |
+ [[ ${#chmod400files[@]} == 0 ]] || |
203 |
+ chmod 0400 "${chmod400files[@]}" || die "cannot chmod ${chmod400files[@]}" |
204 |
+ [[ ${#prunedirs[@]} == 0 ]] || |
205 |
+ rm -rf "${prunedirs[@]}" || die "cannot prune ${prunedirs[@]}" |
206 |
+ return 0 |
207 |
+} |
208 |
+ |
209 |
+postinst_aix() { |
210 |
+ if [[ ${CHOST} != *-aix* ]] || hasq binchecks ${RESTRICT}; then |
211 |
+ return 0 |
212 |
+ fi |
213 |
+ local MY_PR=${PR%r0} |
214 |
+ local ar strip |
215 |
+ if type ${CHOST}-ar >/dev/null 2>&1 && type ${CHOST}-strip >/dev/null 2>&1; then |
216 |
+ ar=${CHOST}-ar |
217 |
+ strip=${CHOST}-strip |
218 |
+ elif [[ ${CBUILD} == "${CHOST}" ]] && type ar >/dev/null 2>&1 && type strip >/dev/null 2>&1; then |
219 |
+ ar=ar |
220 |
+ strip=strip |
221 |
+ elif [[ -x /usr/ccs/bin/ar && -x /usr/ccs/bin/strip ]]; then |
222 |
+ ar=/usr/ccs/bin/ar |
223 |
+ strip=/usr/ccs/bin/strip |
224 |
+ else |
225 |
+ die "cannot find where to use 'ar' and 'strip' from" |
226 |
+ fi |
227 |
+ |
228 |
+ local member contentmember activecontentmembers= prev_archive= archive activearchives= |
229 |
+ while read member; do |
230 |
+ member=${member#*;} # drop "^type;" |
231 |
+ member=${member%%;*} # drop ";soname;runpath;needed$" |
232 |
+ [[ ${member##*/} == *'['*']' ]] || continue |
233 |
+ contentmember=${member%/*}/.${member##*/} |
234 |
+ activecontentmembers="${activecontentmembers}:(${contentmember}):" |
235 |
+ archive=${member%[*} |
236 |
+ [[ ${prev_archive} != ${archive} ]] || continue |
237 |
+ prev_archive=${archive} |
238 |
+ activearchives="${activearchives}:(${archive}):" |
239 |
+ done < "${PORTAGE_BUILDDIR}"/build-info/NEEDED.XCOFF.1 |
240 |
+ |
241 |
+ local type allcontentmembers= all_archives=() |
242 |
+ prev_archive= |
243 |
+ while read type contentmember; do |
244 |
+ contentmember=${contentmember% *} # drop " timestamp$" |
245 |
+ contentmember=${contentmember% *} # drop " hash$" |
246 |
+ [[ ${contentmember##*/} == *'['*']' ]] || continue |
247 |
+ allcontentmembers="${allcontentmembers}:(${contentmember}):" |
248 |
+ member=${contentmember%/.*}/${contentmember##*/.} |
249 |
+ archive=${member%[*} |
250 |
+ [[ ${prev_archive} != ${archive} ]] || continue |
251 |
+ prev_archive=${archive} |
252 |
+ all_archives[${#all_archives[@]}]=${archive} |
253 |
+ done < "${EPREFIX}/var/db/pkg/${CATEGORY}/${P}${MY_PR:+-}${MY_PR}/CONTENTS" |
254 |
+ |
255 |
+ local delmembers oldmembers libmetadir prunemembers=() prunedirs=() |
256 |
+ for archive in "${all_archives[@]}"; do |
257 |
+ [[ -r ${ROOT}${archive} && -w ${ROOT}${archive} ]] || |
258 |
+ chmod a+r,u+w "${ROOT}${archive}" || die "cannot chmod ${archive}" |
259 |
+ delmembers= oldmembers= |
260 |
+ for member in $(${ar} -X32_64 -t "${ROOT}${archive}"); do |
261 |
+ contentmember="${archive%/*}/.${archive##*/}[${member}]" |
262 |
+ if [[ ${allcontentmembers} != *":(${contentmember}):"* ]]; then |
263 |
+ # not existent any more, just drop it |
264 |
+ delmembers="${delmembers} ${member}" |
265 |
+ prunemembers[${#prunemembers[@]}]=${ROOT}${contentmember} |
266 |
+ elif [[ ${activecontentmembers} != *":(${contentmember}):"* ]]; then |
267 |
+ oldmembers="${oldmembers} ${member}" |
268 |
+ fi |
269 |
+ done |
270 |
+ if [[ -n ${delmembers} ]]; then |
271 |
+ einfo "dropping${delmembers}" |
272 |
+ ${ar} -X32_64 -z -o -d "${ROOT}${archive}" ${delmembers} || die "cannot remove${delmembers} from ${archive}" |
273 |
+ eend $? |
274 |
+ fi |
275 |
+ if [[ -n ${oldmembers} && ${activearchives} != *":(${archive}):"* ]]; then |
276 |
+ einfo "preserving (extra)${oldmembers}" |
277 |
+ libmetadir=${ROOT}${archive%/*}/.${archive##*/} |
278 |
+ [[ ! -e ${libmetadir} ]] || rm -rf "${libmetadir}" || die "cannot prune ${libmetadir}" |
279 |
+ mkdir "${libmetadir}" || die "cannot create ${libmetadir}" |
280 |
+ pushd "${libmetadir}" >/dev/null || die "cannot cd to ${libmetadir}" |
281 |
+ ${ar} -X32_64 -x "${ROOT}${archive}" ${oldmembers} || die "cannot unpack ${archive}" |
282 |
+ ${strip} -e ${oldmembers} || die "cannot strip ${oldmembers}" |
283 |
+ ${ar} -X32_64 -z -o -r "${ROOT}${archive}" ${oldmembers} || die "cannot update${oldmembers} in ${archive}" |
284 |
+ popd > /dev/null || die "cannot leave ${libmetadir}" |
285 |
+ prunedirs[${#prunedirs[@]}]=${libmetadir} |
286 |
+ eend $? |
287 |
+ fi |
288 |
+ done |
289 |
+ [[ ${#prunedirs[@]} == 0 ]] || |
290 |
+ rm -rf "${prunedirs[@]}" || die "cannot prune ${prunedirs[@]}" |
291 |
+ [[ ${#prunemembers[@]} == 0 ]] || |
292 |
+ rm -f "${prunemembers[@]}" || die "cannot prune ${contentmenbers[@]}" |
293 |
+ return 0 |
294 |
+} |
295 |
+ |
296 |
preinst_mask() { |
297 |
if [ -z "${D}" ]; then |
298 |
eerror "${FUNCNAME}: D is unset" |
299 |
|
300 |
Modified: main/branches/prefix/pym/portage/__init__.py |
301 |
=================================================================== |
302 |
--- main/branches/prefix/pym/portage/__init__.py 2009-10-28 19:27:43 UTC (rev 14744) |
303 |
+++ main/branches/prefix/pym/portage/__init__.py 2009-10-28 19:38:53 UTC (rev 14745) |
304 |
@@ -5655,6 +5655,7 @@ |
305 |
"install_symlink_html_docs"], |
306 |
|
307 |
"preinst" : [ |
308 |
+ "preinst_aix", |
309 |
"preinst_bsdflags", |
310 |
"preinst_sfperms", |
311 |
"preinst_selinux_labels", |
312 |
@@ -5662,6 +5663,7 @@ |
313 |
"preinst_mask"], |
314 |
|
315 |
"postinst" : [ |
316 |
+ "postinst_aix", |
317 |
"postinst_bsdflags"] |
318 |
} |
319 |
|
320 |
|
321 |
Modified: main/branches/prefix/pym/portage/dbapi/vartree.py |
322 |
=================================================================== |
323 |
--- main/branches/prefix/pym/portage/dbapi/vartree.py 2009-10-28 19:27:43 UTC (rev 14744) |
324 |
+++ main/branches/prefix/pym/portage/dbapi/vartree.py 2009-10-28 19:38:53 UTC (rev 14745) |
325 |
@@ -5,7 +5,7 @@ |
326 |
from __future__ import print_function |
327 |
|
328 |
__all__ = ["PreservedLibsRegistry", "LinkageMap", |
329 |
- "LinkageMapMachO", "LinkageMapPeCoff", |
330 |
+ "LinkageMapMachO", "LinkageMapPeCoff", "LinkageMapXCoff" |
331 |
"vardbapi", "vartree", "dblink"] + \ |
332 |
["write_contents", "tar_contents"] |
333 |
|
334 |
@@ -26,7 +26,7 @@ |
335 |
) |
336 |
|
337 |
from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \ |
338 |
- PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH, EPREFIX, EPREFIX_LSTRIP |
339 |
+ PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH, EPREFIX, EPREFIX_LSTRIP, BASH_BINARY |
340 |
from portage.data import portage_gid, portage_uid, secpass |
341 |
from portage.dbapi import dbapi |
342 |
from portage.exception import CommandNotFound, \ |
343 |
@@ -1479,7 +1479,253 @@ |
344 |
arch_map[needed_soname] = soname_map |
345 |
soname_map.consumers.add(obj_key) |
346 |
|
347 |
+class LinkageMapXCoff(LinkageMap): |
348 |
|
349 |
+ """Models dynamic linker dependencies.""" |
350 |
+ |
351 |
+ _needed_aux_key = "NEEDED.XCOFF.1" |
352 |
+ |
353 |
+ class _ObjectKey(LinkageMap._ObjectKey): |
354 |
+ |
355 |
+ def __init__(self, obj, root): |
356 |
+ LinkageMap._ObjectKey.__init__(self, obj, root) |
357 |
+ |
358 |
+ def _generate_object_key(self, obj, root): |
359 |
+ """ |
360 |
+ Generate object key for a given object. |
361 |
+ |
362 |
+ @param object: path to a file |
363 |
+ @type object: string (example: '/usr/bin/bar') |
364 |
+ @rtype: 2-tuple of types (long, int) if object exists. string if |
365 |
+ object does not exist. |
366 |
+ @return: |
367 |
+ 1. 2-tuple of object's inode and device from a stat call, if object |
368 |
+ exists. |
369 |
+ 2. realpath of object if object does not exist. |
370 |
+ |
371 |
+ """ |
372 |
+ |
373 |
+ os = _os_merge |
374 |
+ |
375 |
+ try: |
376 |
+ _unicode_encode(obj, |
377 |
+ encoding=_encodings['merge'], errors='strict') |
378 |
+ except UnicodeEncodeError: |
379 |
+ # The package appears to have been merged with a |
380 |
+ # different value of sys.getfilesystemencoding(), |
381 |
+ # so fall back to utf_8 if appropriate. |
382 |
+ try: |
383 |
+ _unicode_encode(obj, |
384 |
+ encoding=_encodings['fs'], errors='strict') |
385 |
+ except UnicodeEncodeError: |
386 |
+ pass |
387 |
+ else: |
388 |
+ os = portage.os |
389 |
+ |
390 |
+ abs_path = os.path.join(root, obj.lstrip(os.sep)) |
391 |
+ try: |
392 |
+ object_stat = os.stat(abs_path) |
393 |
+ except OSError: |
394 |
+ # Use the realpath as the key if the file does not exists on the |
395 |
+ # filesystem. |
396 |
+ return os.path.realpath(abs_path) |
397 |
+ # Return a tuple of the device and inode, as well as the basename, |
398 |
+ # because of hardlinks the device and inode might be identical. |
399 |
+ return (object_stat.st_dev, object_stat.st_ino, os.path.basename(abs_path.rstrip(os.sep))) |
400 |
+ |
401 |
+ def file_exists(self): |
402 |
+ """ |
403 |
+ Determine if the file for this key exists on the filesystem. |
404 |
+ |
405 |
+ @rtype: Boolean |
406 |
+ @return: |
407 |
+ 1. True if the file exists. |
408 |
+ 2. False if the file does not exist or is a broken symlink. |
409 |
+ |
410 |
+ """ |
411 |
+ return isinstance(self._key, tuple) |
412 |
+ |
413 |
+ class _LibGraphNode(_ObjectKey): |
414 |
+ __slots__ = ("alt_paths",) |
415 |
+ |
416 |
+ def __init__(self, obj, root): |
417 |
+ LinkageMapXCoff._ObjectKey.__init__(self, obj, root) |
418 |
+ self.alt_paths = set() |
419 |
+ |
420 |
+ def __str__(self): |
421 |
+ return str(sorted(self.alt_paths)) |
422 |
+ |
423 |
+ def rebuild(self, exclude_pkgs=None, include_file=None): |
424 |
+ """ |
425 |
+ Raises CommandNotFound if there are preserved libs |
426 |
+ and the scanelf binary is not available. |
427 |
+ """ |
428 |
+ |
429 |
+ os = _os_merge |
430 |
+ root = self._root |
431 |
+ root_len = len(root) - 1 |
432 |
+ self._clear_cache() |
433 |
+ self._defpath.update(getlibpaths(self._root)) |
434 |
+ libs = self._libs |
435 |
+ obj_key_cache = self._obj_key_cache |
436 |
+ obj_properties = self._obj_properties |
437 |
+ |
438 |
+ lines = [] |
439 |
+ |
440 |
+ # Data from include_file is processed first so that it |
441 |
+ # overrides any data from previously installed files. |
442 |
+ if include_file is not None: |
443 |
+ lines += grabfile(include_file) |
444 |
+ |
445 |
+ aux_keys = [self._needed_aux_key] |
446 |
+ for cpv in self._dbapi.cpv_all(): |
447 |
+ if exclude_pkgs is not None and cpv in exclude_pkgs: |
448 |
+ continue |
449 |
+ lines += self._dbapi.aux_get(cpv, aux_keys)[0].split('\n') |
450 |
+ # Cache NEEDED.* files avoid doing excessive IO for every rebuild. |
451 |
+ self._dbapi.flush_cache() |
452 |
+ |
453 |
+ # have to call scanelf for preserved libs here as they aren't |
454 |
+ # registered in NEEDED.XCOFF.1 files |
455 |
+ if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs(): |
456 |
+ for items in self._dbapi.plib_registry.getPreservedLibs().values(): |
457 |
+ for x in items: |
458 |
+ args = [BASH_BINARY, "-c", ':' |
459 |
+ + '; member="' + x + '"' |
460 |
+ + '; archive=${member}' |
461 |
+ + '; if [[ ${member##*/} == .*"["*"]" ]]' |
462 |
+ + '; then member=${member%/.*}/${member##*/.}' |
463 |
+ + '; archive=${member%[*}' |
464 |
+ + '; fi' |
465 |
+ + '; member=${member#${archive}}' |
466 |
+ + '; [[ -r ${archive} ]] || chmod a+r "${archive}"' |
467 |
+ + '; eval $(aixdll-query "${archive}${member}" FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS)' |
468 |
+ + '; [[ -n ${member} ]] && needed=${FILE##*/} || needed=' |
469 |
+ + '; for deplib in ${DEPLIBS}' |
470 |
+ + '; do eval deplib=${deplib}' |
471 |
+ + '; if [[ ${deplib} != "." && ${deplib} != ".." ]]' |
472 |
+ + '; then needed="${needed}${needed:+,}${deplib}"' |
473 |
+ + '; fi' |
474 |
+ + '; done' |
475 |
+ + '; [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]"' |
476 |
+ + '; [[ " ${FLAGS} " == *" SHROBJ "* ]] && soname=${FILE##*/}${MEMBER} || soname=' |
477 |
+ + '; echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}}${MEMBER};${soname};${RUNPATH};${needed}"' |
478 |
+ + '; [[ -n ${member} ]] || echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}};${FILE##*/};;"' |
479 |
+ ] |
480 |
+ try: |
481 |
+ proc = subprocess.Popen(args, stdout=subprocess.PIPE) |
482 |
+ except EnvironmentError as e: |
483 |
+ if e.errno != errno.ENOENT: |
484 |
+ raise |
485 |
+ raise CommandNotFound("aixdll-query via " + argv[0]) |
486 |
+ else: |
487 |
+ for l in proc.stdout: |
488 |
+ try: |
489 |
+ l = _unicode_decode(l, |
490 |
+ encoding=_encodings['content'], errors='strict') |
491 |
+ except UnicodeDecodeError: |
492 |
+ l = _unicode_decode(l, |
493 |
+ encoding=_encodings['content'], errors='replace') |
494 |
+ writemsg_level(_("\nError decoding characters " \ |
495 |
+ "returned from aixdll-query: %s\n\n") % (l,), |
496 |
+ level=logging.ERROR, noiselevel=-1) |
497 |
+ l = l.rstrip("\n") |
498 |
+ if not l: |
499 |
+ continue |
500 |
+ fields = l.split(";") |
501 |
+ if len(fields) < 5: |
502 |
+ writemsg_level(_("\nWrong number of fields " \ |
503 |
+ "returned from aixdll-query: %s\n\n") % (l,), |
504 |
+ level=logging.ERROR, noiselevel=-1) |
505 |
+ continue |
506 |
+ fields[1] = fields[1][root_len:] |
507 |
+ lines.append(";".join(fields)) |
508 |
+ proc.wait() |
509 |
+ |
510 |
+ for l in lines: |
511 |
+ l = l.rstrip("\n") |
512 |
+ if not l: |
513 |
+ continue |
514 |
+ fields = l.split(";") |
515 |
+ if len(fields) < 5: |
516 |
+ writemsg_level(_("\nWrong number of fields " \ |
517 |
+ "in %s: %s\n\n") % (self._needed_aux_key, l), |
518 |
+ level=logging.ERROR, noiselevel=-1) |
519 |
+ continue |
520 |
+ arch = fields[0] |
521 |
+ |
522 |
+ def as_contentmember(obj): |
523 |
+ if obj.endswith("]"): |
524 |
+ if obj.find("/") >= 0: |
525 |
+ return obj[:obj.rfind("/")] + "/." + obj[obj.rfind("/")+1:] |
526 |
+ return "." + obj |
527 |
+ return obj |
528 |
+ |
529 |
+ obj = as_contentmember(fields[1]) |
530 |
+ soname = as_contentmember(fields[2]) |
531 |
+ path = set([normalize_path(x) \ |
532 |
+ for x in filter(None, fields[3].replace( |
533 |
+ "${ORIGIN}", os.path.dirname(obj)).replace( |
534 |
+ "$ORIGIN", os.path.dirname(obj)).split(":"))]) |
535 |
+ needed = [as_contentmember(x) for x in fields[4].split(",") if x] |
536 |
+ |
537 |
+ obj_key = self._obj_key(obj) |
538 |
+ indexed = True |
539 |
+ myprops = obj_properties.get(obj_key) |
540 |
+ if myprops is None: |
541 |
+ indexed = False |
542 |
+ myprops = (arch, needed, path, soname, set()) |
543 |
+ obj_properties[obj_key] = myprops |
544 |
+ # All object paths are added into the obj_properties tuple. |
545 |
+ myprops[4].add(obj) |
546 |
+ |
547 |
+ # Don't index the same file more that once since only one |
548 |
+ # set of data can be correct and therefore mixing data |
549 |
+ # may corrupt the index (include_file overrides previously |
550 |
+ # installed). |
551 |
+ if indexed: |
552 |
+ continue |
553 |
+ |
554 |
+ arch_map = libs.get(arch) |
555 |
+ if arch_map is None: |
556 |
+ arch_map = {} |
557 |
+ libs[arch] = arch_map |
558 |
+ if soname: |
559 |
+ soname_map = arch_map.get(soname) |
560 |
+ if soname_map is None: |
561 |
+ soname_map = self._soname_map_class( |
562 |
+ providers=set(), consumers=set()) |
563 |
+ arch_map[soname] = soname_map |
564 |
+ soname_map.providers.add(obj_key) |
565 |
+ for needed_soname in needed: |
566 |
+ soname_map = arch_map.get(needed_soname) |
567 |
+ if soname_map is None: |
568 |
+ soname_map = self._soname_map_class( |
569 |
+ providers=set(), consumers=set()) |
570 |
+ arch_map[needed_soname] = soname_map |
571 |
+ soname_map.consumers.add(obj_key) |
572 |
+ |
573 |
+ def getSoname(self, obj): |
574 |
+ """ |
575 |
+ Return the soname associated with an object. |
576 |
+ |
577 |
+ @param obj: absolute path to an object |
578 |
+ @type obj: string (example: '/usr/bin/bar') |
579 |
+ @rtype: string |
580 |
+ @return: soname as a string |
581 |
+ |
582 |
+ """ |
583 |
+ if not self._libs: |
584 |
+ self.rebuild() |
585 |
+ if isinstance(obj, self._ObjectKey): |
586 |
+ obj_key = obj |
587 |
+ if obj_key not in self._obj_properties: |
588 |
+ raise KeyError("%s not in object list" % obj_key) |
589 |
+ return self._obj_properties[obj_key][3] |
590 |
+ if obj not in self._obj_key_cache: |
591 |
+ raise KeyError("%s not in object list" % obj) |
592 |
+ return self._obj_properties[self._obj_key_cache[obj]][3] |
593 |
+ |
594 |
class vardbapi(dbapi): |
595 |
|
596 |
_excluded_dirs = ["CVS", "lost+found"] |
597 |
@@ -1552,6 +1798,8 @@ |
598 |
self.linkmap = LinkageMapMachO(self) |
599 |
elif chost.find('interix') >= 0 or chost.find('winnt') >= 0: |
600 |
self.linkmap = LinkageMapPeCoff(self) |
601 |
+ elif chost.find('aix'): |
602 |
+ self.linkmap = LinkageMapXCoff(self) |
603 |
else: |
604 |
self.linkmap = LinkageMap(self) |
605 |
self._owners = self._owners_db(self) |
606 |
@@ -3698,6 +3946,8 @@ |
607 |
node = LinkageMapMachO._LibGraphNode(path, root) |
608 |
elif chost.find('interix') >= 0 or chost.find('winnt') >= 0: |
609 |
node = LinkageMapPeCoff._LibGraphNode(path, root) |
610 |
+ elif chost.find('aix') >= 0: |
611 |
+ node = LinkageMapXCoff._LibGraphNode(path, root) |
612 |
else: |
613 |
node = LinkageMap._LibGraphNode(path, root) |
614 |
alt_path_node = lib_graph.get(node) |