install-sh revision 692f60a7
1692f60a7Smrg#!/bin/sh 2692f60a7Smrg# install - install a program, script, or datafile 3692f60a7Smrg 4692f60a7Smrgscriptversion=2005-05-14.22 5692f60a7Smrg 6692f60a7Smrg# This originates from X11R5 (mit/util/scripts/install.sh), which was 7692f60a7Smrg# later released in X11R6 (xc/config/util/install.sh) with the 8692f60a7Smrg# following copyright and license. 9692f60a7Smrg# 10692f60a7Smrg# Copyright (C) 1994 X Consortium 11692f60a7Smrg# 12692f60a7Smrg# Permission is hereby granted, free of charge, to any person obtaining a copy 13692f60a7Smrg# of this software and associated documentation files (the "Software"), to 14692f60a7Smrg# deal in the Software without restriction, including without limitation the 15692f60a7Smrg# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16692f60a7Smrg# sell copies of the Software, and to permit persons to whom the Software is 17692f60a7Smrg# furnished to do so, subject to the following conditions: 18692f60a7Smrg# 19692f60a7Smrg# The above copyright notice and this permission notice shall be included in 20692f60a7Smrg# all copies or substantial portions of the Software. 21692f60a7Smrg# 22692f60a7Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23692f60a7Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24692f60a7Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25692f60a7Smrg# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26692f60a7Smrg# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27692f60a7Smrg# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28692f60a7Smrg# 29692f60a7Smrg# Except as contained in this notice, the name of the X Consortium shall not 30692f60a7Smrg# be used in advertising or otherwise to promote the sale, use or other deal- 31692f60a7Smrg# ings in this Software without prior written authorization from the X Consor- 32692f60a7Smrg# tium. 33692f60a7Smrg# 34692f60a7Smrg# 35692f60a7Smrg# FSF changes to this file are in the public domain. 36692f60a7Smrg# 37692f60a7Smrg# Calling this script install-sh is preferred over install.sh, to prevent 38692f60a7Smrg# `make' implicit rules from creating a file called install from it 39692f60a7Smrg# when there is no Makefile. 40692f60a7Smrg# 41692f60a7Smrg# This script is compatible with the BSD install script, but was written 42692f60a7Smrg# from scratch. It can only install one file at a time, a restriction 43692f60a7Smrg# shared with many OS's install programs. 44692f60a7Smrg 45692f60a7Smrg# set DOITPROG to echo to test this script 46692f60a7Smrg 47692f60a7Smrg# Don't use :- since 4.3BSD and earlier shells don't like it. 48692f60a7Smrgdoit="${DOITPROG-}" 49692f60a7Smrg 50692f60a7Smrg# put in absolute paths if you don't have them in your path; or use env. vars. 51692f60a7Smrg 52692f60a7Smrgmvprog="${MVPROG-mv}" 53692f60a7Smrgcpprog="${CPPROG-cp}" 54692f60a7Smrgchmodprog="${CHMODPROG-chmod}" 55692f60a7Smrgchownprog="${CHOWNPROG-chown}" 56692f60a7Smrgchgrpprog="${CHGRPPROG-chgrp}" 57692f60a7Smrgstripprog="${STRIPPROG-strip}" 58692f60a7Smrgrmprog="${RMPROG-rm}" 59692f60a7Smrgmkdirprog="${MKDIRPROG-mkdir}" 60692f60a7Smrg 61692f60a7Smrgchmodcmd="$chmodprog 0755" 62692f60a7Smrgchowncmd= 63692f60a7Smrgchgrpcmd= 64692f60a7Smrgstripcmd= 65692f60a7Smrgrmcmd="$rmprog -f" 66692f60a7Smrgmvcmd="$mvprog" 67692f60a7Smrgsrc= 68692f60a7Smrgdst= 69692f60a7Smrgdir_arg= 70692f60a7Smrgdstarg= 71692f60a7Smrgno_target_directory= 72692f60a7Smrg 73692f60a7Smrgusage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 74692f60a7Smrg or: $0 [OPTION]... SRCFILES... DIRECTORY 75692f60a7Smrg or: $0 [OPTION]... -t DIRECTORY SRCFILES... 76692f60a7Smrg or: $0 [OPTION]... -d DIRECTORIES... 77692f60a7Smrg 78692f60a7SmrgIn the 1st form, copy SRCFILE to DSTFILE. 79692f60a7SmrgIn the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 80692f60a7SmrgIn the 4th, create DIRECTORIES. 81692f60a7Smrg 82692f60a7SmrgOptions: 83692f60a7Smrg-c (ignored) 84692f60a7Smrg-d create directories instead of installing files. 85692f60a7Smrg-g GROUP $chgrpprog installed files to GROUP. 86692f60a7Smrg-m MODE $chmodprog installed files to MODE. 87692f60a7Smrg-o USER $chownprog installed files to USER. 88692f60a7Smrg-s $stripprog installed files. 89692f60a7Smrg-t DIRECTORY install into DIRECTORY. 90692f60a7Smrg-T report an error if DSTFILE is a directory. 91692f60a7Smrg--help display this help and exit. 92692f60a7Smrg--version display version info and exit. 93692f60a7Smrg 94692f60a7SmrgEnvironment variables override the default commands: 95692f60a7Smrg CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG 96692f60a7Smrg" 97692f60a7Smrg 98692f60a7Smrgwhile test -n "$1"; do 99692f60a7Smrg case $1 in 100692f60a7Smrg -c) shift 101692f60a7Smrg continue;; 102692f60a7Smrg 103692f60a7Smrg -d) dir_arg=true 104692f60a7Smrg shift 105692f60a7Smrg continue;; 106692f60a7Smrg 107692f60a7Smrg -g) chgrpcmd="$chgrpprog $2" 108692f60a7Smrg shift 109692f60a7Smrg shift 110692f60a7Smrg continue;; 111692f60a7Smrg 112692f60a7Smrg --help) echo "$usage"; exit $?;; 113692f60a7Smrg 114692f60a7Smrg -m) chmodcmd="$chmodprog $2" 115692f60a7Smrg shift 116692f60a7Smrg shift 117692f60a7Smrg continue;; 118692f60a7Smrg 119692f60a7Smrg -o) chowncmd="$chownprog $2" 120692f60a7Smrg shift 121692f60a7Smrg shift 122692f60a7Smrg continue;; 123692f60a7Smrg 124692f60a7Smrg -s) stripcmd=$stripprog 125692f60a7Smrg shift 126692f60a7Smrg continue;; 127692f60a7Smrg 128692f60a7Smrg -t) dstarg=$2 129692f60a7Smrg shift 130692f60a7Smrg shift 131692f60a7Smrg continue;; 132692f60a7Smrg 133692f60a7Smrg -T) no_target_directory=true 134692f60a7Smrg shift 135692f60a7Smrg continue;; 136692f60a7Smrg 137692f60a7Smrg --version) echo "$0 $scriptversion"; exit $?;; 138692f60a7Smrg 139692f60a7Smrg *) # When -d is used, all remaining arguments are directories to create. 140692f60a7Smrg # When -t is used, the destination is already specified. 141692f60a7Smrg test -n "$dir_arg$dstarg" && break 142692f60a7Smrg # Otherwise, the last argument is the destination. Remove it from $@. 143692f60a7Smrg for arg 144692f60a7Smrg do 145692f60a7Smrg if test -n "$dstarg"; then 146692f60a7Smrg # $@ is not empty: it contains at least $arg. 147692f60a7Smrg set fnord "$@" "$dstarg" 148692f60a7Smrg shift # fnord 149692f60a7Smrg fi 150692f60a7Smrg shift # arg 151692f60a7Smrg dstarg=$arg 152692f60a7Smrg done 153692f60a7Smrg break;; 154692f60a7Smrg esac 155692f60a7Smrgdone 156692f60a7Smrg 157692f60a7Smrgif test -z "$1"; then 158692f60a7Smrg if test -z "$dir_arg"; then 159692f60a7Smrg echo "$0: no input file specified." >&2 160692f60a7Smrg exit 1 161692f60a7Smrg fi 162692f60a7Smrg # It's OK to call `install-sh -d' without argument. 163692f60a7Smrg # This can happen when creating conditional directories. 164692f60a7Smrg exit 0 165692f60a7Smrgfi 166692f60a7Smrg 167692f60a7Smrgfor src 168692f60a7Smrgdo 169692f60a7Smrg # Protect names starting with `-'. 170692f60a7Smrg case $src in 171692f60a7Smrg -*) src=./$src ;; 172692f60a7Smrg esac 173692f60a7Smrg 174692f60a7Smrg if test -n "$dir_arg"; then 175692f60a7Smrg dst=$src 176692f60a7Smrg src= 177692f60a7Smrg 178692f60a7Smrg if test -d "$dst"; then 179692f60a7Smrg mkdircmd=: 180692f60a7Smrg chmodcmd= 181692f60a7Smrg else 182692f60a7Smrg mkdircmd=$mkdirprog 183692f60a7Smrg fi 184692f60a7Smrg else 185692f60a7Smrg # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 186692f60a7Smrg # might cause directories to be created, which would be especially bad 187692f60a7Smrg # if $src (and thus $dsttmp) contains '*'. 188692f60a7Smrg if test ! -f "$src" && test ! -d "$src"; then 189692f60a7Smrg echo "$0: $src does not exist." >&2 190692f60a7Smrg exit 1 191692f60a7Smrg fi 192692f60a7Smrg 193692f60a7Smrg if test -z "$dstarg"; then 194692f60a7Smrg echo "$0: no destination specified." >&2 195692f60a7Smrg exit 1 196692f60a7Smrg fi 197692f60a7Smrg 198692f60a7Smrg dst=$dstarg 199692f60a7Smrg # Protect names starting with `-'. 200692f60a7Smrg case $dst in 201692f60a7Smrg -*) dst=./$dst ;; 202692f60a7Smrg esac 203692f60a7Smrg 204692f60a7Smrg # If destination is a directory, append the input filename; won't work 205692f60a7Smrg # if double slashes aren't ignored. 206692f60a7Smrg if test -d "$dst"; then 207692f60a7Smrg if test -n "$no_target_directory"; then 208692f60a7Smrg echo "$0: $dstarg: Is a directory" >&2 209692f60a7Smrg exit 1 210692f60a7Smrg fi 211692f60a7Smrg dst=$dst/`basename "$src"` 212692f60a7Smrg fi 213692f60a7Smrg fi 214692f60a7Smrg 215692f60a7Smrg # This sed command emulates the dirname command. 216692f60a7Smrg dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'` 217692f60a7Smrg 218692f60a7Smrg # Make sure that the destination directory exists. 219692f60a7Smrg 220692f60a7Smrg # Skip lots of stat calls in the usual case. 221692f60a7Smrg if test ! -d "$dstdir"; then 222692f60a7Smrg defaultIFS=' 223692f60a7Smrg ' 224692f60a7Smrg IFS="${IFS-$defaultIFS}" 225692f60a7Smrg 226692f60a7Smrg oIFS=$IFS 227692f60a7Smrg # Some sh's can't handle IFS=/ for some reason. 228692f60a7Smrg IFS='%' 229692f60a7Smrg set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` 230692f60a7Smrg shift 231692f60a7Smrg IFS=$oIFS 232692f60a7Smrg 233692f60a7Smrg pathcomp= 234692f60a7Smrg 235692f60a7Smrg while test $# -ne 0 ; do 236692f60a7Smrg pathcomp=$pathcomp$1 237692f60a7Smrg shift 238692f60a7Smrg if test ! -d "$pathcomp"; then 239692f60a7Smrg $mkdirprog "$pathcomp" 240692f60a7Smrg # mkdir can fail with a `File exist' error in case several 241692f60a7Smrg # install-sh are creating the directory concurrently. This 242692f60a7Smrg # is OK. 243692f60a7Smrg test -d "$pathcomp" || exit 244692f60a7Smrg fi 245692f60a7Smrg pathcomp=$pathcomp/ 246692f60a7Smrg done 247692f60a7Smrg fi 248692f60a7Smrg 249692f60a7Smrg if test -n "$dir_arg"; then 250692f60a7Smrg $doit $mkdircmd "$dst" \ 251692f60a7Smrg && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \ 252692f60a7Smrg && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \ 253692f60a7Smrg && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \ 254692f60a7Smrg && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; } 255692f60a7Smrg 256692f60a7Smrg else 257692f60a7Smrg dstfile=`basename "$dst"` 258692f60a7Smrg 259692f60a7Smrg # Make a couple of temp file names in the proper directory. 260692f60a7Smrg dsttmp=$dstdir/_inst.$$_ 261692f60a7Smrg rmtmp=$dstdir/_rm.$$_ 262692f60a7Smrg 263692f60a7Smrg # Trap to clean up those temp files at exit. 264692f60a7Smrg trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 265692f60a7Smrg trap '(exit $?); exit' 1 2 13 15 266692f60a7Smrg 267692f60a7Smrg # Copy the file name to the temp name. 268692f60a7Smrg $doit $cpprog "$src" "$dsttmp" && 269692f60a7Smrg 270692f60a7Smrg # and set any options; do chmod last to preserve setuid bits. 271692f60a7Smrg # 272692f60a7Smrg # If any of these fail, we abort the whole thing. If we want to 273692f60a7Smrg # ignore errors from any of these, just make sure not to ignore 274692f60a7Smrg # errors from the above "$doit $cpprog $src $dsttmp" command. 275692f60a7Smrg # 276692f60a7Smrg { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ 277692f60a7Smrg && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ 278692f60a7Smrg && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ 279692f60a7Smrg && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } && 280692f60a7Smrg 281692f60a7Smrg # Now rename the file to the real destination. 282692f60a7Smrg { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \ 283692f60a7Smrg || { 284692f60a7Smrg # The rename failed, perhaps because mv can't rename something else 285692f60a7Smrg # to itself, or perhaps because mv is so ancient that it does not 286692f60a7Smrg # support -f. 287692f60a7Smrg 288692f60a7Smrg # Now remove or move aside any old file at destination location. 289692f60a7Smrg # We try this two ways since rm can't unlink itself on some 290692f60a7Smrg # systems and the destination file might be busy for other 291692f60a7Smrg # reasons. In this case, the final cleanup might fail but the new 292692f60a7Smrg # file should still install successfully. 293692f60a7Smrg { 294692f60a7Smrg if test -f "$dstdir/$dstfile"; then 295692f60a7Smrg $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \ 296692f60a7Smrg || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \ 297692f60a7Smrg || { 298692f60a7Smrg echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 299692f60a7Smrg (exit 1); exit 1 300692f60a7Smrg } 301692f60a7Smrg else 302692f60a7Smrg : 303692f60a7Smrg fi 304692f60a7Smrg } && 305692f60a7Smrg 306692f60a7Smrg # Now rename the file to the real destination. 307692f60a7Smrg $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" 308692f60a7Smrg } 309692f60a7Smrg } 310692f60a7Smrg fi || { (exit 1); exit 1; } 311692f60a7Smrgdone 312692f60a7Smrg 313692f60a7Smrg# The final little trick to "correctly" pass the exit status to the exit trap. 314692f60a7Smrg{ 315692f60a7Smrg (exit 0); exit 0 316692f60a7Smrg} 317692f60a7Smrg 318692f60a7Smrg# Local variables: 319692f60a7Smrg# eval: (add-hook 'write-file-hooks 'time-stamp) 320692f60a7Smrg# time-stamp-start: "scriptversion=" 321692f60a7Smrg# time-stamp-format: "%:y-%02m-%02d.%02H" 322692f60a7Smrg# time-stamp-end: "$" 323692f60a7Smrg# End: 324