#!/bin/sh -
#
# $OpenBSD: gzexe,v 1.4 2005/09/30 06:50:44 otto Exp $
#
#  Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
#
#  Permission to use, copy, modify, and distribute this software for any
#  purpose with or without fee is hereby granted, provided that the above
#  copyright notice and this permission notice appear in all copies.
#
#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#

# The number of lines plus one in the on-the-fly decompression script
lines=19

# A simple string to recognize already compressed files
magic="# compressed by gzexe"

# Write the decompression script to stdout
header () {
	typeset prog tmp
	# first section needs variable expansion, second not
	cat <<- EOF
		#!/bin/sh -
		$magic
		lines=$lines
	EOF
	cat <<- 'EOF'
		prog=`/usr/bin/basename "$0"`
		tmp=`/usr/bin/mktemp -d /tmp/gzexeXXXXXXXXXX` || {
			/bin/echo "$prog: cannot create tmp dir"; exit 1
		}
		trap '/bin/rm -rf "$tmp"' 0
		if /usr/bin/tail +$lines "$0" |
		    /usr/bin/gzip -dc > "$tmp/$prog" 2> /dev/null; then
			/bin/chmod u+x "$tmp/$prog"
			"$tmp/$prog" ${1+"$@"}
			ret=$?
		else
			/bin/echo "$prog: cannot decompress $0"
			ret=1
		fi
		exit $ret
	EOF
}

# Test if a file is compressed by checking the magic line
compressed () {
	test "X`sed -n 2p "$1" 2> /dev/null`" = "X$magic"
}

# Decompress a file
decompress () {
	tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
		echo "$prog: cannot create tmp file"
		return 1
	}
	if ! cp "$1" "$tmp"; then
		echo "$prog: cannot copy $1 to $tmp"
		rm -f "$tmp"
		return 1
	fi
	if ! tail +$lines "$tmp" | gzip -vdc > "$1"; then
		echo "$prog: cannot decompress $1"
		cp "$tmp" "$1"
		rm -f "$tmp"
		return 1
	fi
}

# Perform some sanity checks on the file
check () {
	if test ! -e "$1"; then
		echo "$prog: cannot compress non-existing file $1"
		return 1
	fi

	if test ! -f "$1"; then
		echo "$prog: cannot compress non-regular file $1"
		return 1
	fi

	case `basename "$1"` in
		sh | mktemp | rm | echo | tail | gzip | chmod | basename)
			echo "$prog: cannot compress $1, I depend on it"
			return 1
	esac

	if test ! -x "$1"; then
		echo "$prog: cannot compress $1, it is not executable"
		return 1
	fi

	if test -u "$1" -o -g "$1"; then
		echo "$prog: cannot compress $1, it has an s bit set"
		return 1
	fi

	# Build a list of files we should not compress.
	# * files we need to decompress
	CHECK_LIST="
	/bin/chmod
	/bin/echo
	/bin/sh
	/bin/rm
	/usr/bin/basename
	/usr/bin/gzip
	/usr/bin/mktemp
	/usr/bin/tail
	"
	# * files in /bin and /sbin (decompression fails if /usr/bin is not mounted)
	# (You could skip these if /usr/bin is always mounted on the same mount point.)
	CHECK_LIST="$CHECK_LIST
	/bin/*
	/sbin/*
	"
	# See if the program we are trying to compress is in the list.
	# To avoid compressing hardlinked files (eg compress & gzip)
	# we compare the device & inode.
	PROG_STAT_INFO=`stat -f '%d %i' "$1"`
	for CHECK in $CHECK_LIST; do
		if test -f "$CHECK"; then
			CHECK_STAT_INFO=`stat -f '%d %i' "$CHECK"`
			if test "X$PROG_STAT_INFO" == "X$CHECK_STAT_INFO"; then
				echo "$prog: cannot compress $1, it is the same file as $CHECK"
				return 1
			fi
		fi
	done
}

# Compress a file
compress () {
	tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
		echo "$prog: cannot create tmp file"
		return 1
	}
	if ! cp "$1" "$tmp"; then
		echo "$prog: cannot copy $1 to $tmp"
		rm -f "$tmp"
		return 1
	fi
	if ! cp "$1" "$1"~; then
		echo "$prog: cannot create backup copy $1~"
		rm -f "$1"~ "$tmp"
		return 1
	fi

	# Use cp to overwrite the existing file preserving mode and owner
	# if possible. If the file is not writable, this will produce an
	# error.

	if header "$1" > "$tmp" && gzip -vc "$1" >> "$tmp"; then
		if ! cp "$tmp" "$1"; then
			echo "$prog: cannot copy $tmp to $1"
			rm -f "$tmp"
			return 1
		fi
	else
		echo "$prog: cannot compress $1"
		rm -f "$1"~ "$tmp"
		return 1
	fi
}

# Is the -d flag specified?
dflag=

# Return value
rc=0

if test "X$1" = X-d; then
	dflag=1
	shift
fi

prog=`basename "$0"`
USAGE="usage: $prog [-d] file ..."
if test $# -eq 0; then
	echo $USAGE
	exit 1
fi

while test $# -ne 0; do
	if test $dflag; then
		if ! compressed "$1"; then
			echo "$prog: $1 is not compressed"
			rc=1;
		elif ! decompress "$1"; then
			rc=$?
		fi
	else
		if compressed "$1"; then
			echo "$prog: $1 is already compressed"
			rc=1;
		elif ! check "$1" || ! compress "$1"; then
			rc=$?
		fi
	fi
	shift
done
exit $rc
