xref: /freebsd/contrib/bmake/mk/install-sh (revision f126890ac5386406dadf7c4cfa9566cbb56537c5)
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# SPDX-License-Identifier: BSD-2-Clause
57#
58# RCSid:
59#	$Id: install-sh,v 1.26 2024/02/17 17:26:57 sjg Exp $
60#
61#	@(#) Copyright (c) 1993-2023 Simon J. Gerraty
62#
63#	This file is provided in the hope that it will
64#	be of use.  There is absolutely NO WARRANTY.
65#	Permission to copy, redistribute or otherwise
66#	use this file is hereby granted provided that
67#	the above copyright notice and this notice are
68#	left intact.
69#
70#	Please send copies of changes and bug-fixes to:
71#	sjg@crufty.net
72#
73
74set -- `getopt B:bpxCNcsdo:g:m:i:f: $*`
75
76Mydir=`dirname $0`
77[ -s $Mydir/.installrc ] && . $Mydir/.installrc
78
79OLD_EXT=.old
80owner=:
81group=:
82mode=:
83MODE=0
84strip=:
85mkdirs=
86compare=:
87newer=:
88chflags=:
89LS_1=
90CP_p=
91
92while :
93do
94	case "$1" in
95	--)	shift; break;;
96	-[bc])	;; # ignore
97	-p)	CP_p=-p;;
98	-x)	set -x;;
99	-B)	OLD_EXT=$2; shift;;
100	-C)	compare=Different;;
101	-N)	newer=Newer;
102		# check if /bin/ls supports -1
103		'ls' -1 $0 > /dev/null 2>&1 && LS_1=1
104		;;
105	-o)	owner="${CHOWN:-chown} $2 "; shift;;
106	-g)	group="${CHGRP:-chgrp} $2 "; shift;;
107	-m)	MODE=$2 mode="${CHMOD:-chmod} $2 "; shift;;
108	-s)	strip=${STRIP:-strip};;
109	-d)	mkdirs="mkdir -p";;
110	-i)	ignore_err="$ignore_err$2"; shift;;
111	-f)	chflags="${CHFLAGS:-chflags} $2 "; shift;;
112	*)	break;;
113	esac
114	shift
115done
116
117Newer() {
118	n=`'ls' -t$LS_1 $* 2> /dev/null | head -1`
119	[ $1 = $n ]
120}
121
122Different() {
123	cmp -s $*
124	[ $? != 0 ]
125}
126
127Err() {
128	case "$ignore_err" in
129	*$1*)	;;
130	*)	exit 1;;
131	esac
132}
133
134Setem() {
135	# the order is important
136	if [ ! -d $1 ]; then
137		$strip $1 || Err s
138	fi
139	$group $1 || Err g
140	$owner $1 || Err o
141	$mode  $1 || Err m
142	$chflags $1 || Err f
143	return 0
144}
145
146# a bug in HP-UX's /bin/sh, means we need to re-set $*
147# after any calls to add_path()
148args="$*"
149
150add_path () {
151	test -d $1 || return
152	case ":$PATH:" in
153	*:$1:*) return;;
154	esac
155	PATH=$PATH:$1
156}
157
158add_path /sbin
159add_path /usr/sbin
160
161case "$owner" in
162:)	;;
163*)	# some systems put chown in odd places
164	add_path /etc
165	add_path /usr/etc
166	;;
167esac
168
169# restore saved $*
170set -- $args
171
172# make directories if needed
173# and ensure mode etc are as desired
174if [ "$mkdirs" ]; then
175	case "$MODE" in
176	[1-7]*)
177		# make sure umask is compatible
178		case "$MODE" in
179		????*) MODE=`echo $MODE | sed 's,.*\(...\)$,\1,'`;;
180		esac
181		umask `expr 0777 - 0$MODE |
182		sed 's,^,000,;s,^.*\(...\)$,\1,'`;;
183	esac
184	for d in $*
185	do
186		[ ! -d $d ] && $mkdirs $d
187		Setem $d
188	done
189	exit 0			# that's all we do
190fi
191
192# install files
193if [ $# -eq 1 ]; then
194	echo "what should I do with $*?" >&2
195	exit 1
196fi
197
198# get list of files
199files=
200while [ $# -gt 1 ]
201do
202	test "x$files" = x || dest_dir=yes
203	files="$files $1"
204	shift
205done
206# last one is dest
207dest=$1
208shift
209
210if [ "$dest_dir" = yes -a  ! -d $dest ]; then
211	echo "no directory $dest" >&2
212	exit 1
213fi
214
215for f in $files
216do
217	b=`basename $f`
218	if [ -d $dest ]; then
219		t=$dest/$b
220	else
221		t=$dest
222	fi
223	$newer $f $t || continue
224	$compare $f $t || continue
225	[ -f $t ] && { mv -f $t $t$OLD_EXT || exit 1; }
226	{ cp $CP_p $f $t && Setem $t; } || exit 1
227done
228exit 0
229