Gentoo Archives: gentoo-commits

From: "Mike Frysinger (vapier)" <vapier@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in eclass: unpacker.eclass
Date: Sun, 05 Feb 2012 04:48:52
Message-Id: 20120205044842.37BCB2004B@flycatcher.gentoo.org
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