xref: /freebsd/contrib/bmake/install-sh (revision c8e7f78a3d28ff6e6223ed136ada8e1e2f34965e)
1#!/bin/sh
2
3# NAME:
4#	install.sh - portable version of install(1)
5#
6# SYNOPSIS:
7#	install [-CNcs] [-f flags] [-i errs] [-o owner] [-g group] [-m mode] file1 file2 ...
8#	install -d  [-i errs] [-o owner] [-g group] [-m mode] directory ...
9#
10# DESCRIPTION:
11#	Compatible with BSD install(1).  Except that '-c' is always
12#	true and we always move an already installed target aside as
13#	this is important on many systems.  Recent BSD install(1)
14#	versions have a '-b' option for this.
15#
16#
17# OPTIONS:
18#	-b	move previous target file aside (always true).
19#
20#	-B "suffix"
21#		use "suffix" instead of .old for saving existing target.
22#
23#	-c	copy rather than move the file into place (always true).
24#
25#	-C	compare.  Only install if target is missing or
26#		different.
27#
28#	-N	newer. Only install if target is missing or older.
29#
30#	-s	strip target
31#
32#	-o "owner"
33#		make target owned by "owner"
34#
35#	-g "group"
36#		make target group owned by "group"
37#
38#	-m "mode"
39#		set permissions to "mode"
40#
41#	-f "flags"
42#		Pass "flags" onto chflags(1)
43#
44#	-i "errs"
45#		Ignore errors from steps indicated by "errs" (``s,o,g,m'').
46#
47# BUGS:
48#	The '-i' option is to save your sanity when 'bsd.prog.mk'
49#	insists on haveing a '-o' "owner" option which is doomed to
50#	fail on many systems.  We ignore '-b' and '-c' options.
51#
52# AUTHOR:
53#	Simon J. Gerraty <sjg@crufty.net>
54#
55
56# RCSid:
57#	$Id: install-sh,v 1.25 2023/07/15 05:33:38 sjg Exp $
58#
59#	@(#) Copyright (c) 1993-2023 Simon J. Gerraty
60#
61#	This file is provided in the hope that it will
62#	be of use.  There is absolutely NO WARRANTY.
63#	Permission to copy, redistribute or otherwise
64#	use this file is hereby granted provided that
65#	the above copyright notice and this notice are
66#	left intact.
67#
68#	Please send copies of changes and bug-fixes to:
69#	sjg@crufty.net
70#
71
72set -- `getopt B:bpxCNcsdo:g:m:i:f: $*`
73
74Mydir=`dirname $0`
75[ -s $Mydir/.installrc ] && . $Mydir/.installrc
76
77OLD_EXT=.old
78owner=:
79group=:
80mode=:
81MODE=0
82strip=:
83mkdirs=
84compare=:
85newer=:
86chflags=:
87LS_1=
88CP_p=
89
90while :
91do
92	case "$1" in
93	--)	shift; break;;
94	-[bc])	;; # ignore
95	-p)	CP_p=-p;;
96	-x)	set -x;;
97	-B)	OLD_EXT=$2; shift;;
98	-C)	compare=Different;;
99	-N)	newer=Newer;
100		# check if /bin/ls supports -1
101		'ls' -1 $0 > /dev/null 2>&1 && LS_1=1
102		;;
103	-o)	owner="${CHOWN:-chown} $2 "; shift;;
104	-g)	group="${CHGRP:-chgrp} $2 "; shift;;
105	-m)	MODE=$2 mode="${CHMOD:-chmod} $2 "; shift;;
106	-s)	strip=${STRIP:-strip};;
107	-d)	mkdirs="mkdir -p";;
108	-i)	ignore_err="$ignore_err$2"; shift;;
109	-f)	chflags="${CHFLAGS:-chflags} $2 "; shift;;
110	*)	break;;
111	esac
112	shift
113done
114
115Newer() {
116	n=`'ls' -t$LS_1 $* 2> /dev/null | head -1`
117	[ $1 = $n ]
118}
119
120Different() {
121	cmp -s $*
122	[ $? != 0 ]
123}
124
125Err() {
126	case "$ignore_err" in
127	*$1*)	;;
128	*)	exit 1;;
129	esac
130}
131
132Setem() {
133	# the order is important
134	if [ ! -d $1 ]; then
135		$strip $1 || Err s
136	fi
137	$group $1 || Err g
138	$owner $1 || Err o
139	$mode  $1 || Err m
140	$chflags $1 || Err f
141	return 0
142}
143
144# a bug in HP-UX's /bin/sh, means we need to re-set $*
145# after any calls to add_path()
146args="$*"
147
148add_path () {
149	test -d $1 || return
150	case ":$PATH:" in
151	*:$1:*) return;;
152	esac
153	PATH=$PATH:$1
154}
155
156add_path /sbin
157add_path /usr/sbin
158
159case "$owner" in
160:)	;;
161*)	# some systems put chown in odd places
162	add_path /etc
163	add_path /usr/etc
164	;;
165esac
166
167# restore saved $*
168set -- $args
169
170# make directories if needed
171# and ensure mode etc are as desired
172if [ "$mkdirs" ]; then
173	case "$MODE" in
174	[1-7]*)
175		# make sure umask is compatible
176		case "$MODE" in
177		????*) MODE=`echo $MODE | sed 's,.*\(...\)$,\1,'`;;
178		esac
179		umask `expr 0777 - 0$MODE |
180		sed 's,^,000,;s,^.*\(...\)$,\1,'`;;
181	esac
182	for d in $*
183	do
184		[ ! -d $d ] && $mkdirs $d
185		Setem $d
186	done
187	exit 0			# that's all we do
188fi
189
190# install files
191if [ $# -eq 1 ]; then
192	echo "what should I do with $*?" >&2
193	exit 1
194fi
195
196# get list of files
197files=
198while [ $# -gt 1 ]
199do
200	test "x$files" = x || dest_dir=yes
201	files="$files $1"
202	shift
203done
204# last one is dest
205dest=$1
206shift
207
208if [ "$dest_dir" = yes -a  ! -d $dest ]; then
209	echo "no directory $dest" >&2
210	exit 1
211fi
212
213for f in $files
214do
215	b=`basename $f`
216	if [ -d $dest ]; then
217		t=$dest/$b
218	else
219		t=$dest
220	fi
221	$newer $f $t || continue
222	$compare $f $t || continue
223	[ -f $t ] && { mv -f $t $t$OLD_EXT || exit 1; }
224	{ cp $CP_p $f $t && Setem $t; } || exit 1
225done
226exit 0
227