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