367 lines
9.5 KiB
Bash
Executable file
367 lines
9.5 KiB
Bash
Executable file
#!/bin/sh
|
|
#
|
|
# $NetBSD: extract,v 1.21 2022/01/06 10:30:50 schmonz Exp $
|
|
#
|
|
# Copyright (c) 2006 The NetBSD Foundation, Inc.
|
|
# All rights reserved.
|
|
#
|
|
# This code is derived from software contributed to The NetBSD Foundation
|
|
# by Johnny C. Lam.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
|
# ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
|
# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
######################################################################
|
|
#
|
|
# NAME
|
|
# extract -- extract distfile, regardless of format
|
|
#
|
|
# SYNOPSIS
|
|
# extract [options] distfile [file ...]
|
|
#
|
|
# DESCRIPTION
|
|
# extract will unpack the contents of the named distfile into the
|
|
# current working directory. If any optional files are specified then
|
|
# only they will be extracted from the distfile, provided that the
|
|
# underlying tool supports this ability. If the distfile's file
|
|
# extension doesn't match any known archive format's, then the
|
|
# distfile is simply copied into the current working directory. If
|
|
# "-" is given as the distfile, then standard input is used as the
|
|
# contents of the archive, provided that the underlying tool supports
|
|
# this ability.
|
|
#
|
|
# OPTIONS
|
|
# -c format Force interpretation of the distfile's compression
|
|
# format to be the specified format. Valid formats
|
|
# are: gzip, bzip, compress, and none.
|
|
#
|
|
# -d dir Extract the files into the specified dir instead
|
|
# of the current working directory. If the directory
|
|
# doesn't exist, then it is created along with any
|
|
# intermediate directories using the current umask.
|
|
#
|
|
# -f format Force interpretation of the distfile's archive
|
|
# format to be the specified format.
|
|
#
|
|
# -t tarprog This specifies the tool to use to extract tar/ustar
|
|
# archives, and may be either "tar" or "pax", or the
|
|
# full path to the program.
|
|
#
|
|
# -X excludefile excludefile is a list of file patterns to exclude
|
|
# from extraction. If the -X option is specified
|
|
# then any optional files listed on the command line
|
|
# are ignored.
|
|
#
|
|
# -x This causes the optional files listed on the
|
|
# command line to be excluded from extraction,
|
|
# provided the underlying tool supports this
|
|
# ability.
|
|
#
|
|
# ENVIRONMENT
|
|
# EXTRACT_OPTS_BIN
|
|
# EXTRACT_OPTS_LHA
|
|
# EXTRACT_OPTS_PAX
|
|
# EXTRACT_OPTS_RAR
|
|
# EXTRACT_OPTS_RPM
|
|
# EXTRACT_OPTS_TAR
|
|
# EXTRACT_OPTS_ZIP
|
|
# EXTRACT_OPTS_ZSTD
|
|
# EXTRACT_OPTS_ZOO
|
|
# These variables set additional arguments passed to the
|
|
# underlying extraction tool to unpack their respective
|
|
# archive formats.
|
|
#
|
|
######################################################################
|
|
|
|
set -e # exit on errors
|
|
set -u # treat undefined variables as errors
|
|
|
|
: ${BZCAT:=bzcat}
|
|
: ${CAT:=cat}
|
|
: ${CP:=cp}
|
|
: ${ECHO:=echo}
|
|
: ${GEM:="gem unpack"}
|
|
: ${GZCAT:="gzip -cd"}
|
|
: ${LHA:=lha}
|
|
: ${LZCAT:="lzip -cd"}
|
|
: ${MKDIR:=mkdir}
|
|
: ${PAX:=pax}
|
|
: ${RM:=rm}
|
|
: ${RPM2PKG:=rpm2pkg}
|
|
: ${SH:=sh}
|
|
: ${TAR:=tar}
|
|
: ${TEST:=test}
|
|
: ${UNRAR:=unrar}
|
|
: ${UNZIP_CMD:=unzip}
|
|
: ${UNZOO:=unzoo}
|
|
: ${P7ZA:="7za x"}
|
|
: ${P7ZA_SO:="7za x -so"}
|
|
: ${ZSTD:="zstd"}
|
|
|
|
: ${TMPDIR:=/tmp}
|
|
|
|
self="${0##*/}"
|
|
|
|
usage() {
|
|
${ECHO} 1>&2 "usage: $self [-c format] [-d dir] [-f format] [-t tarprog] [-X excludefile | -x] distfile [file ...]"
|
|
}
|
|
|
|
exclude=no
|
|
exclude_file=
|
|
exclude_flag=
|
|
extract_dir=.
|
|
extract_using=tar
|
|
format=
|
|
cformat=
|
|
|
|
# Process optional arguments
|
|
while ${TEST} $# -gt 0; do
|
|
case "$1" in
|
|
-c) cformat="$2"; shift 2 ;;
|
|
-d) extract_dir="$2"; shift 2 ;;
|
|
-f) format="$2"; shift 2 ;;
|
|
-t) extract_using="$2"; shift 2 ;;
|
|
-X) exclude_file="$2"; shift 2 ;;
|
|
-x) exclude=yes; shift ;;
|
|
--) shift; break ;;
|
|
-?*) ${ECHO} 1>&2 "$self: unknown option -- ${1#-}"
|
|
usage
|
|
exit 1
|
|
;;
|
|
*) break ;;
|
|
esac
|
|
done
|
|
|
|
case "$extract_using" in
|
|
/*tar|/*pax) tarprog="$extract_using" ;;
|
|
*tar) tarprog="${TAR}" ;;
|
|
*pax) tarprog="${PAX}" ;;
|
|
*) tarprog="${TAR}" ;;
|
|
esac
|
|
|
|
if ${TEST} -n "$exclude_file" -a ! -f "$exclude_file"; then
|
|
${ECHO} 1>&2 "$self: exclude file missing: $exclude_file"
|
|
exit 1
|
|
fi
|
|
|
|
# Process required arguments
|
|
${TEST} $# -gt 0 || { usage; exit 1; }
|
|
distfile="$1"; shift
|
|
|
|
# Make distfile an absolute path, because we will change the current
|
|
# directory soon.
|
|
case "$distfile" in
|
|
/*) ;;
|
|
*) distfile=`exec pwd`/"$distfile"
|
|
;;
|
|
esac
|
|
|
|
# Derive the compression format of the archive based on the file extension.
|
|
case "$distfile" in
|
|
*.gz|*.tgz|*.z|*.crate) _cformat=gzip ;;
|
|
*.7z) _cformat=7z ;;
|
|
*.bz2|*.tbz|*.tbz2|*.bz) _cformat=bzip ;;
|
|
*.lz) _cformat=lzip ;;
|
|
*.lzma) _cformat=lzma ;;
|
|
*.xz|*.txz) _cformat=xz ;;
|
|
*.Z) _cformat=compress ;;
|
|
*) _cformat=none ;;
|
|
esac
|
|
${TEST} -n "$cformat" || cformat="$_cformat"
|
|
|
|
# Derive the command to decompress the file and write the contents to
|
|
# stdout, based on the file extension.
|
|
#
|
|
case "$cformat" in
|
|
gzip|compress) decompress_cat="${GZCAT}" ;;
|
|
7z) decompress_cat="${P7ZA_SO}" ;;
|
|
bzip) decompress_cat="${BZCAT}" ;;
|
|
lzip) decompress_cat="${LZCAT}" ;;
|
|
lzma) decompress_cat="${XZCAT}" ;;
|
|
xz) decompress_cat="${XZCAT}" ;;
|
|
none) decompress_cat="${CAT}" ;;
|
|
*) decompress_cat="${CAT}" ;;
|
|
esac
|
|
|
|
# Derive the format of the archive based on the file extension.
|
|
case "$distfile" in
|
|
*.tar.gz|*.tgz|*-tar.gz|*_tar.gz|*.tar.bz2|*.txz|*.tbz|*.tbz2|*.tar.lz|*.tar.lzma|*.tar.xz|*.tar.Z|*.tar.z|*.tar|*.tar.bz|*.tar.7z|*.tar.zst|*.crate)
|
|
_format=tar ;;
|
|
*.cpio|*.cpio.gz|*.cpio.bz2)
|
|
_format=cpio ;;
|
|
*.shar.gz|*.shar.bz2|*.shar.Z|*.shar|*.shr.gz|*.shr.bz2|*.shr.Z|*.shr)
|
|
_format=shar ;;
|
|
*.zip|*.ZIP) _format=zip ;;
|
|
*.lha|*.lzh) _format=lha ;;
|
|
*.Z|*.bz2|*.gz|*.z)
|
|
_format=compressed ;;
|
|
*.zoo) _format=zoo ;;
|
|
*.rar) _format=rar ;;
|
|
*.rpm) _format=rpm ;;
|
|
*.bin|*.sh) _format=jre-bin ;;
|
|
*.gem) _format=gem ;;
|
|
*.7z) _format=7z ;;
|
|
*.zst) _format=zstd ;;
|
|
*) _format=none ;;
|
|
esac
|
|
${TEST} -n "$format" || format="$_format"
|
|
|
|
case "$format" in
|
|
tar|shar) ;;
|
|
*) if ${TEST} "$distfile" = "-"; then
|
|
${ECHO} 1>&2 "$self: archive format cannot be given on standard input -- $format"
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
${TEST} -d "$extract_dir" || ${MKDIR} -p "$extract_dir"
|
|
cd "$extract_dir"
|
|
|
|
# Use the correct tool and extraction procedure to perform the extraction
|
|
# based on the archive format.
|
|
#
|
|
case "$format" in
|
|
tar)
|
|
case "$extract_using" in
|
|
*pax)
|
|
: ${EXTRACT_OPTS_PAX=}
|
|
case "$extract_using" in
|
|
/*) paxprog="$extract_using" ;;
|
|
*) paxprog="${PAX}" ;;
|
|
esac
|
|
if ${TEST} -n "$exclude_file"; then
|
|
exclude=yes
|
|
set -- dummy `${CAT} "$exclude_file"`; shift
|
|
fi
|
|
${TEST} "$exclude" = no || exclude_flag="-c"
|
|
$decompress_cat "$distfile" |
|
|
$paxprog ${EXTRACT_OPTS_PAX} $exclude_flag -O -r ${1+"$@"}
|
|
;;
|
|
*tar)
|
|
: ${EXTRACT_OPTS_TAR=}
|
|
case "$extract_using" in
|
|
/*) tarprog="$extract_using" ;;
|
|
*) tarprog="${TAR}" ;;
|
|
esac
|
|
tmpfile=
|
|
if ${TEST} "$exclude" = "yes"; then
|
|
tmpfile="${TMPDIR}/$self.$$"
|
|
${RM} -f "$tmpfile"
|
|
trap "\${RM} -f \"\$tmpfile\"" 0
|
|
for i in ${1+"$@"}; do
|
|
${ECHO} "$i" >> "$tmpfile"
|
|
done
|
|
exclude_file="$tmpfile"
|
|
fi
|
|
if ${TEST} -n "$exclude_file"; then
|
|
exclude_flag="-X $exclude_file"
|
|
set -- dummy; shift
|
|
fi
|
|
$decompress_cat "$distfile" |
|
|
$tarprog ${EXTRACT_OPTS_TAR} $exclude_flag -xf - ${1+"$@"}
|
|
;;
|
|
*)
|
|
${ECHO} 1>&2 "$self: unknown tar program: $extract_using"
|
|
exit 1
|
|
esac
|
|
;;
|
|
|
|
cpio)
|
|
: ${EXTRACT_OPTS_PAX=}
|
|
if ${TEST} -n "$exclude_file"; then
|
|
exclude=yes
|
|
set -- dummy `${CAT} "$exclude_file"`; shift
|
|
fi
|
|
${TEST} "$exclude" = no || exclude_flag="-c"
|
|
$decompress_cat "$distfile" |
|
|
${PAX} ${EXTRACT_OPTS_PAX} $exclude_flag -r ${1+"$@"}
|
|
;;
|
|
|
|
shar)
|
|
$decompress_cat "$distfile" | ${SH}
|
|
;;
|
|
|
|
zip)
|
|
: ${EXTRACT_OPTS_ZIP=-aqo}
|
|
${TEST} "$exclude" = "no" || exclude_flag="-x"
|
|
if ${TEST} -n "$exclude_file"; then
|
|
set -- dummy `${CAT} "$exclude_file"`; shift
|
|
fi
|
|
${UNZIP_CMD} ${EXTRACT_OPTS_ZIP} "$distfile" $exclude_flag ${1+"$@"}
|
|
;;
|
|
|
|
lha)
|
|
: ${EXTRACT_OPTS_LHA=q}
|
|
${LHA} x${EXTRACT_OPTS_LHA} "$distfile" ${1+"$@"}
|
|
;;
|
|
|
|
compressed)
|
|
target="${distfile##*/}"; target="${target%.*}"
|
|
$decompress_cat "$distfile" > "$target"
|
|
;;
|
|
|
|
zoo)
|
|
: ${EXTRACT_OPTS_ZOO=}
|
|
${UNZOO} -x ${EXTRACT_OPTS_ZOO} "$distfile" ${1+"$@"}
|
|
;;
|
|
|
|
rar)
|
|
: ${EXTRACT_OPTS_RAR=-inul}
|
|
${UNRAR} x ${EXTRACT_OPTS_RAR} "$distfile" ${1+"$@"}
|
|
;;
|
|
|
|
rpm)
|
|
: ${EXTRACT_OPTS_RPM=}
|
|
${RPM2PKG} -d . ${EXTRACT_OPTS_RPM} "$distfile" ${1+"$@"}
|
|
;;
|
|
|
|
jre-bin)
|
|
: ${EXTRACT_OPTS_BIN=}
|
|
${ECHO} yes | "$distfile" ${EXTRACT_OPTS_BIN} >/dev/null
|
|
;;
|
|
|
|
gem)
|
|
${GEM} "$distfile"
|
|
;;
|
|
|
|
7z)
|
|
${P7ZA} "$distfile"
|
|
;;
|
|
|
|
zst)
|
|
: ${EXTRACT_OPTS_ZSTD=}
|
|
${ZSTD} -d ${EXTRACT_OPTS_ZSTD} "$distfile" ${1+"$@"}
|
|
;;
|
|
|
|
none)
|
|
# By default, copy the distfile over to the current working directory.
|
|
${CP} "$distfile" .
|
|
;;
|
|
|
|
*)
|
|
${ECHO} 1>&2 "$self: archive format not recognized -- $format"
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
exit 0
|