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