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