1 |
here's v2 |
2 |
-mike |
3 |
|
4 |
# Copyright 1999-2012 Gentoo Foundation |
5 |
# Distributed under the terms of the GNU General Public License v2 |
6 |
# $Header: /var/cvsroot/gentoo-x86/eclass/eutils.eclass,v 1.377 2012/01/03 08:45:36 jlec Exp $ |
7 |
|
8 |
# @ECLASS: unpacker.eclass |
9 |
# @MAINTAINER: |
10 |
# base-system@g.o |
11 |
# @BLURB: helpers for extraneous file formats and consistent behavior across EAPIs |
12 |
# @DESCRIPTION: |
13 |
# Some extraneous file formats are not part of PMS, or are only in certain |
14 |
# EAPIs. Rather than worrying about that, support the crazy cruft here |
15 |
# and for all EAPI versions. |
16 |
|
17 |
# Possible todos: |
18 |
# - merge rpm unpacking |
19 |
# - support partial unpacks? |
20 |
|
21 |
if [[ ${___ECLASS_ONCE_UNPACKER} != "recur -_+^+_- spank" ]] ; then |
22 |
___ECLASS_ONCE_UNPACKER="recur -_+^+_- spank" |
23 |
|
24 |
# @ECLASS-VARIABLE: UNPACKER_BZ2 |
25 |
# @DEFAULT_UNSET |
26 |
# @DESCRIPTION: |
27 |
# Utility to use to decompress bzip2 files. Will dynamically pick between |
28 |
# `pbzip2` and `bzip2`. Make sure your choice accepts the "-c" option. |
29 |
# Note: this is meant for users to set, not ebuilds. |
30 |
|
31 |
# for internal use only (unpack_pdv and unpack_makeself) |
32 |
find_unpackable_file() { |
33 |
local src=$1 |
34 |
if [[ -z ${src} ]] ; then |
35 |
src=${DISTDIR}/${A} |
36 |
else |
37 |
if [[ ${src} == ./* ]] ; then |
38 |
: # already what we want |
39 |
elif [[ -e ${DISTDIR}/${src} ]] ; then |
40 |
src=${DISTDIR}/${src} |
41 |
elif [[ -e ${PWD}/${src} ]] ; then |
42 |
src=${PWD}/${src} |
43 |
elif [[ -e ${src} ]] ; then |
44 |
src=${src} |
45 |
fi |
46 |
fi |
47 |
[[ ! -e ${src} ]] && return 1 |
48 |
echo "${src}" |
49 |
} |
50 |
|
51 |
unpack_banner() { |
52 |
echo ">>> Unpacking ${1##*/} to ${PWD}" |
53 |
} |
54 |
|
55 |
# @FUNCTION: unpack_pdv |
56 |
# @USAGE: <file to unpack> <size of off_t> |
57 |
# @DESCRIPTION: |
58 |
# Unpack those pesky pdv generated files ... |
59 |
# They're self-unpacking programs with the binary package stuffed in |
60 |
# the middle of the archive. Valve seems to use it a lot ... too bad |
61 |
# it seems to like to segfault a lot :(. So lets take it apart ourselves. |
62 |
# |
63 |
# You have to specify the off_t size ... I have no idea how to extract that |
64 |
# information out of the binary executable myself. Basically you pass in |
65 |
# the size of the off_t type (in bytes) on the machine that built the pdv |
66 |
# archive. |
67 |
# |
68 |
# One way to determine this is by running the following commands: |
69 |
# |
70 |
# @CODE |
71 |
# strings <pdv archive> | grep lseek |
72 |
# strace -elseek <pdv archive> |
73 |
# @CODE |
74 |
# |
75 |
# Basically look for the first lseek command (we do the strings/grep because |
76 |
# sometimes the function call is _llseek or something) and steal the 2nd |
77 |
# parameter. Here is an example: |
78 |
# |
79 |
# @CODE |
80 |
# vapier@vapier 0 pdv_unpack # strings hldsupdatetool.bin | grep lseek |
81 |
# lseek |
82 |
# vapier@vapier 0 pdv_unpack # strace -elseek ./hldsupdatetool.bin |
83 |
# lseek(3, -4, SEEK_END) = 2981250 |
84 |
# @CODE |
85 |
# |
86 |
# Thus we would pass in the value of '4' as the second parameter. |
87 |
unpack_pdv() { |
88 |
local src=$(find_unpackable_file "$1") |
89 |
local sizeoff_t=$2 |
90 |
|
91 |
[[ -z ${src} ]] && die "Could not locate source for '$1'" |
92 |
[[ -z ${sizeoff_t} ]] && die "No idea what off_t size was used for this pdv :(" |
93 |
|
94 |
unpack_banner "${src}" |
95 |
|
96 |
local metaskip=$(tail -c ${sizeoff_t} "${src}" | hexdump -e \"%i\") |
97 |
local tailskip=$(tail -c $((${sizeoff_t}*2)) "${src}" | head -c ${sizeoff_t} | hexdump -e \"%i\") |
98 |
|
99 |
# grab metadata for debug reasons |
100 |
local metafile=$(emktemp) |
101 |
tail -c +$((${metaskip}+1)) "${src}" > "${metafile}" |
102 |
|
103 |
# rip out the final file name from the metadata |
104 |
local datafile=$(tail -c +$((${metaskip}+1)) "${src}" | strings | head -n 1) |
105 |
datafile=$(basename "${datafile}") |
106 |
|
107 |
# now lets uncompress/untar the file if need be |
108 |
local tmpfile=$(emktemp) |
109 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null | head -c 512 > ${tmpfile} |
110 |
|
111 |
local iscompressed=$(file -b "${tmpfile}") |
112 |
if [[ ${iscompressed:0:8} == "compress" ]] ; then |
113 |
iscompressed=1 |
114 |
mv ${tmpfile}{,.Z} |
115 |
gunzip ${tmpfile} |
116 |
else |
117 |
iscompressed=0 |
118 |
fi |
119 |
local istar=$(file -b "${tmpfile}") |
120 |
if [[ ${istar:0:9} == "POSIX tar" ]] ; then |
121 |
istar=1 |
122 |
else |
123 |
istar=0 |
124 |
fi |
125 |
|
126 |
#for some reason gzip dies with this ... dd cant provide buffer fast enough ? |
127 |
#dd if=${src} ibs=${metaskip} count=1 \ |
128 |
# | dd ibs=${tailskip} skip=1 \ |
129 |
# | gzip -dc \ |
130 |
# > ${datafile} |
131 |
if [ ${iscompressed} -eq 1 ] ; then |
132 |
if [ ${istar} -eq 1 ] ; then |
133 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
134 |
| head -c $((${metaskip}-${tailskip})) \ |
135 |
| tar -xzf - |
136 |
else |
137 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
138 |
| head -c $((${metaskip}-${tailskip})) \ |
139 |
| gzip -dc \ |
140 |
> ${datafile} |
141 |
fi |
142 |
else |
143 |
if [ ${istar} -eq 1 ] ; then |
144 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
145 |
| head -c $((${metaskip}-${tailskip})) \ |
146 |
| tar --no-same-owner -xf - |
147 |
else |
148 |
tail -c +$((${tailskip}+1)) ${src} 2>/dev/null \ |
149 |
| head -c $((${metaskip}-${tailskip})) \ |
150 |
> ${datafile} |
151 |
fi |
152 |
fi |
153 |
true |
154 |
#[ -s "${datafile}" ] || die "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')" |
155 |
#assert "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')" |
156 |
} |
157 |
|
158 |
# @FUNCTION: unpack_makeself |
159 |
# @USAGE: [file to unpack] [offset] [tail|dd] |
160 |
# @DESCRIPTION: |
161 |
# Unpack those pesky makeself generated files ... |
162 |
# They're shell scripts with the binary package tagged onto |
163 |
# the end of the archive. Loki utilized the format as does |
164 |
# many other game companies. |
165 |
# |
166 |
# If the file is not specified, then ${A} is used. If the |
167 |
# offset is not specified then we will attempt to extract |
168 |
# the proper offset from the script itself. |
169 |
unpack_makeself() { |
170 |
local src_input=${1:-${A}} |
171 |
local src=$(find_unpackable_file "${src_input}") |
172 |
local skip=$2 |
173 |
local exe=$3 |
174 |
|
175 |
[[ -z ${src} ]] && die "Could not locate source for '${src_input}'" |
176 |
|
177 |
unpack_banner "${src}" |
178 |
|
179 |
if [[ -z ${skip} ]] ; then |
180 |
local ver=$(grep -m1 -a '#.*Makeself' "${src}" | awk '{print $NF}') |
181 |
local skip=0 |
182 |
exe=tail |
183 |
case ${ver} in |
184 |
1.5.*|1.6.0-nv) # tested 1.5.{3,4,5} ... guessing 1.5.x series is same |
185 |
skip=$(grep -a ^skip= "${src}" | cut -d= -f2) |
186 |
;; |
187 |
2.0|2.0.1) |
188 |
skip=$(grep -a ^$'\t'tail "${src}" | awk '{print $2}' | cut -b2-) |
189 |
;; |
190 |
2.1.1) |
191 |
skip=$(grep -a ^offset= "${src}" | awk '{print $2}' | cut -b2-) |
192 |
(( skip++ )) |
193 |
;; |
194 |
2.1.2) |
195 |
skip=$(grep -a ^offset= "${src}" | awk '{print $3}' | head -n 1) |
196 |
(( skip++ )) |
197 |
;; |
198 |
2.1.3) |
199 |
skip=`grep -a ^offset= "${src}" | awk '{print $3}'` |
200 |
(( skip++ )) |
201 |
;; |
202 |
2.1.4|2.1.5) |
203 |
skip=$(grep -a offset=.*head.*wc "${src}" | awk '{print $3}' | head -n 1) |
204 |
skip=$(head -n ${skip} "${src}" | wc -c) |
205 |
exe="dd" |
206 |
;; |
207 |
*) |
208 |
eerror "I'm sorry, but I was unable to support the Makeself file." |
209 |
eerror "The version I detected was '${ver}'." |
210 |
eerror "Please file a bug about the file ${src##*/} at" |
211 |
eerror "http://bugs.gentoo.org/ so that support can be added." |
212 |
die "makeself version '${ver}' not supported" |
213 |
;; |
214 |
esac |
215 |
debug-print "Detected Makeself version ${ver} ... using ${skip} as offset" |
216 |
fi |
217 |
case ${exe} in |
218 |
tail) exe="tail -n +${skip} '${src}'";; |
219 |
dd) exe="dd ibs=${skip} skip=1 if='${src}'";; |
220 |
*) die "makeself cant handle exe '${exe}'" |
221 |
esac |
222 |
|
223 |
# lets grab the first few bytes of the file to figure out what kind of archive it is |
224 |
local filetype tmpfile=$(emktemp) |
225 |
eval ${exe} 2>/dev/null | head -c 512 > "${tmpfile}" |
226 |
filetype=$(file -b "${tmpfile}") || die |
227 |
case ${filetype} in |
228 |
*tar\ archive*) |
229 |
eval ${exe} | tar --no-same-owner -xf - |
230 |
;; |
231 |
bzip2*) |
232 |
eval ${exe} | bzip2 -dc | tar --no-same-owner -xf - |
233 |
;; |
234 |
gzip*) |
235 |
eval ${exe} | tar --no-same-owner -xzf - |
236 |
;; |
237 |
compress*) |
238 |
eval ${exe} | gunzip | tar --no-same-owner -xf - |
239 |
;; |
240 |
*) |
241 |
eerror "Unknown filetype \"${filetype}\" ?" |
242 |
false |
243 |
;; |
244 |
esac |
245 |
assert "failure unpacking (${filetype}) makeself ${src##*/} ('${ver}' +${skip})" |
246 |
} |
247 |
|
248 |
# @FUNCTION: unpack_deb |
249 |
# @USAGE: <one deb to unpack> |
250 |
# @DESCRIPTION: |
251 |
# Unpack a Debian .deb archive in style. |
252 |
unpack_deb() { |
253 |
[[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>" |
254 |
|
255 |
local deb=$(find_unpackable_file "$1") |
256 |
|
257 |
unpack_banner "${deb}" |
258 |
|
259 |
ar x "${deb}" |
260 |
unpack ./data.tar* |
261 |
} |
262 |
|
263 |
# @FUNCTION: _unpacker |
264 |
# @USAGE: <one archive to unpack> |
265 |
# @INTERNAL |
266 |
# @DESCRIPTION: |
267 |
# Unpack the specified archive. We only operate on one archive here |
268 |
# to keep down on the looping logic (that is handled by `unpacker`). |
269 |
_unpacker() { |
270 |
[[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>" |
271 |
|
272 |
local a=$1 |
273 |
local m=$(echo "${a}" | tr '[:upper:]' '[:lower:]') |
274 |
a=$(find_unpackable_file "${a}") |
275 |
|
276 |
# first figure out the decompression method |
277 |
case ${m} in |
278 |
*.bz2|*.tbz|*.tbz2) |
279 |
local bzcmd=${PORTAGE_BZIP2_COMMAND:-$(type -P pbzip2 || bzip2)} |
280 |
local bzuncmd=${PORTAGE_BUNZIP2_COMMAND:-${PORTAGE_BZIP2_COMMAND} -d} |
281 |
: ${UNPACKER_BZ2:=${bzuncmd}} |
282 |
comp="${UNPACKER_BZ2} -c" |
283 |
;; |
284 |
*.z|*.gz|*.tgz) |
285 |
comp="gzip -dc" ;; |
286 |
*.lzma|*.xz|*.txz) |
287 |
comp="xz -dc" ;; |
288 |
*) comp="" ;; |
289 |
esac |
290 |
|
291 |
# then figure out if there are any archiving aspects |
292 |
case ${m} in |
293 |
*.tgz|*.tbz|*.tbz2|*.txz|*.tar.*|*.tar) |
294 |
arch="tar --no-same-owner -xof" ;; |
295 |
*.deb) |
296 |
arch="unpack_deb" ;; |
297 |
*.run) |
298 |
arch="unpack_makeself" ;; |
299 |
*) arch="" ;; |
300 |
esac |
301 |
|
302 |
# finally do the unpack |
303 |
if [[ -z ${arch}${comp} ]] ; then |
304 |
unpack "${a}" |
305 |
return $? |
306 |
fi |
307 |
|
308 |
[[ ${arch} != unpack_* ]] && unpack_banner "${a}" |
309 |
|
310 |
if [[ -z ${arch} ]] ; then |
311 |
${comp} "${a}" > "${a%.*}" |
312 |
elif [[ -z ${comp} ]] ; then |
313 |
${arch} "${a}" |
314 |
else |
315 |
${comp} "${a}" | ${arch} - |
316 |
fi |
317 |
|
318 |
assert "unpacking ${a} failed (comp=${comp} arch=${arch})" |
319 |
} |
320 |
|
321 |
# @FUNCTION: unpacker |
322 |
# @USAGE: [archives to unpack] |
323 |
# @DESCRIPTION: |
324 |
# This works in the same way that `unpack` does. If you don't specify |
325 |
# any files, it will default to ${A}. |
326 |
unpacker() { |
327 |
local a |
328 |
[[ $# -eq 0 ]] && set -- ${A} |
329 |
for a ; do _unpacker "${a}" ; done |
330 |
} |
331 |
|
332 |
# @FUNCTION: unpacker_src_unpack |
333 |
# @DESCRIPTION: |
334 |
# Run `unpacker` to unpack all our stuff. |
335 |
unpacker_src_unpack() { |
336 |
unpacker |
337 |
} |
338 |
|
339 |
# @FUNCTION: unpacker_src_uri_depends |
340 |
# @USAGE: [archives that we will unpack] |
341 |
# @RETURN: Dependencies needed to unpack all the archives |
342 |
# @DESCRIPTION: |
343 |
# Walk all the specified files (defaults to $SRC_URI) and figure out the |
344 |
# dependencies that are needed to unpack things. |
345 |
# |
346 |
# Note: USE flags are not yet handled. |
347 |
unpacker_src_uri_depends() { |
348 |
local uri deps d |
349 |
|
350 |
[[ $# -eq 0 ]] && set -- ${SRC_URI} |
351 |
|
352 |
for uri in "$@" ; do |
353 |
case ${uri} in |
354 |
*.rar|*.RAR) |
355 |
d="app-arch/unrar" ;; |
356 |
*.7z) |
357 |
d="app-arch/p7zip" ;; |
358 |
*.xz) |
359 |
d="app-arch/xz-utils" ;; |
360 |
esac |
361 |
deps+=" ${d}" |
362 |
done |
363 |
|
364 |
echo "${deps}" |
365 |
} |
366 |
|
367 |
EXPORT_FUNCTIONS src_unpack |
368 |
|
369 |
fi |