install-sh revision 4b0ead49
14b0ead49Smrg#!/bin/sh
24b0ead49Smrg# install - install a program, script, or datafile
34b0ead49Smrg
44b0ead49Smrgscriptversion=2005-05-14.22
54b0ead49Smrg
64b0ead49Smrg# This originates from X11R5 (mit/util/scripts/install.sh), which was
74b0ead49Smrg# later released in X11R6 (xc/config/util/install.sh) with the
84b0ead49Smrg# following copyright and license.
94b0ead49Smrg#
104b0ead49Smrg# Copyright (C) 1994 X Consortium
114b0ead49Smrg#
124b0ead49Smrg# Permission is hereby granted, free of charge, to any person obtaining a copy
134b0ead49Smrg# of this software and associated documentation files (the "Software"), to
144b0ead49Smrg# deal in the Software without restriction, including without limitation the
154b0ead49Smrg# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
164b0ead49Smrg# sell copies of the Software, and to permit persons to whom the Software is
174b0ead49Smrg# furnished to do so, subject to the following conditions:
184b0ead49Smrg#
194b0ead49Smrg# The above copyright notice and this permission notice shall be included in
204b0ead49Smrg# all copies or substantial portions of the Software.
214b0ead49Smrg#
224b0ead49Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
234b0ead49Smrg# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
244b0ead49Smrg# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
254b0ead49Smrg# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
264b0ead49Smrg# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
274b0ead49Smrg# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
284b0ead49Smrg#
294b0ead49Smrg# Except as contained in this notice, the name of the X Consortium shall not
304b0ead49Smrg# be used in advertising or otherwise to promote the sale, use or other deal-
314b0ead49Smrg# ings in this Software without prior written authorization from the X Consor-
324b0ead49Smrg# tium.
334b0ead49Smrg#
344b0ead49Smrg#
354b0ead49Smrg# FSF changes to this file are in the public domain.
364b0ead49Smrg#
374b0ead49Smrg# Calling this script install-sh is preferred over install.sh, to prevent
384b0ead49Smrg# `make' implicit rules from creating a file called install from it
394b0ead49Smrg# when there is no Makefile.
404b0ead49Smrg#
414b0ead49Smrg# This script is compatible with the BSD install script, but was written
424b0ead49Smrg# from scratch.  It can only install one file at a time, a restriction
434b0ead49Smrg# shared with many OS's install programs.
444b0ead49Smrg
454b0ead49Smrg# set DOITPROG to echo to test this script
464b0ead49Smrg
474b0ead49Smrg# Don't use :- since 4.3BSD and earlier shells don't like it.
484b0ead49Smrgdoit="${DOITPROG-}"
494b0ead49Smrg
504b0ead49Smrg# put in absolute paths if you don't have them in your path; or use env. vars.
514b0ead49Smrg
524b0ead49Smrgmvprog="${MVPROG-mv}"
534b0ead49Smrgcpprog="${CPPROG-cp}"
544b0ead49Smrgchmodprog="${CHMODPROG-chmod}"
554b0ead49Smrgchownprog="${CHOWNPROG-chown}"
564b0ead49Smrgchgrpprog="${CHGRPPROG-chgrp}"
574b0ead49Smrgstripprog="${STRIPPROG-strip}"
584b0ead49Smrgrmprog="${RMPROG-rm}"
594b0ead49Smrgmkdirprog="${MKDIRPROG-mkdir}"
604b0ead49Smrg
614b0ead49Smrgchmodcmd="$chmodprog 0755"
624b0ead49Smrgchowncmd=
634b0ead49Smrgchgrpcmd=
644b0ead49Smrgstripcmd=
654b0ead49Smrgrmcmd="$rmprog -f"
664b0ead49Smrgmvcmd="$mvprog"
674b0ead49Smrgsrc=
684b0ead49Smrgdst=
694b0ead49Smrgdir_arg=
704b0ead49Smrgdstarg=
714b0ead49Smrgno_target_directory=
724b0ead49Smrg
734b0ead49Smrgusage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
744b0ead49Smrg   or: $0 [OPTION]... SRCFILES... DIRECTORY
754b0ead49Smrg   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
764b0ead49Smrg   or: $0 [OPTION]... -d DIRECTORIES...
774b0ead49Smrg
784b0ead49SmrgIn the 1st form, copy SRCFILE to DSTFILE.
794b0ead49SmrgIn the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
804b0ead49SmrgIn the 4th, create DIRECTORIES.
814b0ead49Smrg
824b0ead49SmrgOptions:
834b0ead49Smrg-c         (ignored)
844b0ead49Smrg-d         create directories instead of installing files.
854b0ead49Smrg-g GROUP   $chgrpprog installed files to GROUP.
864b0ead49Smrg-m MODE    $chmodprog installed files to MODE.
874b0ead49Smrg-o USER    $chownprog installed files to USER.
884b0ead49Smrg-s         $stripprog installed files.
894b0ead49Smrg-t DIRECTORY  install into DIRECTORY.
904b0ead49Smrg-T         report an error if DSTFILE is a directory.
914b0ead49Smrg--help     display this help and exit.
924b0ead49Smrg--version  display version info and exit.
934b0ead49Smrg
944b0ead49SmrgEnvironment variables override the default commands:
954b0ead49Smrg  CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
964b0ead49Smrg"
974b0ead49Smrg
984b0ead49Smrgwhile test -n "$1"; do
994b0ead49Smrg  case $1 in
1004b0ead49Smrg    -c) shift
1014b0ead49Smrg        continue;;
1024b0ead49Smrg
1034b0ead49Smrg    -d) dir_arg=true
1044b0ead49Smrg        shift
1054b0ead49Smrg        continue;;
1064b0ead49Smrg
1074b0ead49Smrg    -g) chgrpcmd="$chgrpprog $2"
1084b0ead49Smrg        shift
1094b0ead49Smrg        shift
1104b0ead49Smrg        continue;;
1114b0ead49Smrg
1124b0ead49Smrg    --help) echo "$usage"; exit $?;;
1134b0ead49Smrg
1144b0ead49Smrg    -m) chmodcmd="$chmodprog $2"
1154b0ead49Smrg        shift
1164b0ead49Smrg        shift
1174b0ead49Smrg        continue;;
1184b0ead49Smrg
1194b0ead49Smrg    -o) chowncmd="$chownprog $2"
1204b0ead49Smrg        shift
1214b0ead49Smrg        shift
1224b0ead49Smrg        continue;;
1234b0ead49Smrg
1244b0ead49Smrg    -s) stripcmd=$stripprog
1254b0ead49Smrg        shift
1264b0ead49Smrg        continue;;
1274b0ead49Smrg
1284b0ead49Smrg    -t) dstarg=$2
1294b0ead49Smrg	shift
1304b0ead49Smrg	shift
1314b0ead49Smrg	continue;;
1324b0ead49Smrg
1334b0ead49Smrg    -T) no_target_directory=true
1344b0ead49Smrg	shift
1354b0ead49Smrg	continue;;
1364b0ead49Smrg
1374b0ead49Smrg    --version) echo "$0 $scriptversion"; exit $?;;
1384b0ead49Smrg
1394b0ead49Smrg    *)  # When -d is used, all remaining arguments are directories to create.
1404b0ead49Smrg	# When -t is used, the destination is already specified.
1414b0ead49Smrg	test -n "$dir_arg$dstarg" && break
1424b0ead49Smrg        # Otherwise, the last argument is the destination.  Remove it from $@.
1434b0ead49Smrg	for arg
1444b0ead49Smrg	do
1454b0ead49Smrg          if test -n "$dstarg"; then
1464b0ead49Smrg	    # $@ is not empty: it contains at least $arg.
1474b0ead49Smrg	    set fnord "$@" "$dstarg"
1484b0ead49Smrg	    shift # fnord
1494b0ead49Smrg	  fi
1504b0ead49Smrg	  shift # arg
1514b0ead49Smrg	  dstarg=$arg
1524b0ead49Smrg	done
1534b0ead49Smrg	break;;
1544b0ead49Smrg  esac
1554b0ead49Smrgdone
1564b0ead49Smrg
1574b0ead49Smrgif test -z "$1"; then
1584b0ead49Smrg  if test -z "$dir_arg"; then
1594b0ead49Smrg    echo "$0: no input file specified." >&2
1604b0ead49Smrg    exit 1
1614b0ead49Smrg  fi
1624b0ead49Smrg  # It's OK to call `install-sh -d' without argument.
1634b0ead49Smrg  # This can happen when creating conditional directories.
1644b0ead49Smrg  exit 0
1654b0ead49Smrgfi
1664b0ead49Smrg
1674b0ead49Smrgfor src
1684b0ead49Smrgdo
1694b0ead49Smrg  # Protect names starting with `-'.
1704b0ead49Smrg  case $src in
1714b0ead49Smrg    -*) src=./$src ;;
1724b0ead49Smrg  esac
1734b0ead49Smrg
1744b0ead49Smrg  if test -n "$dir_arg"; then
1754b0ead49Smrg    dst=$src
1764b0ead49Smrg    src=
1774b0ead49Smrg
1784b0ead49Smrg    if test -d "$dst"; then
1794b0ead49Smrg      mkdircmd=:
1804b0ead49Smrg      chmodcmd=
1814b0ead49Smrg    else
1824b0ead49Smrg      mkdircmd=$mkdirprog
1834b0ead49Smrg    fi
1844b0ead49Smrg  else
1854b0ead49Smrg    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
1864b0ead49Smrg    # might cause directories to be created, which would be especially bad
1874b0ead49Smrg    # if $src (and thus $dsttmp) contains '*'.
1884b0ead49Smrg    if test ! -f "$src" && test ! -d "$src"; then
1894b0ead49Smrg      echo "$0: $src does not exist." >&2
1904b0ead49Smrg      exit 1
1914b0ead49Smrg    fi
1924b0ead49Smrg
1934b0ead49Smrg    if test -z "$dstarg"; then
1944b0ead49Smrg      echo "$0: no destination specified." >&2
1954b0ead49Smrg      exit 1
1964b0ead49Smrg    fi
1974b0ead49Smrg
1984b0ead49Smrg    dst=$dstarg
1994b0ead49Smrg    # Protect names starting with `-'.
2004b0ead49Smrg    case $dst in
2014b0ead49Smrg      -*) dst=./$dst ;;
2024b0ead49Smrg    esac
2034b0ead49Smrg
2044b0ead49Smrg    # If destination is a directory, append the input filename; won't work
2054b0ead49Smrg    # if double slashes aren't ignored.
2064b0ead49Smrg    if test -d "$dst"; then
2074b0ead49Smrg      if test -n "$no_target_directory"; then
2084b0ead49Smrg	echo "$0: $dstarg: Is a directory" >&2
2094b0ead49Smrg	exit 1
2104b0ead49Smrg      fi
2114b0ead49Smrg      dst=$dst/`basename "$src"`
2124b0ead49Smrg    fi
2134b0ead49Smrg  fi
2144b0ead49Smrg
2154b0ead49Smrg  # This sed command emulates the dirname command.
2164b0ead49Smrg  dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
2174b0ead49Smrg
2184b0ead49Smrg  # Make sure that the destination directory exists.
2194b0ead49Smrg
2204b0ead49Smrg  # Skip lots of stat calls in the usual case.
2214b0ead49Smrg  if test ! -d "$dstdir"; then
2224b0ead49Smrg    defaultIFS='
2234b0ead49Smrg	 '
2244b0ead49Smrg    IFS="${IFS-$defaultIFS}"
2254b0ead49Smrg
2264b0ead49Smrg    oIFS=$IFS
2274b0ead49Smrg    # Some sh's can't handle IFS=/ for some reason.
2284b0ead49Smrg    IFS='%'
2294b0ead49Smrg    set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
2304b0ead49Smrg    shift
2314b0ead49Smrg    IFS=$oIFS
2324b0ead49Smrg
2334b0ead49Smrg    pathcomp=
2344b0ead49Smrg
2354b0ead49Smrg    while test $# -ne 0 ; do
2364b0ead49Smrg      pathcomp=$pathcomp$1
2374b0ead49Smrg      shift
2384b0ead49Smrg      if test ! -d "$pathcomp"; then
2394b0ead49Smrg        $mkdirprog "$pathcomp"
2404b0ead49Smrg	# mkdir can fail with a `File exist' error in case several
2414b0ead49Smrg	# install-sh are creating the directory concurrently.  This
2424b0ead49Smrg	# is OK.
2434b0ead49Smrg	test -d "$pathcomp" || exit
2444b0ead49Smrg      fi
2454b0ead49Smrg      pathcomp=$pathcomp/
2464b0ead49Smrg    done
2474b0ead49Smrg  fi
2484b0ead49Smrg
2494b0ead49Smrg  if test -n "$dir_arg"; then
2504b0ead49Smrg    $doit $mkdircmd "$dst" \
2514b0ead49Smrg      && { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
2524b0ead49Smrg      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
2534b0ead49Smrg      && { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
2544b0ead49Smrg      && { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
2554b0ead49Smrg
2564b0ead49Smrg  else
2574b0ead49Smrg    dstfile=`basename "$dst"`
2584b0ead49Smrg
2594b0ead49Smrg    # Make a couple of temp file names in the proper directory.
2604b0ead49Smrg    dsttmp=$dstdir/_inst.$$_
2614b0ead49Smrg    rmtmp=$dstdir/_rm.$$_
2624b0ead49Smrg
2634b0ead49Smrg    # Trap to clean up those temp files at exit.
2644b0ead49Smrg    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
2654b0ead49Smrg    trap '(exit $?); exit' 1 2 13 15
2664b0ead49Smrg
2674b0ead49Smrg    # Copy the file name to the temp name.
2684b0ead49Smrg    $doit $cpprog "$src" "$dsttmp" &&
2694b0ead49Smrg
2704b0ead49Smrg    # and set any options; do chmod last to preserve setuid bits.
2714b0ead49Smrg    #
2724b0ead49Smrg    # If any of these fail, we abort the whole thing.  If we want to
2734b0ead49Smrg    # ignore errors from any of these, just make sure not to ignore
2744b0ead49Smrg    # errors from the above "$doit $cpprog $src $dsttmp" command.
2754b0ead49Smrg    #
2764b0ead49Smrg    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
2774b0ead49Smrg      && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
2784b0ead49Smrg      && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
2794b0ead49Smrg      && { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
2804b0ead49Smrg
2814b0ead49Smrg    # Now rename the file to the real destination.
2824b0ead49Smrg    { $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
2834b0ead49Smrg      || {
2844b0ead49Smrg	   # The rename failed, perhaps because mv can't rename something else
2854b0ead49Smrg	   # to itself, or perhaps because mv is so ancient that it does not
2864b0ead49Smrg	   # support -f.
2874b0ead49Smrg
2884b0ead49Smrg	   # Now remove or move aside any old file at destination location.
2894b0ead49Smrg	   # We try this two ways since rm can't unlink itself on some
2904b0ead49Smrg	   # systems and the destination file might be busy for other
2914b0ead49Smrg	   # reasons.  In this case, the final cleanup might fail but the new
2924b0ead49Smrg	   # file should still install successfully.
2934b0ead49Smrg	   {
2944b0ead49Smrg	     if test -f "$dstdir/$dstfile"; then
2954b0ead49Smrg	       $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
2964b0ead49Smrg	       || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
2974b0ead49Smrg	       || {
2984b0ead49Smrg		 echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
2994b0ead49Smrg		 (exit 1); exit 1
3004b0ead49Smrg	       }
3014b0ead49Smrg	     else
3024b0ead49Smrg	       :
3034b0ead49Smrg	     fi
3044b0ead49Smrg	   } &&
3054b0ead49Smrg
3064b0ead49Smrg	   # Now rename the file to the real destination.
3074b0ead49Smrg	   $doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
3084b0ead49Smrg	 }
3094b0ead49Smrg    }
3104b0ead49Smrg  fi || { (exit 1); exit 1; }
3114b0ead49Smrgdone
3124b0ead49Smrg
3134b0ead49Smrg# The final little trick to "correctly" pass the exit status to the exit trap.
3144b0ead49Smrg{
3154b0ead49Smrg  (exit 0); exit 0
3164b0ead49Smrg}
3174b0ead49Smrg
3184b0ead49Smrg# Local variables:
3194b0ead49Smrg# eval: (add-hook 'write-file-hooks 'time-stamp)
3204b0ead49Smrg# time-stamp-start: "scriptversion="
3214b0ead49Smrg# time-stamp-format: "%:y-%02m-%02d.%02H"
3224b0ead49Smrg# time-stamp-end: "$"
3234b0ead49Smrg# End:
324