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

Contents of /eclass/unpacker.eclass

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.17 - (hide annotations) (download)
Thu May 1 19:27:14 2014 UTC (5 months, 3 weeks ago) by ottxor
Branch: MAIN
Changes since 1.16: +4 -4 lines
add app-arch/plzip support (bug #509264)

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

  ViewVC Help
Powered by ViewVC 1.1.20