1 # Copyright 1999-2017 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
4 # @ECLASS: unpacker.eclass
6 # base-system@gentoo.org
7 # @BLURB: helpers for extraneous file formats and consistent behavior across EAPIs
9 # Some extraneous file formats are not part of PMS, or are only in certain
10 # EAPIs. Rather than worrying about that, support the crazy cruft here
11 # and for all EAPI versions.
14 # - merge rpm unpacking
15 # - support partial unpacks?
17 if [[ -z ${_UNPACKER_ECLASS} ]]; then
20 # @ECLASS-VARIABLE: UNPACKER_BZ2
23 # Utility to use to decompress bzip2 files. Will dynamically pick between
24 # `pbzip2` and `bzip2`. Make sure your choice accepts the "-dc" options.
25 # Note: this is meant for users to set, not ebuilds.
27 # @ECLASS-VARIABLE: UNPACKER_LZIP
30 # Utility to use to decompress lzip files. Will dynamically pick between
31 # `plzip`, `pdlzip` and `lzip`. Make sure your choice accepts the "-dc" options.
32 # Note: this is meant for users to set, not ebuilds.
34 # for internal use only (unpack_pdv and unpack_makeself)
35 find_unpackable_file() {
37 if [[ -z ${src} ]] ; then
40 if [[ ${src} == ./* ]] ; then
41 : # already what we want
42 elif [[ -e ${DISTDIR}/${src} ]] ; then
44 elif [[ -e ${PWD}/${src} ]] ; then
46 elif [[ -e ${src} ]] ; then
50 [[ ! -e ${src} ]] && return 1
55 echo ">>> Unpacking ${1##*/} to ${PWD}"
58 # @FUNCTION: unpack_pdv
59 # @USAGE: <file to unpack> <size of off_t>
61 # Unpack those pesky pdv generated files ...
62 # They're self-unpacking programs with the binary package stuffed in
63 # the middle of the archive. Valve seems to use it a lot ... too bad
64 # it seems to like to segfault a lot :(. So lets take it apart ourselves.
66 # You have to specify the off_t size ... I have no idea how to extract that
67 # information out of the binary executable myself. Basically you pass in
68 # the size of the off_t type (in bytes) on the machine that built the pdv
71 # One way to determine this is by running the following commands:
74 # strings <pdv archive> | grep lseek
75 # strace -elseek <pdv archive>
78 # Basically look for the first lseek command (we do the strings/grep because
79 # sometimes the function call is _llseek or something) and steal the 2nd
80 # parameter. Here is an example:
83 # $ strings hldsupdatetool.bin | grep lseek
85 # $ strace -elseek ./hldsupdatetool.bin
86 # lseek(3, -4, SEEK_END) = 2981250
89 # Thus we would pass in the value of '4' as the second parameter.
91 local src=$(find_unpackable_file "$1")
94 [[ -z ${src} ]] && die "Could not locate source for '$1'"
95 [[ -z ${sizeoff_t} ]] && die "No idea what off_t size was used for this pdv :("
97 unpack_banner "${src}"
99 local metaskip=$(tail -c ${sizeoff_t} "${src}" | hexdump -e \"%i\")
100 local tailskip=$(tail -c $((${sizeoff_t}*2)) "${src}" | head -c ${sizeoff_t} | hexdump -e \"%i\")
102 # grab metadata for debug reasons
103 local metafile="${T}/${FUNCNAME}.meta"
104 tail -c +$((${metaskip}+1)) "${src}" > "${metafile}"
106 # rip out the final file name from the metadata
107 local datafile=$(tail -c +$((${metaskip}+1)) "${src}" | strings | head -n 1)
108 datafile=$(basename "${datafile}")
110 # now lets uncompress/untar the file if need be
111 local tmpfile="${T}/${FUNCNAME}"
112 tail -c +$((${tailskip}+1)) ${src} 2>/dev/null | head -c 512 > "${tmpfile}"
114 local iscompressed=$(file -b "${tmpfile}")
115 if [[ ${iscompressed:0:8} == "compress" ]] ; then
122 local istar=$(file -b "${tmpfile}")
123 if [[ ${istar:0:9} == "POSIX tar" ]] ; then
129 #for some reason gzip dies with this ... dd cant provide buffer fast enough ?
130 #dd if=${src} ibs=${metaskip} count=1 \
131 # | dd ibs=${tailskip} skip=1 \
134 if [ ${iscompressed} -eq 1 ] ; then
135 if [ ${istar} -eq 1 ] ; then
136 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
137 | head -c $((${metaskip}-${tailskip})) \
140 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
141 | head -c $((${metaskip}-${tailskip})) \
146 if [ ${istar} -eq 1 ] ; then
147 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
148 | head -c $((${metaskip}-${tailskip})) \
149 | tar --no-same-owner -xf -
151 tail -c +$((${tailskip}+1)) "${src}" 2>/dev/null \
152 | head -c $((${metaskip}-${tailskip})) \
157 #[ -s "${datafile}" ] || die "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')"
158 #assert "failure unpacking pdv ('${metaskip}' '${tailskip}' '${datafile}')"
161 # @FUNCTION: unpack_makeself
162 # @USAGE: [file to unpack] [offset] [tail|dd]
164 # Unpack those pesky makeself generated files ...
165 # They're shell scripts with the binary package tagged onto
166 # the end of the archive. Loki utilized the format as does
167 # many other game companies.
169 # If the file is not specified, then ${A} is used. If the
170 # offset is not specified then we will attempt to extract
171 # the proper offset from the script itself.
173 local src_input=${1:-${A}}
174 local src=$(find_unpackable_file "${src_input}")
178 [[ -z ${src} ]] && die "Could not locate source for '${src_input}'"
180 unpack_banner "${src}"
182 if [[ -z ${skip} ]] ; then
183 local ver=$(grep -m1 -a '#.*Makeself' "${src}" | awk '{print $NF}')
187 1.5.*|1.6.0-nv*) # tested 1.5.{3,4,5} ... guessing 1.5.x series is same
188 skip=$(grep -a ^skip= "${src}" | cut -d= -f2)
191 skip=$(grep -a ^$'\t'tail "${src}" | awk '{print $2}' | cut -b2-)
194 skip=$(grep -a ^offset= "${src}" | awk '{print $2}' | cut -b2-)
198 skip=$(grep -a ^offset= "${src}" | awk '{print $3}' | head -n 1)
202 skip=`grep -a ^offset= "${src}" | awk '{print $3}'`
205 2.1.4|2.1.5|2.1.6|2.2.0|2.4.0)
206 skip=$(grep -a offset=.*head.*wc "${src}" | awk '{print $3}' | head -n 1)
207 skip=$(head -n ${skip} "${src}" | wc -c)
211 eerror "I'm sorry, but I was unable to support the Makeself file."
212 eerror "The version I detected was '${ver}'."
213 eerror "Please file a bug about the file ${src##*/} at"
214 eerror "https://bugs.gentoo.org/ so that support can be added."
215 die "makeself version '${ver}' not supported"
218 debug-print "Detected Makeself version ${ver} ... using ${skip} as offset"
221 tail) exe=( tail -n +${skip} "${src}" );;
222 dd) exe=( dd ibs=${skip} skip=1 if="${src}" );;
223 *) die "makeself cant handle exe '${exe}'"
226 # lets grab the first few bytes of the file to figure out what kind of archive it is
227 local filetype tmpfile="${T}/${FUNCNAME}"
228 "${exe[@]}" 2>/dev/null | head -c 512 > "${tmpfile}"
229 filetype=$(file -b "${tmpfile}") || die
232 "${exe[@]}" | tar --no-same-owner -xf -
235 "${exe[@]}" | bzip2 -dc | tar --no-same-owner -xf -
238 "${exe[@]}" | tar --no-same-owner -xzf -
241 "${exe[@]}" | gunzip | tar --no-same-owner -xf -
244 "${exe[@]}" | unxz | tar --no-same-owner -xf -
247 eerror "Unknown filetype \"${filetype}\" ?"
251 assert "failure unpacking (${filetype}) makeself ${src##*/} ('${ver}' +${skip})"
254 # @FUNCTION: unpack_deb
255 # @USAGE: <one deb to unpack>
257 # Unpack a Debian .deb archive in style.
259 [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
261 local deb=$(find_unpackable_file "$1")
263 unpack_banner "${deb}"
265 # on AIX ar doesn't work out as their ar used a different format
266 # from what GNU ar (and thus what .deb files) produce
267 if [[ -n ${EPREFIX} ]] ; then
270 [[ ${REPLY} = "!<arch>" ]] || die "${deb} does not seem to be a deb archive"
271 local f timestamp uid gid mode size magic
272 while read f timestamp uid gid mode size magic ; do
273 [[ -n ${f} && -n ${size} ]] || continue # ignore empty lines
274 if [[ ${f} = "data.tar"* ]] ; then
275 head -c "${size}" > "${f}"
277 head -c "${size}" > /dev/null # trash it
287 # Clean things up #458658. No one seems to actually care about
288 # these, so wait until someone requests to do something else ...
289 rm -f debian-binary {control,data}.tar*
292 # @FUNCTION: unpack_cpio
293 # @USAGE: <one cpio to unpack>
295 # Unpack a cpio archive, file "-" means stdin.
297 [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
299 # needed as cpio always reads from stdin
300 local cpio_cmd=( cpio --make-directories --extract --preserve-modification-time )
301 if [[ $1 == "-" ]] ; then
302 unpack_banner "stdin"
305 local cpio=$(find_unpackable_file "$1")
306 unpack_banner "${cpio}"
307 "${cpio_cmd[@]}" <"${cpio}"
311 # @FUNCTION: unpack_zip
314 # Unpack zip archives.
315 # This function ignores all non-fatal errors (i.e. warnings).
316 # That is useful for zip archives with extra crap attached
317 # (e.g. self-extracting archives).
319 [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
321 local zip=$(find_unpackable_file "$1")
322 unpack_banner "${zip}"
325 [[ $? -le 1 ]] || die "unpacking ${zip} failed (arch=unpack_zip)"
328 # @FUNCTION: _unpacker
329 # @USAGE: <one archive to unpack>
332 # Unpack the specified archive. We only operate on one archive here
333 # to keep down on the looping logic (that is handled by `unpacker`).
335 [[ $# -eq 1 ]] || die "Usage: ${FUNCNAME} <file>"
338 local m=$(echo "${a}" | tr '[:upper:]' '[:lower:]')
339 a=$(find_unpackable_file "${a}")
341 # first figure out the decompression method
345 local bzcmd=${PORTAGE_BZIP2_COMMAND:-$(type -P pbzip2 || type -P bzip2)}
346 local bzuncmd=${PORTAGE_BUNZIP2_COMMAND:-${bzcmd} -d}
347 : ${UNPACKER_BZ2:=${bzuncmd}}
348 comp="${UNPACKER_BZ2} -c"
355 : ${UNPACKER_LZIP:=$(type -P plzip || type -P pdlzip || type -P lzip)}
356 comp="${UNPACKER_LZIP} -dc" ;;
359 # then figure out if there are any archiving aspects
362 *.tgz|*.tbz|*.tbz2|*.txz|*.tar.*|*.tar)
363 arch="tar --no-same-owner -xof" ;;
365 arch="unpack_cpio" ;;
369 arch="unpack_makeself" ;;
371 # Not all shell scripts are makeself
372 if head -n 30 "${a}" | grep -qs '#.*Makeself' ; then
373 arch="unpack_makeself"
377 # Makeself archives can be annoyingly named
378 if head -c 100 "${a}" | grep -qs '#.*Makeself' ; then
379 arch="unpack_makeself"
386 # finally do the unpack
387 if [[ -z ${arch}${comp} ]] ; then
392 [[ ${arch} != unpack_* ]] && unpack_banner "${a}"
394 if [[ -z ${arch} ]] ; then
395 # Need to decompress the file into $PWD #408801
397 ${comp} "${a}" > "${_a##*/}"
398 elif [[ -z ${comp} ]] ; then
401 ${comp} "${a}" | ${arch} -
404 assert "unpacking ${a} failed (comp=${comp} arch=${arch})"
407 # @FUNCTION: unpacker
408 # @USAGE: [archives to unpack]
410 # This works in the same way that `unpack` does. If you don't specify
411 # any files, it will default to ${A}.
414 [[ $# -eq 0 ]] && set -- ${A}
415 for a ; do _unpacker "${a}" ; done
418 # @FUNCTION: unpacker_src_unpack
420 # Run `unpacker` to unpack all our stuff.
421 unpacker_src_unpack() {
425 # @FUNCTION: unpacker_src_uri_depends
426 # @USAGE: [archives that we will unpack]
427 # @RETURN: Dependencies needed to unpack all the archives
429 # Walk all the specified files (defaults to $SRC_URI) and figure out the
430 # dependencies that are needed to unpack things.
432 # Note: USE flags are not yet handled.
433 unpacker_src_uri_depends() {
436 if [[ $# -eq 0 ]] ; then
437 # Disable path expansion for USE conditionals. #654960
448 # platforms like AIX don't have a good ar
449 d="kernel_AIX? ( app-arch/deb2targz )" ;;
451 d="app-arch/unrar" ;;
453 d="app-arch/p7zip" ;;
455 d="app-arch/xz-utils" ;;
457 d="app-arch/unzip" ;;
459 d="|| ( app-arch/plzip app-arch/pdlzip app-arch/lzip )" ;;
467 EXPORT_FUNCTIONS src_unpack