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