xref: /freebsd/contrib/ncurses/install-sh (revision 68ad2b0d7af2a3571c4abac9afa712f9b09b721c)
1#!/bin/sh
2# install - install a program, script, or datafile
3
4scriptversion=2020-11-14.01; # UTC
5
6# https://lists.gnu.org/archive/html/automake/2018-09/msg00002.html
7#
8# Originally X11R4 util/scripts/install.sh, the following comments, copyright
9# and license were added by an autoconf developer in 1998 (about nine years
10# later).  I have made a minor change to the wording, i.e., "copyright holders"
11# vs "X Consortium", for reusability -TD
12#
13# -----------------------------------------------------------------------------
14# This originates from X11R5 (mit/util/scripts/install.sh), which was
15# later released in X11R6 (xc/config/util/install.sh) with the
16# following copyright and license.
17# -----------------------------------------------------------------------------
18# Copyright (C) 1994 X Consortium
19#
20# Permission is hereby granted, free of charge, to any person obtaining a copy
21# of this software and associated documentation files (the "Software"), to
22# deal in the Software without restriction, including without limitation the
23# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
24# sell copies of the Software, and to permit persons to whom the Software is
25# furnished to do so, subject to the following conditions:
26#
27# The above copyright notice and this permission notice shall be included in
28# all copies or substantial portions of the Software.
29#
30# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
33# ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
35# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
36# IN THE SOFTWARE.
37#
38# Except as contained in this notice, the name(s) of the above copyright
39# holders shall not be used in advertising or otherwise to promote the sale,
40# use or other dealings in this Software without prior written authorization.
41# -----------------------------------------------------------------------------
42# FSF changes to this file are in the public domain.
43#
44# Calling this script install-sh is preferred over install.sh, to prevent
45# 'make' implicit rules from creating a file called install from it
46# when there is no Makefile.
47#
48# This script is compatible with the BSD install script, but was written
49# from scratch.
50
51tab='	'
52nl='
53'
54IFS=" $tab$nl"
55
56# Set DOITPROG to "echo" to test this script.
57
58doit=${DOITPROG-}
59doit_exec=${doit:-exec}
60
61# Put in absolute file names if you don't have them in your path;
62# or use environment vars.
63
64chgrpprog=${CHGRPPROG-chgrp}
65chmodprog=${CHMODPROG-chmod}
66chownprog=${CHOWNPROG-chown}
67cmpprog=${CMPPROG-cmp}
68cpprog=${CPPROG-cp}
69mkdirprog=${MKDIRPROG-mkdir}
70mvprog=${MVPROG-mv}
71rmprog=${RMPROG-rm}
72stripprog=${STRIPPROG-strip}
73
74posix_mkdir=
75
76# Desired mode of installed file.
77mode=0755
78
79# Create dirs (including intermediate dirs) using mode 755.
80# This is like GNU 'install' as of coreutils 8.32 (2020).
81mkdir_umask=22
82
83backupsuffix=
84chgrpcmd=
85chmodcmd=$chmodprog
86chowncmd=
87mvcmd=$mvprog
88rmcmd="$rmprog -f"
89stripcmd=
90
91src=
92dst=
93dir_arg=
94dst_arg=
95
96copy_on_change=false
97is_target_a_directory=possibly
98
99usage="\
100Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
101   or: $0 [OPTION]... SRCFILES... DIRECTORY
102   or: $0 [OPTION]... -t DIRECTORY SRCFILES...
103   or: $0 [OPTION]... -d DIRECTORIES...
104
105In the 1st form, copy SRCFILE to DSTFILE.
106In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
107In the 4th, create DIRECTORIES.
108
109Options:
110     --help     display this help and exit.
111     --version  display version info and exit.
112
113  -c            (ignored)
114  -C            install only if different (preserve data modification time)
115  -d            create directories instead of installing files.
116  -g GROUP      $chgrpprog installed files to GROUP.
117  -m MODE       $chmodprog installed files to MODE.
118  -o USER       $chownprog installed files to USER.
119  -p            pass -p to $cpprog.
120  -s            $stripprog installed files.
121  -S SUFFIX     attempt to back up existing files, with suffix SUFFIX.
122  -t DIRECTORY  install into DIRECTORY.
123  -T            report an error if DSTFILE is a directory.
124
125Environment variables override the default commands:
126  CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
127  RMPROG STRIPPROG
128
129By default, rm is invoked with -f; when overridden with RMPROG,
130it's up to you to specify -f if you want it.
131
132If -S is not specified, no backups are attempted.
133
134Email bug reports to bug-automake@gnu.org.
135Automake home page: https://www.gnu.org/software/automake/
136"
137
138while test $# -ne 0; do
139  case $1 in
140    -c) ;;
141
142    -C) copy_on_change=true;;
143
144    -d) dir_arg=true;;
145
146    -g) chgrpcmd="$chgrpprog $2"
147        shift;;
148
149    --help) echo "$usage"; exit $?;;
150
151    -m) mode=$2
152        case $mode in
153          *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*)
154            echo "$0: invalid mode: $mode" >&2
155            exit 1;;
156        esac
157        shift;;
158
159    -o) chowncmd="$chownprog $2"
160        shift;;
161
162    -p) cpprog="$cpprog -p";;
163
164    -s) stripcmd=$stripprog;;
165
166    -S) backupsuffix="$2"
167        shift;;
168
169    -t)
170        is_target_a_directory=always
171        dst_arg=$2
172        # Protect names problematic for 'test' and other utilities.
173        case $dst_arg in
174          -* | [=\(\)!]) dst_arg=./$dst_arg;;
175        esac
176        shift;;
177
178    -T) is_target_a_directory=never;;
179
180    --version) echo "$0 $scriptversion"; exit $?;;
181
182    --) shift
183        break;;
184
185    -*) echo "$0: invalid option: $1" >&2
186        exit 1;;
187
188    *)  break;;
189  esac
190  shift
191done
192
193# We allow the use of options -d and -T together, by making -d
194# take the precedence; this is for compatibility with GNU install.
195
196if test -n "$dir_arg"; then
197  if test -n "$dst_arg"; then
198    echo "$0: target directory not allowed when installing a directory." >&2
199    exit 1
200  fi
201fi
202
203if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
204  # When -d is used, all remaining arguments are directories to create.
205  # When -t is used, the destination is already specified.
206  # Otherwise, the last argument is the destination.  Remove it from $@.
207  for arg
208  do
209    if test -n "$dst_arg"; then
210      # $@ is not empty: it contains at least $arg.
211      set fnord "$@" "$dst_arg"
212      shift # fnord
213    fi
214    shift # arg
215    dst_arg=$arg
216    # Protect names problematic for 'test' and other utilities.
217    case $dst_arg in
218      -* | [=\(\)!]) dst_arg=./$dst_arg;;
219    esac
220  done
221fi
222
223if test $# -eq 0; then
224  if test -z "$dir_arg"; then
225    echo "$0: no input file specified." >&2
226    exit 1
227  fi
228  # It's OK to call 'install-sh -d' without argument.
229  # This can happen when creating conditional directories.
230  exit 0
231fi
232
233if test -z "$dir_arg"; then
234  if test $# -gt 1 || test "$is_target_a_directory" = always; then
235    if test ! -d "$dst_arg"; then
236      echo "$0: $dst_arg: Is not a directory." >&2
237      exit 1
238    fi
239  fi
240fi
241
242if test -z "$dir_arg"; then
243  do_exit='(exit $ret); exit $ret'
244  trap "ret=129; $do_exit" 1
245  trap "ret=130; $do_exit" 2
246  trap "ret=141; $do_exit" 13
247  trap "ret=143; $do_exit" 15
248
249  # Set umask so as not to create temps with too-generous modes.
250  # However, 'strip' requires both read and write access to temps.
251  case $mode in
252    # Optimize common cases.
253    *644) cp_umask=133;;
254    *755) cp_umask=22;;
255
256    *[0-7])
257      if test -z "$stripcmd"; then
258        u_plus_rw=
259      else
260        u_plus_rw='% 200'
261      fi
262      cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
263    *)
264      if test -z "$stripcmd"; then
265        u_plus_rw=
266      else
267        u_plus_rw=,u+rw
268      fi
269      cp_umask=$mode$u_plus_rw;;
270  esac
271fi
272
273for src
274do
275  # Protect names problematic for 'test' and other utilities.
276  case $src in
277    -* | [=\(\)!]) src=./$src;;
278  esac
279
280  if test -n "$dir_arg"; then
281    dst=$src
282    dstdir=$dst
283    test -d "$dstdir"
284    dstdir_status=$?
285    # Don't chown directories that already exist.
286    if test $dstdir_status = 0; then
287      chowncmd=""
288    fi
289  else
290
291    # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
292    # might cause directories to be created, which would be especially bad
293    # if $src (and thus $dsttmp) contains '*'.
294    if test ! -f "$src" && test ! -d "$src"; then
295      echo "$0: $src does not exist." >&2
296      exit 1
297    fi
298
299    if test -z "$dst_arg"; then
300      echo "$0: no destination specified." >&2
301      exit 1
302    fi
303    dst=$dst_arg
304
305    # If destination is a directory, append the input filename.
306    if test -d "$dst"; then
307      if test "$is_target_a_directory" = never; then
308        echo "$0: $dst_arg: Is a directory" >&2
309        exit 1
310      fi
311      dstdir=$dst
312      dstbase=`basename "$src"`
313      case $dst in
314	*/) dst=$dst$dstbase;;
315	*)  dst=$dst/$dstbase;;
316      esac
317      dstdir_status=0
318    else
319      dstdir=`dirname "$dst"`
320      test -d "$dstdir"
321      dstdir_status=$?
322    fi
323  fi
324
325  case $dstdir in
326    */) dstdirslash=$dstdir;;
327    *)  dstdirslash=$dstdir/;;
328  esac
329
330  obsolete_mkdir_used=false
331
332  if test $dstdir_status != 0; then
333    case $posix_mkdir in
334      '')
335        # With -d, create the new directory with the user-specified mode.
336        # Otherwise, rely on $mkdir_umask.
337        if test -n "$dir_arg"; then
338          mkdir_mode=-m$mode
339        else
340          mkdir_mode=
341        fi
342
343        posix_mkdir=false
344	# The $RANDOM variable is not portable (e.g., dash).  Use it
345	# here however when possible just to lower collision chance.
346	tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
347
348	trap '
349	  ret=$?
350	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
351	  exit $ret
352	' 0
353
354	# Because "mkdir -p" follows existing symlinks and we likely work
355	# directly in world-writeable /tmp, make sure that the '$tmpdir'
356	# directory is successfully created first before we actually test
357	# 'mkdir -p'.
358	if (umask $mkdir_umask &&
359	    $mkdirprog $mkdir_mode "$tmpdir" &&
360	    exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
361	then
362	  if test -z "$dir_arg" || {
363	       # Check for POSIX incompatibilities with -m.
364	       # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
365	       # other-writable bit of parent directory when it shouldn't.
366	       # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
367	       test_tmpdir="$tmpdir/a"
368	       ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
369	       case $ls_ld_tmpdir in
370		 d????-?r-*) different_mode=700;;
371		 d????-?--*) different_mode=755;;
372		 *) false;;
373	       esac &&
374	       $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
375		 ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
376		 test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
377	       }
378	     }
379	  then posix_mkdir=:
380	  fi
381	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
382	else
383	  # Remove any dirs left behind by ancient mkdir implementations.
384	  rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
385	fi
386	trap '' 0;;
387    esac
388
389    if
390      $posix_mkdir && (
391        umask $mkdir_umask &&
392        $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
393      )
394    then :
395    else
396
397      # mkdir does not conform to POSIX,
398      # or it failed possibly due to a race condition.  Create the
399      # directory the slow way, step by step, checking for races as we go.
400
401      case $dstdir in
402        /*) prefix='/';;
403        [-=\(\)!]*) prefix='./';;
404        *)  prefix='';;
405      esac
406
407      oIFS=$IFS
408      IFS=/
409      set -f
410      set fnord $dstdir
411      shift
412      set +f
413      IFS=$oIFS
414
415      prefixes=
416
417      for d
418      do
419        test X"$d" = X && continue
420
421        prefix=$prefix$d
422        if test -d "$prefix"; then
423          prefixes=
424        else
425          if $posix_mkdir; then
426            (umask $mkdir_umask &&
427             $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
428            # Don't fail if two instances are running concurrently.
429            test -d "$prefix" || exit 1
430          else
431            case $prefix in
432              *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
433              *) qprefix=$prefix;;
434            esac
435            prefixes="$prefixes '$qprefix'"
436          fi
437        fi
438        prefix=$prefix/
439      done
440
441      if test -n "$prefixes"; then
442        # Don't fail if two instances are running concurrently.
443        (umask $mkdir_umask &&
444         eval "\$doit_exec \$mkdirprog $prefixes") ||
445          test -d "$dstdir" || exit 1
446        obsolete_mkdir_used=true
447      fi
448    fi
449  fi
450
451  if test -n "$dir_arg"; then
452    { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
453    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
454    { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
455      test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
456  else
457
458    # Make a couple of temp file names in the proper directory.
459    dsttmp=${dstdirslash}_inst.$$_
460    rmtmp=${dstdirslash}_rm.$$_
461
462    # Trap to clean up those temp files at exit.
463    trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
464
465    # Copy the file name to the temp name.
466    (umask $cp_umask &&
467     { test -z "$stripcmd" || {
468	 # Create $dsttmp read-write so that cp doesn't create it read-only,
469	 # which would cause strip to fail.
470	 if test -z "$doit"; then
471	   : >"$dsttmp" # No need to fork-exec 'touch'.
472	 else
473	   $doit touch "$dsttmp"
474	 fi
475       }
476     } &&
477     $doit_exec $cpprog "$src" "$dsttmp") &&
478
479    # and set any options; do chmod last to preserve setuid bits.
480    #
481    # If any of these fail, we abort the whole thing.  If we want to
482    # ignore errors from any of these, just make sure not to ignore
483    # errors from the above "$doit $cpprog $src $dsttmp" command.
484    #
485    { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
486    { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
487    { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
488    { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
489
490    # If -C, don't bother to copy if it wouldn't change the file.
491    if $copy_on_change &&
492       old=`LC_ALL=C ls -dlL "$dst"     2>/dev/null` &&
493       new=`LC_ALL=C ls -dlL "$dsttmp"  2>/dev/null` &&
494       set -f &&
495       set X $old && old=:$2:$4:$5:$6 &&
496       set X $new && new=:$2:$4:$5:$6 &&
497       set +f &&
498       test "$old" = "$new" &&
499       $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
500    then
501      rm -f "$dsttmp"
502    else
503      # If $backupsuffix is set, and the file being installed
504      # already exists, attempt a backup.  Don't worry if it fails,
505      # e.g., if mv doesn't support -f.
506      if test -n "$backupsuffix" && test -f "$dst"; then
507        $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
508      fi
509
510      # Rename the file to the real destination.
511      $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
512
513      # The rename failed, perhaps because mv can't rename something else
514      # to itself, or perhaps because mv is so ancient that it does not
515      # support -f.
516      {
517        # Now remove or move aside any old file at destination location.
518        # We try this two ways since rm can't unlink itself on some
519        # systems and the destination file might be busy for other
520        # reasons.  In this case, the final cleanup might fail but the new
521        # file should still install successfully.
522        {
523          test ! -f "$dst" ||
524          $doit $rmcmd "$dst" 2>/dev/null ||
525          { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
526            { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
527          } ||
528          { echo "$0: cannot unlink or rename $dst" >&2
529            (exit 1); exit 1
530          }
531        } &&
532
533        # Now rename the file to the real destination.
534        $doit $mvcmd "$dsttmp" "$dst"
535      }
536    fi || exit 1
537
538    trap '' 0
539  fi
540done
541
542# Local variables:
543# eval: (add-hook 'before-save-hook 'time-stamp)
544# time-stamp-start: "scriptversion="
545# time-stamp-format: "%:y-%02m-%02d.%02H"
546# time-stamp-time-zone: "UTC0"
547# time-stamp-end: "; # UTC"
548# End:
549