/[gentoo-x86]/eclass/unpacker.eclass
Gentoo

Contents of /eclass/unpacker.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations) (download)
Wed Apr 10 14:47:49 2013 UTC (20 months, 1 week ago) by jer
Branch: MAIN
Changes since 1.12: +5 -2 lines
Add support for 1.6.0-nv2 (bug #465340).

1 hasufell 1.12 # Copyright 1999-2013 Gentoo Foundation
2 vapier 1.1 # Distributed under the terms of the GNU General Public License v2
3 jer 1.13 # $Header: /var/cvsroot/gentoo-x86/eclass/unpacker.eclass,v 1.12 2013/03/23 21:18:25 hasufell Exp $
4 vapier 1.1
5     # @ECLASS: unpacker.eclass
6     # @MAINTAINER:
7     # base-system@gentoo.org
8     # @BLURB: helpers for extraneous file formats and consistent behavior across EAPIs
9     # @DESCRIPTION:
10     # Some extraneous file formats are not part of PMS, or are only in certain
11     # EAPIs. Rather than worrying about that, support the crazy cruft here
12     # and for all EAPI versions.
13    
14     # Possible todos:
15     # - merge rpm unpacking
16     # - support partial unpacks?
17    
18     if [[ ${___ECLASS_ONCE_UNPACKER} != "recur -_+^+_- spank" ]] ; then
19     ___ECLASS_ONCE_UNPACKER="recur -_+^+_- spank"
20    
21     # @ECLASS-VARIABLE: UNPACKER_BZ2
22     # @DEFAULT_UNSET
23     # @DESCRIPTION:
24     # Utility to use to decompress bzip2 files. Will dynamically pick between
25     # `pbzip2` and `bzip2`. Make sure your choice accepts the "-c" option.
26     # Note: this is meant for users to set, not ebuilds.
27    
28     # for internal use only (unpack_pdv and unpack_makeself)
29     find_unpackable_file() {
30     local src=$1
31     if [[ -z ${src} ]] ; then
32     src=${DISTDIR}/${A}
33     else
34     if [[ ${src} == ./* ]] ; then
35     : # already what we want
36     elif [[ -e ${DISTDIR}/${src} ]] ; then
37     src=${DISTDIR}/${src}
38     elif [[ -e ${PWD}/${src} ]] ; then
39     src=${PWD}/${src}
40     elif [[ -e ${src} ]] ; then
41     src=${src}
42     fi
43     fi
44     [[ ! -e ${src} ]] && return 1
45     echo "${src}"
46     }
47    
48     unpack_banner() {
49     echo ">>> Unpacking ${1##*/} to ${PWD}"
50     }
51    
52     # @FUNCTION: unpack_pdv
53     # @USAGE: <file to unpack> <size of off_t>
54     # @DESCRIPTION:
55     # Unpack those pesky pdv generated files ...
56     # They're self-unpacking programs with the binary package stuffed in
57     # the middle of the archive. Valve seems to use it a lot ... too bad
58     # it seems to like to segfault a lot :(. So lets take it apart ourselves.
59     #
60     # You have to specify the off_t size ... I have no idea how to extract that
61     # information out of the binary executable myself. Basically you pass in
62     # the size of the off_t type (in bytes) on the machine that built the pdv
63     # archive.
64     #
65     # One way to determine this is by running the following commands:
66     #
67     # @CODE
68     # strings <pdv archive> | grep lseek
69     # strace -elseek <pdv archive>
70     # @CODE
71     #
72     # Basically look for the first lseek command (we do the strings/grep because
73     # sometimes the function call is _llseek or something) and steal the 2nd
74     # parameter. Here is an example:
75     #
76     # @CODE
77     # vapier@vapier 0 pdv_unpack # strings hldsupdatetool.bin | grep lseek
78     # lseek
79     # vapier@vapier 0 pdv_unpack # strace -elseek ./hldsupdatetool.bin
80     # lseek(3, -4, SEEK_END) = 2981250
81     # @CODE
82     #
83     # Thus we would pass in the value of '4' as the second parameter.
84     unpack_pdv() {
85     local src=$(find_unpackable_file "$1")
86     local sizeoff_t=$2
87    
88     [[ -z ${src} ]] && die "Could not locate source for '$1'"
89     [[ -z ${sizeoff_t} ]] && die "No idea what off_t size was used for this pdv :("
90    
91     unpack_banner "${src}"
92    
93     local metaskip=$(tail -c ${sizeoff_t} "${src}" | hexdump -e \"%i\")
94     local tailskip=$(tail -c $((${sizeoff_t}*2)) "${src}" | head -c ${sizeoff_t} | hexdump -e \"%i\")
95    
96     # grab metadata for debug reasons
97 vapier 1.2 local metafile="${T}/${FUNCNAME}.meta"
98 vapier 1.1 tail -c +$((${metaskip}+1)) "${src}" > "${metafile}"
99    
100     # rip out the final file name from the metadata
101     local datafile=$(tail -c +$((${metaskip}+1)) "${src}" | strings | head -n 1)
102     datafile=$(basename "${datafile}")
103    
104     # now lets uncompress/untar the file if need be
105 vapier 1.2 local tmpfile="${T}/${FUNCNAME}"
106     tail -c +$((${tailskip}+1)) ${src} 2>/dev/null | head -c 512 > "${tmpfile}"
107 vapier 1.1
108     local iscompressed=$(file -b "${tmpfile}")
109     if [[ ${iscompressed:0:8} == "compress" ]] ; then
110     iscompressed=1
111 vapier 1.2 mv "${tmpfile}"{,.Z}
112     gunzip "${tmpfile}"
113 vapier 1.1 else
114     iscompressed=0
115     fi
116     local istar=$(file -b "${tmpfile}")
117     if [[ ${istar:0:9} == "POSIX tar" ]] ; then
118     istar=1
119     else
120     istar=0
121     fi
122    
123     #for some reason gzip dies with this ... dd cant provide buffer fast enough ?
124     #dd if=${src} ibs=${metaskip} count=1 \
125     # | dd ibs=${tailskip} skip=1 \
126     # | gzip -dc \
127     # > ${datafile}
128     if [ ${iscompressed} -eq 1 ] ; then
129     if [ ${istar} -eq 1 ] ; then
130 vapier 1.2 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
131 vapier 1.1 | head -c $((${metaskip}-${tailskip})) \
132     | tar -xzf -
133     else
134 vapier 1.2 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
135 vapier 1.1 | head -c $((${metaskip}-${tailskip})) \
136     | gzip -dc \
137     > ${datafile}
138     fi
139     else
140     if [ ${istar} -eq 1 ] ; then
141 vapier 1.2 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
142 vapier 1.1 | head -c $((${metaskip}-${tailskip})) \
143     | tar --no-same-owner -xf -
144     else
145 vapier 1.2 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
146 vapier 1.1 | head -c $((${metaskip}-${tailskip})) \
147     > ${datafile}
148     fi
149     fi
150     true
151     #[ -s "${datafile}" ] || die "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')"
152     #assert "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')"
153     }
154    
155     # @FUNCTION: unpack_makeself
156     # @USAGE: [file to unpack] [offset] [tail|dd]
157     # @DESCRIPTION:
158     # Unpack those pesky makeself generated files ...
159     # They're shell scripts with the binary package tagged onto
160     # the end of the archive. Loki utilized the format as does
161     # many other game companies.
162     #
163     # If the file is not specified, then ${A} is used. If the
164     # offset is not specified then we will attempt to extract
165     # the proper offset from the script itself.
166     unpack_makeself() {
167     local src_input=${1:-${A}}
168     local src=$(find_unpackable_file "${src_input}")
169     local skip=$2
170     local exe=$3
171    
172     [[ -z ${src} ]] && die "Could not locate source for '${src_input}'"
173    
174     unpack_banner "${src}"
175    
176     if [[ -z ${skip} ]] ; then
177     local ver=$(grep -m1 -a '#.*Makeself' "${src}" | awk '{print $NF}')
178     local skip=0
179     exe=tail
180     case ${ver} in
181 jer 1.13 1.5.*|1.6.0-nv*) # tested 1.5.{3,4,5} ... guessing 1.5.x series is same
182 vapier 1.1 skip=$(grep -a ^skip= "${src}" | cut -d= -f2)
183     ;;
184     2.0|2.0.1)
185     skip=$(grep -a ^$'\t'tail "${src}" | awk '{print $2}' | cut -b2-)
186     ;;
187     2.1.1)
188     skip=$(grep -a ^offset= "${src}" | awk '{print $2}' | cut -b2-)
189     (( skip++ ))
190     ;;
191     2.1.2)
192     skip=$(grep -a ^offset= "${src}" | awk '{print $3}' | head -n 1)
193     (( skip++ ))
194     ;;
195     2.1.3)
196     skip=`grep -a ^offset= "${src}" | awk '{print $3}'`
197     (( skip++ ))
198     ;;
199 vapier 1.4 2.1.4|2.1.5|2.1.6)
200 vapier 1.1 skip=$(grep -a offset=.*head.*wc "${src}" | awk '{print $3}' | head -n 1)
201     skip=$(head -n ${skip} "${src}" | wc -c)
202     exe="dd"
203     ;;
204     *)
205     eerror "I'm sorry, but I was unable to support the Makeself file."
206     eerror "The version I detected was '${ver}'."
207     eerror "Please file a bug about the file ${src##*/} at"
208     eerror "http://bugs.gentoo.org/ so that support can be added."
209     die "makeself version '${ver}' not supported"
210     ;;
211     esac
212     debug-print "Detected Makeself version ${ver} ... using ${skip} as offset"
213     fi
214     case ${exe} in
215     tail) exe="tail -n +${skip} '${src}'";;
216     dd) exe="dd ibs=${skip} skip=1 if='${src}'";;
217     *) die "makeself cant handle exe '${exe}'"
218     esac
219    
220     # lets grab the first few bytes of the file to figure out what kind of archive it is
221 vapier 1.2 local filetype tmpfile="${T}/${FUNCNAME}"
222 vapier 1.1 eval ${exe} 2>/dev/null | head -c 512 > "${tmpfile}"
223     filetype=$(file -b "${tmpfile}") || die
224     case ${filetype} in
225     *tar\ archive*)
226     eval ${exe} | tar --no-same-owner -xf -
227     ;;
228     bzip2*)
229     eval ${exe} | bzip2 -dc | tar --no-same-owner -xf -
230     ;;
231     gzip*)
232     eval ${exe} | tar --no-same-owner -xzf -
233     ;;
234     compress*)
235     eval ${exe} | gunzip | tar --no-same-owner -xf -
236     ;;
237 jer 1.13 XZ*)
238     eval ${exe} | unxz | tar --no-same-owner -xf -
239     ;;
240 vapier 1.1 *)
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 vapier 1.7 # on AIX ar doesn't work out as their ar used a different format
260     # from what GNU ar (and thus what .deb files) produce
261     if [[ -n ${EPREFIX} ]] ; then
262     {
263     read # global header
264     [[ ${REPLY} = "!<arch>" ]] || die "${deb} does not seem to be a deb archive"
265     local f timestamp uid gid mode size magic
266     while read f timestamp uid gid mode size magic ; do
267     [[ -n ${f} && -n ${size} ]] || continue # ignore empty lines
268     if [[ ${f} = "data.tar"* ]] ; then
269     head -c "${size}" > "${f}"
270     else
271     head -c "${size}" > /dev/null # trash it
272     fi
273     done
274     } < "${deb}"
275     else
276     ar x "${deb}"
277     fi
278    
279     unpacker ./data.tar*
280 vapier 1.11
281     # Clean things up #458658. No one seems to actually care about
282     # these, so wait until someone requests to do something else ...
283     rm -f debian-binary {control,data}.tar*
284 vapier 1.1 }
285    
286 ottxor 1.10 # @FUNCTION: unpack_cpio
287     # @USAGE: <one cpio to unpack>
288     # @DESCRIPTION:
289     # Unpack a cpio archive, file "-" means stdin.
290     unpack_cpio() {
291     [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
292    
293     # needed as cpio always reads from stdin
294     local cpio_cmd=( cpio --make-directories --extract --preserve-modification-time )
295     if [[ $1 == "-" ]] ; then
296     unpack_banner "stdin"
297     "${cpio_cmd[@]}"
298     else
299     local cpio=$(find_unpackable_file "$1")
300     unpack_banner "${cpio}"
301     "${cpio_cmd[@]}" <"${cpio}"
302     fi
303     }
304    
305 hasufell 1.12 # @FUNCTION: unpack_zip
306     # @USAGE: <zip file>
307     # @DESCRIPTION:
308     # Unpack zip archives.
309     # This function ignores all non-fatal errors (i.e. warnings).
310     # That is useful for zip archives with extra crap attached
311     # (e.g. self-extracting archives).
312     unpack_zip() {
313     [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
314    
315     local zip=$(find_unpackable_file "$1")
316     unpack_banner "${zip}"
317     unzip -qo "${zip}"
318    
319     [[ $? -le 1 ]] || die "unpacking ${zip} failed (arch=unpack_zip)"
320     }
321    
322 vapier 1.1 # @FUNCTION: _unpacker
323     # @USAGE: <one archive to unpack>
324     # @INTERNAL
325     # @DESCRIPTION:
326     # Unpack the specified archive. We only operate on one archive here
327     # to keep down on the looping logic (that is handled by `unpacker`).
328     _unpacker() {
329     [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
330    
331     local a=$1
332     local m=$(echo "${a}" | tr '[:upper:]' '[:lower:]')
333     a=$(find_unpackable_file "${a}")
334    
335     # first figure out the decompression method
336     case ${m} in
337     *.bz2|*.tbz|*.tbz2)
338 vapier 1.8 local bzcmd=${PORTAGE_BZIP2_COMMAND:-$(type -P pbzip2 || type -P bzip2)}
339     local bzuncmd=${PORTAGE_BUNZIP2_COMMAND:-${bzcmd} -d}
340 vapier 1.1 : ${UNPACKER_BZ2:=${bzuncmd}}
341     comp="${UNPACKER_BZ2} -c"
342     ;;
343     *.z|*.gz|*.tgz)
344     comp="gzip -dc" ;;
345     *.lzma|*.xz|*.txz)
346     comp="xz -dc" ;;
347     *) comp="" ;;
348     esac
349    
350     # then figure out if there are any archiving aspects
351 vapier 1.5 arch=""
352 vapier 1.1 case ${m} in
353     *.tgz|*.tbz|*.tbz2|*.txz|*.tar.*|*.tar)
354     arch="tar --no-same-owner -xof" ;;
355 ottxor 1.10 *.cpio.*|*.cpio)
356     arch="unpack_cpio" ;;
357 vapier 1.1 *.deb)
358     arch="unpack_deb" ;;
359     *.run)
360     arch="unpack_makeself" ;;
361 vapier 1.9 *.sh)
362     # Not all shell scripts are makeself
363     if head -n 30 "${a}" | grep -qs '#.*Makeself' ; then
364     arch="unpack_makeself"
365     fi
366     ;;
367 vapier 1.5 *.bin)
368     # Makeself archives can be annoyingly named
369     if head -c 100 "${a}" | grep -qs '#.*Makeself' ; then
370     arch="unpack_makeself"
371     fi
372     ;;
373 hasufell 1.12 *.zip)
374     arch="unpack_zip" ;;
375 vapier 1.1 esac
376    
377     # finally do the unpack
378     if [[ -z ${arch}${comp} ]] ; then
379 vapier 1.3 unpack "$1"
380 vapier 1.1 return $?
381     fi
382    
383     [[ ${arch} != unpack_* ]] && unpack_banner "${a}"
384    
385     if [[ -z ${arch} ]] ; then
386 vapier 1.6 # Need to decompress the file into $PWD #408801
387     local _a=${a%.*}
388     ${comp} "${a}" > "${_a##*/}"
389 vapier 1.1 elif [[ -z ${comp} ]] ; then
390     ${arch} "${a}"
391     else
392     ${comp} "${a}" | ${arch} -
393     fi
394    
395     assert "unpacking ${a} failed (comp=${comp} arch=${arch})"
396     }
397    
398     # @FUNCTION: unpacker
399     # @USAGE: [archives to unpack]
400     # @DESCRIPTION:
401     # This works in the same way that `unpack` does. If you don't specify
402     # any files, it will default to ${A}.
403     unpacker() {
404     local a
405     [[ $# -eq 0 ]] && set -- ${A}
406     for a ; do _unpacker "${a}" ; done
407     }
408    
409     # @FUNCTION: unpacker_src_unpack
410     # @DESCRIPTION:
411     # Run `unpacker` to unpack all our stuff.
412     unpacker_src_unpack() {
413     unpacker
414     }
415    
416     # @FUNCTION: unpacker_src_uri_depends
417     # @USAGE: [archives that we will unpack]
418     # @RETURN: Dependencies needed to unpack all the archives
419     # @DESCRIPTION:
420     # Walk all the specified files (defaults to $SRC_URI) and figure out the
421     # dependencies that are needed to unpack things.
422     #
423     # Note: USE flags are not yet handled.
424     unpacker_src_uri_depends() {
425     local uri deps d
426    
427     [[ $# -eq 0 ]] && set -- ${SRC_URI}
428    
429     for uri in "$@" ; do
430     case ${uri} in
431 ottxor 1.10 *.cpio.*|*.cpio)
432     d="app-arch/cpio" ;;
433 vapier 1.1 *.rar|*.RAR)
434     d="app-arch/unrar" ;;
435     *.7z)
436     d="app-arch/p7zip" ;;
437     *.xz)
438     d="app-arch/xz-utils" ;;
439 hasufell 1.12 *.zip)
440     d="app-arch/unzip" ;;
441 vapier 1.1 esac
442     deps+=" ${d}"
443     done
444    
445     echo "${deps}"
446     }
447    
448     EXPORT_FUNCTIONS src_unpack
449    
450     fi

  ViewVC Help
Powered by ViewVC 1.1.20