install-sh revision dcae5b9e
1dcae5b9eSmrg#!/bin/sh
2dcae5b9eSmrg#
3dcae5b9eSmrg# install - install a program, script, or datafile
4dcae5b9eSmrg#
5dcae5b9eSmrg# This originates from X11R5 (mit/util/scripts/install.sh), which was
6dcae5b9eSmrg# later released in X11R6 (xc/config/util/install.sh) with the
7dcae5b9eSmrg# following copyright and license.
8dcae5b9eSmrg#
9dcae5b9eSmrg# Copyright (C) 1994 X Consortium
10dcae5b9eSmrg#
11dcae5b9eSmrg# Permission is hereby granted, free of charge, to any person obtaining a copy
12dcae5b9eSmrg# of this software and associated documentation files (the "Software"), to
13dcae5b9eSmrg# deal in the Software without restriction, including without limitation the
14dcae5b9eSmrg# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
15dcae5b9eSmrg# sell copies of the Software, and to permit persons to whom the Software is
16dcae5b9eSmrg# furnished to do so, subject to the following conditions:
17dcae5b9eSmrg#
18dcae5b9eSmrg# The above copyright notice and this permission notice shall be included in
19dcae5b9eSmrg# all copies or substantial portions of the Software.
20dcae5b9eSmrg#
21dcae5b9eSmrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22dcae5b9eSmrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23dcae5b9eSmrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24dcae5b9eSmrg# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
25dcae5b9eSmrg# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
26dcae5b9eSmrg# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27dcae5b9eSmrg#
28dcae5b9eSmrg# Except as contained in this notice, the name of the X Consortium shall not
29dcae5b9eSmrg# be used in advertising or otherwise to promote the sale, use or other deal-
30dcae5b9eSmrg# ings in this Software without prior written authorization from the X Consor-
31dcae5b9eSmrg# tium.
32dcae5b9eSmrg#
33dcae5b9eSmrg#
34dcae5b9eSmrg# FSF changes to this file are in the public domain.
35dcae5b9eSmrg#
36dcae5b9eSmrg# Calling this script install-sh is preferred over install.sh, to prevent
37dcae5b9eSmrg# `make' implicit rules from creating a file called install from it
38dcae5b9eSmrg# when there is no Makefile.
39dcae5b9eSmrg#
40dcae5b9eSmrg# This script is compatible with the BSD install script, but was written
41dcae5b9eSmrg# from scratch.  It can only install one file at a time, a restriction
42dcae5b9eSmrg# shared with many OS's install programs.
43dcae5b9eSmrg
44dcae5b9eSmrg
45dcae5b9eSmrg# set DOITPROG to echo to test this script
46dcae5b9eSmrg
47dcae5b9eSmrg# Don't use :- since 4.3BSD and earlier shells don't like it.
48dcae5b9eSmrgdoit="${DOITPROG-}"
49dcae5b9eSmrg
50dcae5b9eSmrg
51dcae5b9eSmrg# put in absolute paths if you don't have them in your path; or use env. vars.
52dcae5b9eSmrg
53dcae5b9eSmrgmvprog="${MVPROG-mv}"
54dcae5b9eSmrgcpprog="${CPPROG-cp}"
55dcae5b9eSmrgchmodprog="${CHMODPROG-chmod}"
56dcae5b9eSmrgchownprog="${CHOWNPROG-chown}"
57dcae5b9eSmrgchgrpprog="${CHGRPPROG-chgrp}"
58dcae5b9eSmrgstripprog="${STRIPPROG-strip}"
59dcae5b9eSmrgrmprog="${RMPROG-rm}"
60dcae5b9eSmrgmkdirprog="${MKDIRPROG-mkdir}"
61dcae5b9eSmrg
62dcae5b9eSmrgtransformbasename=""
63dcae5b9eSmrgtransform_arg=""
64dcae5b9eSmrginstcmd="$mvprog"
65dcae5b9eSmrgchmodcmd="$chmodprog 0755"
66dcae5b9eSmrgchowncmd=""
67dcae5b9eSmrgchgrpcmd=""
68dcae5b9eSmrgstripcmd=""
69dcae5b9eSmrgrmcmd="$rmprog -f"
70dcae5b9eSmrgmvcmd="$mvprog"
71dcae5b9eSmrgsrc=""
72dcae5b9eSmrgdst=""
73dcae5b9eSmrgdir_arg=""
74dcae5b9eSmrg
75dcae5b9eSmrgwhile [ x"$1" != x ]; do
76dcae5b9eSmrg    case $1 in
77dcae5b9eSmrg	-c) instcmd=$cpprog
78dcae5b9eSmrg	    shift
79dcae5b9eSmrg	    continue;;
80dcae5b9eSmrg
81dcae5b9eSmrg	-d) dir_arg=true
82dcae5b9eSmrg	    shift
83dcae5b9eSmrg	    continue;;
84dcae5b9eSmrg
85dcae5b9eSmrg	-m) chmodcmd="$chmodprog $2"
86dcae5b9eSmrg	    shift
87dcae5b9eSmrg	    shift
88dcae5b9eSmrg	    continue;;
89dcae5b9eSmrg
90dcae5b9eSmrg	-o) chowncmd="$chownprog $2"
91dcae5b9eSmrg	    shift
92dcae5b9eSmrg	    shift
93dcae5b9eSmrg	    continue;;
94dcae5b9eSmrg
95dcae5b9eSmrg	-g) chgrpcmd="$chgrpprog $2"
96dcae5b9eSmrg	    shift
97dcae5b9eSmrg	    shift
98dcae5b9eSmrg	    continue;;
99dcae5b9eSmrg
100dcae5b9eSmrg	-s) stripcmd=$stripprog
101dcae5b9eSmrg	    shift
102dcae5b9eSmrg	    continue;;
103dcae5b9eSmrg
104dcae5b9eSmrg	-t=*) transformarg=`echo $1 | sed 's/-t=//'`
105dcae5b9eSmrg	    shift
106dcae5b9eSmrg	    continue;;
107dcae5b9eSmrg
108dcae5b9eSmrg	-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
109dcae5b9eSmrg	    shift
110dcae5b9eSmrg	    continue;;
111dcae5b9eSmrg
112dcae5b9eSmrg	*)  if [ x"$src" = x ]
113dcae5b9eSmrg	    then
114dcae5b9eSmrg		src=$1
115dcae5b9eSmrg	    else
116dcae5b9eSmrg		# this colon is to work around a 386BSD /bin/sh bug
117dcae5b9eSmrg		:
118dcae5b9eSmrg		dst=$1
119dcae5b9eSmrg	    fi
120dcae5b9eSmrg	    shift
121dcae5b9eSmrg	    continue;;
122dcae5b9eSmrg    esac
123dcae5b9eSmrgdone
124dcae5b9eSmrg
125dcae5b9eSmrgif [ x"$src" = x ]
126dcae5b9eSmrgthen
127dcae5b9eSmrg	echo "$0: no input file specified" >&2
128dcae5b9eSmrg	exit 1
129dcae5b9eSmrgelse
130dcae5b9eSmrg	:
131dcae5b9eSmrgfi
132dcae5b9eSmrg
133dcae5b9eSmrgif [ x"$dir_arg" != x ]; then
134dcae5b9eSmrg	dst=$src
135dcae5b9eSmrg	src=""
136dcae5b9eSmrg
137dcae5b9eSmrg	if [ -d "$dst" ]; then
138dcae5b9eSmrg		instcmd=:
139dcae5b9eSmrg		chmodcmd=""
140dcae5b9eSmrg	else
141dcae5b9eSmrg		instcmd=$mkdirprog
142dcae5b9eSmrg	fi
143dcae5b9eSmrgelse
144dcae5b9eSmrg
145dcae5b9eSmrg# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
146dcae5b9eSmrg# might cause directories to be created, which would be especially bad
147dcae5b9eSmrg# if $src (and thus $dsttmp) contains '*'.
148dcae5b9eSmrg
149dcae5b9eSmrg	if [ -f "$src" ] || [ -d "$src" ]
150dcae5b9eSmrg	then
151dcae5b9eSmrg		:
152dcae5b9eSmrg	else
153dcae5b9eSmrg		echo "$0: $src does not exist" >&2
154dcae5b9eSmrg		exit 1
155dcae5b9eSmrg	fi
156dcae5b9eSmrg
157dcae5b9eSmrg	if [ x"$dst" = x ]
158dcae5b9eSmrg	then
159dcae5b9eSmrg		echo "$0: no destination specified" >&2
160dcae5b9eSmrg		exit 1
161dcae5b9eSmrg	else
162dcae5b9eSmrg		:
163dcae5b9eSmrg	fi
164dcae5b9eSmrg
165dcae5b9eSmrg# If destination is a directory, append the input filename; if your system
166dcae5b9eSmrg# does not like double slashes in filenames, you may need to add some logic
167dcae5b9eSmrg
168dcae5b9eSmrg	if [ -d "$dst" ]
169dcae5b9eSmrg	then
170dcae5b9eSmrg		dst=$dst/`basename "$src"`
171dcae5b9eSmrg	else
172dcae5b9eSmrg		:
173dcae5b9eSmrg	fi
174dcae5b9eSmrgfi
175dcae5b9eSmrg
176dcae5b9eSmrg## this sed command emulates the dirname command
177dcae5b9eSmrgdstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
178dcae5b9eSmrg
179dcae5b9eSmrg# Make sure that the destination directory exists.
180dcae5b9eSmrg#  this part is taken from Noah Friedman's mkinstalldirs script
181dcae5b9eSmrg
182dcae5b9eSmrg# Skip lots of stat calls in the usual case.
183dcae5b9eSmrgif [ ! -d "$dstdir" ]; then
184dcae5b9eSmrgdefaultIFS='
185dcae5b9eSmrg	'
186dcae5b9eSmrgIFS="${IFS-$defaultIFS}"
187dcae5b9eSmrg
188dcae5b9eSmrgoIFS=$IFS
189dcae5b9eSmrg# Some sh's can't handle IFS=/ for some reason.
190dcae5b9eSmrgIFS='%'
191dcae5b9eSmrgset - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
192dcae5b9eSmrgIFS=$oIFS
193dcae5b9eSmrg
194dcae5b9eSmrgpathcomp=''
195dcae5b9eSmrg
196dcae5b9eSmrgwhile [ $# -ne 0 ] ; do
197dcae5b9eSmrg	pathcomp=$pathcomp$1
198dcae5b9eSmrg	shift
199dcae5b9eSmrg
200dcae5b9eSmrg	if [ ! -d "$pathcomp" ] ;
201dcae5b9eSmrg        then
202dcae5b9eSmrg		$mkdirprog "$pathcomp"
203dcae5b9eSmrg	else
204dcae5b9eSmrg		:
205dcae5b9eSmrg	fi
206dcae5b9eSmrg
207dcae5b9eSmrg	pathcomp=$pathcomp/
208dcae5b9eSmrgdone
209dcae5b9eSmrgfi
210dcae5b9eSmrg
211dcae5b9eSmrgif [ x"$dir_arg" != x ]
212dcae5b9eSmrgthen
213dcae5b9eSmrg	$doit $instcmd "$dst" &&
214dcae5b9eSmrg
215dcae5b9eSmrg	if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi &&
216dcae5b9eSmrg	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi &&
217dcae5b9eSmrg	if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi &&
218dcae5b9eSmrg	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi
219dcae5b9eSmrgelse
220dcae5b9eSmrg
221dcae5b9eSmrg# If we're going to rename the final executable, determine the name now.
222dcae5b9eSmrg
223dcae5b9eSmrg	if [ x"$transformarg" = x ]
224dcae5b9eSmrg	then
225dcae5b9eSmrg		dstfile=`basename "$dst"`
226dcae5b9eSmrg	else
227dcae5b9eSmrg		dstfile=`basename "$dst" $transformbasename |
228dcae5b9eSmrg			sed $transformarg`$transformbasename
229dcae5b9eSmrg	fi
230dcae5b9eSmrg
231dcae5b9eSmrg# don't allow the sed command to completely eliminate the filename
232dcae5b9eSmrg
233dcae5b9eSmrg	if [ x"$dstfile" = x ]
234dcae5b9eSmrg	then
235dcae5b9eSmrg		dstfile=`basename "$dst"`
236dcae5b9eSmrg	else
237dcae5b9eSmrg		:
238dcae5b9eSmrg	fi
239dcae5b9eSmrg
240dcae5b9eSmrg# Make a couple of temp file names in the proper directory.
241dcae5b9eSmrg
242dcae5b9eSmrg	dsttmp=$dstdir/_inst.$$_
243dcae5b9eSmrg	rmtmp=$dstdir/_rm.$$_
244dcae5b9eSmrg
245dcae5b9eSmrg# Trap to clean up temp files at exit.
246dcae5b9eSmrg
247dcae5b9eSmrg	trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
248dcae5b9eSmrg	trap '(exit $?); exit' 1 2 13 15
249dcae5b9eSmrg
250dcae5b9eSmrg# Move or copy the file name to the temp name
251dcae5b9eSmrg
252dcae5b9eSmrg	$doit $instcmd "$src" "$dsttmp" &&
253dcae5b9eSmrg
254dcae5b9eSmrg# and set any options; do chmod last to preserve setuid bits
255dcae5b9eSmrg
256dcae5b9eSmrg# If any of these fail, we abort the whole thing.  If we want to
257dcae5b9eSmrg# ignore errors from any of these, just make sure not to ignore
258dcae5b9eSmrg# errors from the above "$doit $instcmd $src $dsttmp" command.
259dcae5b9eSmrg
260dcae5b9eSmrg	if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi &&
261dcae5b9eSmrg	if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi &&
262dcae5b9eSmrg	if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi &&
263dcae5b9eSmrg	if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi &&
264dcae5b9eSmrg
265dcae5b9eSmrg# Now remove or move aside any old file at destination location.  We try this
266dcae5b9eSmrg# two ways since rm can't unlink itself on some systems and the destination
267dcae5b9eSmrg# file might be busy for other reasons.  In this case, the final cleanup
268dcae5b9eSmrg# might fail but the new file should still install successfully.
269dcae5b9eSmrg
270dcae5b9eSmrg{
271dcae5b9eSmrg	if [ -f "$dstdir/$dstfile" ]
272dcae5b9eSmrg	then
273dcae5b9eSmrg		$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null ||
274dcae5b9eSmrg		$doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null ||
275dcae5b9eSmrg		{
276dcae5b9eSmrg		  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
277dcae5b9eSmrg		  (exit 1); exit
278dcae5b9eSmrg		}
279dcae5b9eSmrg	else
280dcae5b9eSmrg		:
281dcae5b9eSmrg	fi
282dcae5b9eSmrg} &&
283dcae5b9eSmrg
284dcae5b9eSmrg# Now rename the file to the real destination.
285dcae5b9eSmrg
286dcae5b9eSmrg	$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
287dcae5b9eSmrg
288dcae5b9eSmrgfi &&
289dcae5b9eSmrg
290dcae5b9eSmrg# The final little trick to "correctly" pass the exit status to the exit trap.
291dcae5b9eSmrg
292dcae5b9eSmrg{
293dcae5b9eSmrg	(exit 0); exit
294dcae5b9eSmrg}
295