install-sh 15 KB

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