unpacker.eclass 13 KB

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