install-sh revision 17ca54c3
117ca54c3Smrg#!/bin/sh
217ca54c3Smrg# install - install a program, script, or datafile
317ca54c3Smrg
417ca54c3Smrgscriptversion=2004-02-15.20
517ca54c3Smrg
617ca54c3Smrg# This originates from X11R5 (mit/util/scripts/install.sh), which was
717ca54c3Smrg# later released in X11R6 (xc/config/util/install.sh) with the
817ca54c3Smrg# following copyright and license.
917ca54c3Smrg#
1017ca54c3Smrg# Copyright (C) 1994 X Consortium
1117ca54c3Smrg#
1217ca54c3Smrg# Permission is hereby granted, free of charge, to any person obtaining a copy
1317ca54c3Smrg# of this software and associated documentation files (the "Software"), to
1417ca54c3Smrg# deal in the Software without restriction, including without limitation the
1517ca54c3Smrg# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
1617ca54c3Smrg# sell copies of the Software, and to permit persons to whom the Software is
1717ca54c3Smrg# furnished to do so, subject to the following conditions:
1817ca54c3Smrg#
1917ca54c3Smrg# The above copyright notice and this permission notice shall be included in
2017ca54c3Smrg# all copies or substantial portions of the Software.
2117ca54c3Smrg#
2217ca54c3Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2317ca54c3Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2417ca54c3Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
2517ca54c3Smrg# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
2617ca54c3Smrg# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
2717ca54c3Smrg# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2817ca54c3Smrg#
2917ca54c3Smrg# Except as contained in this notice, the name of the X Consortium shall not
3017ca54c3Smrg# be used in advertising or otherwise to promote the sale, use or other deal-
3117ca54c3Smrg# ings in this Software without prior written authorization from the X Consor-
3217ca54c3Smrg# tium.
3317ca54c3Smrg#
3417ca54c3Smrg#
3517ca54c3Smrg# FSF changes to this file are in the public domain.
3617ca54c3Smrg#
3717ca54c3Smrg# Calling this script install-sh is preferred over install.sh, to prevent
3817ca54c3Smrg# `make' implicit rules from creating a file called install from it
3917ca54c3Smrg# when there is no Makefile.
4017ca54c3Smrg#
4117ca54c3Smrg# This script is compatible with the BSD install script, but was written
4217ca54c3Smrg# from scratch.  It can only install one file at a time, a restriction
4317ca54c3Smrg# shared with many OS's install programs.
4417ca54c3Smrg
4517ca54c3Smrg# set DOITPROG to echo to test this script
4617ca54c3Smrg
4717ca54c3Smrg# Don't use :- since 4.3BSD and earlier shells don't like it.
4817ca54c3Smrgdoit="${DOITPROG-}"
4917ca54c3Smrg
5017ca54c3Smrg# put in absolute paths if you don't have them in your path; or use env. vars.
5117ca54c3Smrg
5217ca54c3Smrgmvprog="${MVPROG-mv}"
5317ca54c3Smrgcpprog="${CPPROG-cp}"
5417ca54c3Smrgchmodprog="${CHMODPROG-chmod}"
5517ca54c3Smrgchownprog="${CHOWNPROG-chown}"
5617ca54c3Smrgchgrpprog="${CHGRPPROG-chgrp}"
5717ca54c3Smrgstripprog="${STRIPPROG-strip}"
5817ca54c3Smrgrmprog="${RMPROG-rm}"
5917ca54c3Smrgmkdirprog="${MKDIRPROG-mkdir}"
6017ca54c3Smrg
6117ca54c3Smrgtransformbasename=
6217ca54c3Smrgtransform_arg=
6317ca54c3Smrginstcmd="$mvprog"
6417ca54c3Smrgchmodcmd="$chmodprog 0755"
6517ca54c3Smrgchowncmd=
6617ca54c3Smrgchgrpcmd=
6717ca54c3Smrgstripcmd=
6817ca54c3Smrgrmcmd="$rmprog -f"
6917ca54c3Smrgmvcmd="$mvprog"
7017ca54c3Smrgsrc=
7117ca54c3Smrgdst=
7217ca54c3Smrgdir_arg=
7317ca54c3Smrg
7417ca54c3Smrgusage="Usage: $0 [OPTION]... SRCFILE DSTFILE
7517ca54c3Smrg   or: $0 [OPTION]... SRCFILES... DIRECTORY
7617ca54c3Smrg   or: $0 -d DIRECTORIES...
7717ca54c3Smrg
7817ca54c3SmrgIn the first form, install SRCFILE to DSTFILE, removing SRCFILE by default.
7917ca54c3SmrgIn the second, create the directory path DIR.
8017ca54c3Smrg
8117ca54c3SmrgOptions:
8217ca54c3Smrg-b=TRANSFORMBASENAME
8317ca54c3Smrg-c         copy source (using $cpprog) instead of moving (using $mvprog).
8417ca54c3Smrg-d         create directories instead of installing files.
8517ca54c3Smrg-g GROUP   $chgrp installed files to GROUP.
8617ca54c3Smrg-m MODE    $chmod installed files to MODE.
8717ca54c3Smrg-o USER    $chown installed files to USER.
8817ca54c3Smrg-s         strip installed files (using $stripprog).
8917ca54c3Smrg-t=TRANSFORM
9017ca54c3Smrg--help     display this help and exit.
9117ca54c3Smrg--version  display version info and exit.
9217ca54c3Smrg
9317ca54c3SmrgEnvironment variables override the default commands:
9417ca54c3Smrg  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
9517ca54c3Smrg"
9617ca54c3Smrg
9717ca54c3Smrgwhile test -n "$1"; do
9817ca54c3Smrg  case $1 in
9917ca54c3Smrg    -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
10017ca54c3Smrg        shift
10117ca54c3Smrg        continue;;
10217ca54c3Smrg
10317ca54c3Smrg    -c) instcmd=$cpprog
10417ca54c3Smrg        shift
10517ca54c3Smrg        continue;;
10617ca54c3Smrg
10717ca54c3Smrg    -d) dir_arg=true
10817ca54c3Smrg        shift
10917ca54c3Smrg        continue;;
11017ca54c3Smrg
11117ca54c3Smrg    -g) chgrpcmd="$chgrpprog $2"
11217ca54c3Smrg        shift
11317ca54c3Smrg        shift
11417ca54c3Smrg        continue;;
11517ca54c3Smrg
11617ca54c3Smrg    --help) echo "$usage"; exit 0;;
11717ca54c3Smrg
11817ca54c3Smrg    -m) chmodcmd="$chmodprog $2"
11917ca54c3Smrg        shift
12017ca54c3Smrg        shift
12117ca54c3Smrg        continue;;
12217ca54c3Smrg
12317ca54c3Smrg    -o) chowncmd="$chownprog $2"
12417ca54c3Smrg        shift
12517ca54c3Smrg        shift
12617ca54c3Smrg        continue;;
12717ca54c3Smrg
12817ca54c3Smrg    -s) stripcmd=$stripprog
12917ca54c3Smrg        shift
13017ca54c3Smrg        continue;;
13117ca54c3Smrg
13217ca54c3Smrg    -t=*) transformarg=`echo $1 | sed 's/-t=//'`
13317ca54c3Smrg        shift
13417ca54c3Smrg        continue;;
13517ca54c3Smrg
13617ca54c3Smrg    --version) echo "$0 $scriptversion"; exit 0;;
13717ca54c3Smrg
13817ca54c3Smrg    *)  # When -d is used, all remaining arguments are directories to create.
13917ca54c3Smrg	test -n "$dir_arg" && break
14017ca54c3Smrg        # Otherwise, the last argument is the destination.  Remove it from $@.
14117ca54c3Smrg	for arg
14217ca54c3Smrg	do
14317ca54c3Smrg          if test -n "$dstarg"; then
14417ca54c3Smrg	    # $@ is not empty: it contains at least $arg.
14517ca54c3Smrg	    set fnord "$@" "$dstarg"
14617ca54c3Smrg	    shift # fnord
14717ca54c3Smrg	  fi
14817ca54c3Smrg	  shift # arg
14917ca54c3Smrg	  dstarg=$arg
15017ca54c3Smrg	done
15117ca54c3Smrg	break;;
15217ca54c3Smrg  esac
15317ca54c3Smrgdone
15417ca54c3Smrg
15517ca54c3Smrgif test -z "$1"; then
15617ca54c3Smrg  if test -z "$dir_arg"; then
15717ca54c3Smrg    echo "$0: no input file specified." >&2
15817ca54c3Smrg    exit 1
15917ca54c3Smrg  fi
16017ca54c3Smrg  # It's OK to call `install-sh -d' without argument.
16117ca54c3Smrg  # This can happen when creating conditional directories.
16217ca54c3Smrg  exit 0
16317ca54c3Smrgfi
16417ca54c3Smrg
16517ca54c3Smrgfor src
16617ca54c3Smrgdo
16717ca54c3Smrg  # Protect names starting with `-'.
16817ca54c3Smrg  case $src in
16917ca54c3Smrg    -*) src=./$src ;;
17017ca54c3Smrg  esac
17117ca54c3Smrg
17217ca54c3Smrg  if test -n "$dir_arg"; then
17317ca54c3Smrg    dst=$src
17417ca54c3Smrg    src=
17517ca54c3Smrg
17617ca54c3Smrg    if test -d "$dst"; then
17717ca54c3Smrg      instcmd=:
17817ca54c3Smrg      chmodcmd=
17917ca54c3Smrg    else
18017ca54c3Smrg      instcmd=$mkdirprog
18117ca54c3Smrg    fi
18217ca54c3Smrg  else
18317ca54c3Smrg    # Waiting for this to be detected by the "$instcmd $src $dsttmp" command
18417ca54c3Smrg    # might cause directories to be created, which would be especially bad
18517ca54c3Smrg    # if $src (and thus $dsttmp) contains '*'.
18617ca54c3Smrg    if test ! -f "$src" && test ! -d "$src"; then
18717ca54c3Smrg      echo "$0: $src does not exist." >&2
18817ca54c3Smrg      exit 1
18917ca54c3Smrg    fi
19017ca54c3Smrg
19117ca54c3Smrg    if test -z "$dstarg"; then
19217ca54c3Smrg      echo "$0: no destination specified." >&2
19317ca54c3Smrg      exit 1
19417ca54c3Smrg    fi
19517ca54c3Smrg
19617ca54c3Smrg    dst=$dstarg
19717ca54c3Smrg    # Protect names starting with `-'.
19817ca54c3Smrg    case $dst in
19917ca54c3Smrg      -*) dst=./$dst ;;
20017ca54c3Smrg    esac
20117ca54c3Smrg
20217ca54c3Smrg    # If destination is a directory, append the input filename; won't work
20317ca54c3Smrg    # if double slashes aren't ignored.
20417ca54c3Smrg    if test -d "$dst"; then
20517ca54c3Smrg      dst=$dst/`basename "$src"`
20617ca54c3Smrg    fi
20717ca54c3Smrg  fi
20817ca54c3Smrg
20917ca54c3Smrg  # This sed command emulates the dirname command.
21017ca54c3Smrg  dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
21117ca54c3Smrg
21217ca54c3Smrg  # Make sure that the destination directory exists.
21317ca54c3Smrg
21417ca54c3Smrg  # Skip lots of stat calls in the usual case.
21517ca54c3Smrg  if test ! -d "$dstdir"; then
21617ca54c3Smrg    defaultIFS='
21717ca54c3Smrg	 '
21817ca54c3Smrg    IFS="${IFS-$defaultIFS}"
21917ca54c3Smrg
22017ca54c3Smrg    oIFS=$IFS
22117ca54c3Smrg    # Some sh's can't handle IFS=/ for some reason.
22217ca54c3Smrg    IFS='%'
22317ca54c3Smrg    set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
22417ca54c3Smrg    IFS=$oIFS
22517ca54c3Smrg
22617ca54c3Smrg    pathcomp=
22717ca54c3Smrg
22817ca54c3Smrg    while test $# -ne 0 ; do
22917ca54c3Smrg      pathcomp=$pathcomp$1
23017ca54c3Smrg      shift
23117ca54c3Smrg      if test ! -d "$pathcomp"; then
23217ca54c3Smrg        $mkdirprog "$pathcomp" || lasterr=$?
23317ca54c3Smrg	# mkdir can fail with a `File exist' error in case several
23417ca54c3Smrg	# install-sh are creating the directory concurrently.  This
23517ca54c3Smrg	# is OK.
23617ca54c3Smrg	test ! -d "$pathcomp" && { (exit ${lasterr-1}); exit; }
23717ca54c3Smrg      fi
23817ca54c3Smrg      pathcomp=$pathcomp/
23917ca54c3Smrg    done
24017ca54c3Smrg  fi
24117ca54c3Smrg
24217ca54c3Smrg  if test -n "$dir_arg"; then
24317ca54c3Smrg    $doit $instcmd "$dst" \
24417ca54c3Smrg      && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
24517ca54c3Smrg      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
24617ca54c3Smrg      && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
24717ca54c3Smrg      && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
24817ca54c3Smrg
24917ca54c3Smrg  else
25017ca54c3Smrg    # If we're going to rename the final executable, determine the name now.
25117ca54c3Smrg    if test -z "$transformarg"; then
25217ca54c3Smrg      dstfile=`basename "$dst"`
25317ca54c3Smrg    else
25417ca54c3Smrg      dstfile=`basename "$dst" $transformbasename \
25517ca54c3Smrg               | sed $transformarg`$transformbasename
25617ca54c3Smrg    fi
25717ca54c3Smrg
25817ca54c3Smrg    # don't allow the sed command to completely eliminate the filename.
25917ca54c3Smrg    test -z "$dstfile" && dstfile=`basename "$dst"`
26017ca54c3Smrg
26117ca54c3Smrg    # Make a couple of temp file names in the proper directory.
26217ca54c3Smrg    dsttmp=$dstdir/_inst.$$_
26317ca54c3Smrg    rmtmp=$dstdir/_rm.$$_
26417ca54c3Smrg
26517ca54c3Smrg    # Trap to clean up those temp files at exit.
26617ca54c3Smrg    trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0
26717ca54c3Smrg    trap '(exit $?); exit' 1 2 13 15
26817ca54c3Smrg
26917ca54c3Smrg    # Move or copy the file name to the temp name
27017ca54c3Smrg    $doit $instcmd "$src" "$dsttmp" &&
27117ca54c3Smrg
27217ca54c3Smrg    # and set any options; do chmod last to preserve setuid bits.
27317ca54c3Smrg    #
27417ca54c3Smrg    # If any of these fail, we abort the whole thing.  If we want to
27517ca54c3Smrg    # ignore errors from any of these, just make sure not to ignore
27617ca54c3Smrg    # errors from the above "$doit $instcmd $src $dsttmp" command.
27717ca54c3Smrg    #
27817ca54c3Smrg    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
27917ca54c3Smrg      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
28017ca54c3Smrg      && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
28117ca54c3Smrg      && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
28217ca54c3Smrg
28317ca54c3Smrg    # Now remove or move aside any old file at destination location.  We
28417ca54c3Smrg    # try this two ways since rm can't unlink itself on some systems and
28517ca54c3Smrg    # the destination file might be busy for other reasons.  In this case,
28617ca54c3Smrg    # the final cleanup might fail but the new file should still install
28717ca54c3Smrg    # successfully.
28817ca54c3Smrg    {
28917ca54c3Smrg      if test -f "$dstdir/$dstfile"; then
29017ca54c3Smrg        $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
29117ca54c3Smrg        || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
29217ca54c3Smrg        || {
29317ca54c3Smrg	  echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
29417ca54c3Smrg	  (exit 1); exit
29517ca54c3Smrg        }
29617ca54c3Smrg      else
29717ca54c3Smrg        :
29817ca54c3Smrg      fi
29917ca54c3Smrg    } &&
30017ca54c3Smrg
30117ca54c3Smrg    # Now rename the file to the real destination.
30217ca54c3Smrg    $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
30317ca54c3Smrg  fi || { (exit 1); exit; }
30417ca54c3Smrgdone
30517ca54c3Smrg
30617ca54c3Smrg# The final little trick to "correctly" pass the exit status to the exit trap.
30717ca54c3Smrg{
30817ca54c3Smrg  (exit 0); exit
30917ca54c3Smrg}
31017ca54c3Smrg
31117ca54c3Smrg# Local variables:
31217ca54c3Smrg# eval: (add-hook 'write-file-hooks 'time-stamp)
31317ca54c3Smrg# time-stamp-start: "scriptversion="
31417ca54c3Smrg# time-stamp-format: "%:y-%02m-%02d.%02H"
31517ca54c3Smrg# time-stamp-end: "$"
31617ca54c3Smrg# End:
317