1#!/bin/sh -
2#
3# $NetBSD: gzexe,v 1.3 2004/05/01 08:22:41 wiz Exp $
4# $OpenBSD: gzexe,v 1.3 2003/08/05 18:22:17 deraadt Exp $
5#
6#-
7#  Copyright (c) 2003 Otto Moerbeek <otto@drijf.net>
8#
9#  Permission to use, copy, modify, and distribute this software for any
10#  purpose with or without fee is hereby granted, provided that the above
11#  copyright notice and this permission notice appear in all copies.
12#
13#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20#
21# $FreeBSD$
22
23# The number of lines plus one in the on-the-fly decompression script
24lines=19
25
26# A simple string to recognize already compressed files
27magic="# compressed by gzexe"
28
29# Write the decompression script to stdout
30header () {
31	# first section needs variable expansion, second not
32	cat <<- EOF
33		#!/bin/sh -
34		$magic
35		lines=$lines
36	EOF
37	cat <<- 'EOF'
38		prog=`/usr/bin/basename "$0"`
39		tmp=`/usr/bin/mktemp -d /tmp/gzexeXXXXXXXXXX` || {
40			/bin/echo "$prog: cannot create tmp dir"; exit 1
41		}
42		trap '/bin/rm -rf "$tmp"' 0
43		if /usr/bin/tail +$lines "$0" |
44		    /usr/bin/gzip -dc > "$tmp/$prog" 2> /dev/null; then
45			/bin/chmod u+x "$tmp/$prog"
46			"$tmp/$prog" ${1+"$@"}
47			ret=$?
48		else
49			/bin/echo "$prog: cannot decompress $0"
50			ret=1
51		fi
52		exit $ret
53	EOF
54}
55
56# Test if a file is compressed by checking the magic line
57compressed () {
58	test "X`sed -n 2p "$1" 2> /dev/null`" = "X$magic"
59}
60
61# Decompress a file
62decompress () {
63	tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
64		echo "$prog: cannot create tmp file"
65		return 1
66	}
67	if ! cp "$1" "$tmp"; then
68		echo "$prog: cannot copy $1 to $tmp"
69		rm -f "$tmp"
70		return 1
71	fi
72	if ! tail +$lines "$tmp" | gzip -vdc > "$1"; then
73		echo "$prog: cannot decompress $1"
74		cp "$tmp" "$1"
75		rm -f "$tmp"
76		return 1
77	fi
78}
79
80# Perform some sanity checks on the file
81check () {
82	if test ! -e "$1"; then
83		echo "$prog: cannot compress non-existing file $1"
84		return 1
85	fi
86
87	if test ! -f "$1"; then
88		echo "$prog: cannot compress non-regular file $1"
89		return 1
90	fi
91
92	case `basename "$1"` in
93		sh | mktemp | rm | echo | tail | gzip | chmod)
94			echo "$prog: cannot compress $1, I depend on it"
95			return 1
96	esac
97
98	if test ! -x "$1"; then
99		echo "$prog: cannot compress $1, it is not executable"
100		return 1
101	fi
102
103	if test -u "$1" -o -g "$1"; then
104		echo "$prog: cannot compress $1, it has an s bit set"
105		return 1
106	fi
107}
108
109# Compress a file
110compress () {
111	tmp=`mktemp /tmp/gzexeXXXXXXXXXX` || {
112		echo "$prog: cannot create tmp file"
113		return 1
114	}
115	if ! cp "$1" "$tmp"; then
116		echo "$prog: cannot copy $1 to $tmp"
117		rm -f "$tmp"
118		return 1
119	fi
120	if ! cp "$1" "$1"~; then
121		echo "$prog: cannot create backup copy $1~"
122		rm -f "$1"~ "$tmp"
123		return 1
124	fi
125
126	# Use cp to overwrite the existing file preserving mode and owner
127	# if possible. If the file is not writable, this will produce an
128	# error.
129
130	if header "$1" > "$tmp" && gzip -vc "$1" >> "$tmp"; then
131		if ! cp "$tmp" "$1"; then
132			echo "$prog: cannot copy $tmp to $1"
133			rm -f "$tmp"
134			return 1
135		fi
136	else
137		echo "$prog: cannot compress $1"
138		rm -f "$1"~ "$tmp"
139		return 1
140	fi
141}
142
143# Is the -d flag specified?
144dflag=
145
146# Return value
147rc=0
148
149if test "X$1" = X-d; then
150	dflag=1
151	shift
152fi
153
154prog=`basename "$0"`
155USAGE="usage: $prog [-d] file ..."
156if test $# -eq 0; then
157	echo $USAGE
158	exit 1
159fi
160
161while test $# -ne 0; do
162	if test $dflag; then
163		if ! compressed "$1"; then
164			echo "$prog: $1 is not compressed"
165			rc=1;
166		elif ! decompress "$1"; then
167			rc=$?
168		fi
169	else
170		if compressed "$1"; then
171			echo "$prog: $1 is already compressed"
172			rc=1;
173		elif ! check "$1" || ! compress "$1"; then
174			rc=$?
175		fi
176	fi
177	shift
178done
179exit $rc
180