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