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