Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
inspect jar and war files, Grails applications and plugins
#!/bin/sh
# needs bash >= 3.2 for regex
jarfile=
file=
fileList=
verbose=0
extract=0
list=0
listFilter=
manifestHeaders=
# check whether zipinfo is available
which zipinfo >/dev/null 2>&1
zipInfoAvailable=$?
ALL_HEADERS="--all--"
options="hHvxXoawmISMWjJrgGcCpPlLdD:"
function usage() {
echo "jinspect [-$options] jarfile [filename ...]"
cat <<EOU
Options:
-h show help
-v be more verbose
-X save specified files (including path) to the current directory instead of printing them
-l list war contents; specify again to include more information
-x list xml files
-o list properties files
-c list class files
-j list java files
-J list jsp files
-S list js files
-g list groovy files
-G list gsp files
-H list html files
-C list css files
-I list image files
-L list files in lib directory
-M list files in META-INF directory
-W list files in WEB-INF directory
-a show WEB-INF/applicationContext.xml
-w show WEB-INF/web.xml
-r show WEB-INF/grails.xml
-m show META-INF/MANIFEST.MF
-p show plugin.xml
-P show *GrailsPlugin.groovy
-d show manifest headers in nicely formatted way; implies -m
-D <name> display named manifest header; can be used multiple times, implies -m
EOU
}
function addFilter() {
local expr=$1
if [ "$list" -eq 0 ]; then
list=$((list + 1))
fi
if [ -n "$listFilter" ]; then
listFilter="$listFilter|$expr"
else
listFilter="$expr"
fi
}
function addFile() {
local file=$1
# skip duplicates
for existingFile in $fileList; do
if [ "$file" = "$existingFile" ]; then
return 1
fi
done
if [ -n "$fileList" ]; then
fileList="$fileList $file"
else
fileList="$file"
fi
}
function addManifestHeader() {
local header="$1"
if [ -n "$manifestHeaders" ]; then
manifestHeaders="$manifestHeaders $header"
else
manifestHeaders="$header"
fi
addFile "META-INF/MANIFEST.MF"
}
function displayManifestHeader() {
awk ' BEGIN { ORS=""; indent=" "; headerCount=0 }; {
pos=index($0, ":")
if (pos > 0) {
# split name from contents
name=substr($0, 1, pos - 1)
contents=substr($0, pos + 1, length($0))
# remove leading and trailing whitespace
sub(/^[ \t]+/, "", contents)
sub(/[ \t]+$/, "", contents)
# header name
if (headerCount > 0) {
print "\n"
}
print name "\n"
headerCount++
# iterate over contents, which is separated by ','
# NOTE: some quoted parts may contain ',' as well, e.g. in version range
inQuotes=0
newPart=1
# for each character
count = split(contents, parts, "")
for (p=1; p <= count; p++) {
# new part
if (newPart > 0) {
newPart=0
print indent
}
# quote character
if (parts[p] == "\"") {
if (inQuotes > 0) {
inQuotes=0
}
else {
inQuotes=1
}
print parts[p]
}
# comma, which is a spearator, when not within quotes
else if (parts[p] == ",") {
if (inQuotes) {
print parts[p]
}
else {
print "\n"
newPart=1
}
}
# any other character
else {
print parts[p]
}
}
}
else {
print $0
}
}; END { print "\n" }'
}
function showManifestHeaders() {
local jarfile=$1
shift
# extract MANIFEST.MF, remove \r and rejoin wrapped lines
local manifestHeaders=`
unzip -p "$jarfile" "META-INF/MANIFEST.MF" | tr -d '\r' |
awk '
BEGIN { ORS="" }
/^[^ ]/{
if ( NR > 1) {
print "\n"
}
# remove trailing whitespace
sub(/[ \t]+$/, "", $0)
print $0
}
/^[ ]/{
# remove leading whitespace
sub(/^[ \t]+/, "", $0)
print $0
}
END { print "\n"; }'`
# print wanted headers
for header in $@; do
if [ "$header" = "$ALL_HEADERS" ]; then
echo "$manifestHeaders" | displayManifestHeader
else
echo "$manifestHeaders" | grep "$header" | displayManifestHeader
fi
done
}
# parse options
while getopts "$options" OPT $@; do
case "$OPT" in
h) usage; exit 0 ;;
v) verbose=$((verbose + 1));;
l) list=$((list + 1));;
x) addFilter '\.xml';;
X) extract=1;;
o) addFilter '\.properties';;
c) addFilter '\.class';;
C) addFilter '\.css';;
j) addFilter '\.java';;
J) addFilter '\.jsp';;
S) addFilter '\.js';;
g) addFilter '\.groovy';;
G) addFilter '\.gsp';;
H) addFilter '\.html';;
I) addFilter '\.jpg'; addFilter '\.png'; addFilter '\.gif'; addFilter '\.ico'; addFilter '\.bmp';;
M) addFilter 'META-INF/';;
W) addFilter 'WEB-INF/';;
L) addFilter 'lib/';;
m) addFile "META-INF/MANIFEST.MF";;
a) addFile "WEB-INF/applicationContext.xml";;
w) addFile "WEB-INF/web.xml";;
r) addFile "WEB-INF/grails.xml";;
p) addFile "*plugin.xml";;
P) addFile "*GrailsPlugin.groovy";;
d) addManifestHeader "$ALL_HEADERS";;
D) addManifestHeader "$OPTARG";;
esac
done
optind=$OPTIND
unset OPTIND
if [ "$optind" -gt 0 ]; then
# remove options
shift $((optind - 1))
fi
jarfile="$1"
if [ ! -e "$jarfile" ]; then
echo >&2 "no such file: $jarfile"
exit 1
fi
shift
for file in "$@"; do
addFile "$file"
done
if [ -n "$2" ]; then
# use file name provided on command line
file=$2
fi
if [ -n "$fileList" ]; then
index=0
if [ "$verbose" -gt 0 ]; then
echo "=== extracting $fileList from $jarfile"
fi
for file in $fileList; do
if [ "$verbose" -gt 0 ]; then
if [ "$index" -gt 0 ]; then
echo ""
fi
echo "=== $jarfile:$file"
fi
if [ "$extract" -gt 0 ]; then
unzip "$jarfile" "$file"
elif [[ "$file" =~ \.xml$ ]]; then
# xml file, prettify
unzip -p "$jarfile" "$file" | xmllint --format --recover --nowarning -
elif [ "$file" = "META-INF/MANIFEST.MF" -a -n "$manifestHeaders" ]; then
showManifestHeaders "$jarfile" $manifestHeaders
else
unzip -p "$jarfile" "$file"
fi
index=$((index + 1))
done
else
# no file specified, list contents
if [ "$list" -eq 0 ]; then
list=$((list + 1))
fi
fi
if [ "$list" -gt 0 ]; then
if [ "$verbose" -gt 0 ]; then
if [ -n "$listFilter" ]; then
# remove regex escapes
displayFilter=`echo "$listFilter" | sed 's/\\\\//g'`
echo "=== listing contents of $jarfile: $displayFilter"
else
echo "=== listing contents of $jarfile"
fi
fi
listing=
# use unzip -l if long listing is wanted or zip info is not available
if [ "$list" -gt 1 -o "$zipInfoAvailable" -gt 0 ]; then
listing=`unzip -l "$jarfile"`
else
listing=`zipinfo -1 "$jarfile"`
fi
if [ -n "$listing" ]; then
if [ -n "$listFilter" ]; then
echo "$listing" | grep -E $listFilter
else
echo "$listing"
fi
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment