diff mbox series

[5/6] Makefile: use "ln -f" instead of "rm && ln"

Message ID patch-5.7-f81708f6120-20210329T162327Z-avarab@gmail.com (mailing list archive)
State New, archived
Headers show
Series Makefile: make non-symlink & non-hardlink install sane | expand

Commit Message

Ævar Arnfjörð Bjarmason March 29, 2021, 4:31 p.m. UTC
Change the invocations and behavior of "ln-or-cp.sh" to not assume
that we're going to "rm" the file in question beforehand.

This reduces the complexity of these rules, and as a bonus means it's
now safe to "make install" on a system that may have running "git"
programs, before this we'd be racing the "rm && ln/cp" and wouldn't
have a working "git" (or one of the built-ins) in the interim.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 Makefile    | 10 ++--------
 ln-or-cp.sh |  5 ++---
 2 files changed, 4 insertions(+), 11 deletions(-)

Comments

Junio C Hamano March 29, 2021, 10:46 p.m. UTC | #1
Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:

> Change the invocations and behavior of "ln-or-cp.sh" to not assume
> that we're going to "rm" the file in question beforehand.
>
> This reduces the complexity of these rules, and as a bonus means it's
> now safe to "make install" on a system that may have running "git"
> programs, before this we'd be racing the "rm && ln/cp" and wouldn't
> have a working "git" (or one of the built-ins) in the interim.

Neither link(2) nor symlink(2) has the equivalent of the -f flag, so
"ln [-s] -f" has to be implemented as an unlink(2) followed by
link(2) or symlink(2) anyway, so you didn't solve the "racing"
problem (if that is a problem in the first place, that is), did you?

The only reason why "rm -f t && ln s t" makes sense over "ln -f s t"
is because there could be a leftover 't' directory from a previous
build or rogue testing process or whatever.  It avoids creating a
hardlink at t/s, unlike "ln -f s t" which would happily do so.  It
would let us notice there is something fishy going on by failing to
remove the stray directory that should not exist.

I do not object to replace "rm then ln" with "ln -f", as the "be
cautious against somebody mistakenly making a directory there" is
not something I find valuable all that much.

But I do not want to be associated with a commit that claims that
"ln -f" avoids race in "rm && ln" ;-).

Thanks.
diff mbox series

Patch

diff --git a/Makefile b/Makefile
index 29d9bade5a8..466df1a8e90 100644
--- a/Makefile
+++ b/Makefile
@@ -2204,8 +2204,7 @@  version.sp version.s version.o: EXTRA_CPPFLAGS = \
 
 $(BUILT_INS): GIT-LNCPFLAGS
 $(BUILT_INS): git$X
-	$(QUIET_BUILT_IN)$(RM) $@ && \
-	./ln-or-cp.sh \
+	$(QUIET_BUILT_IN)./ln-or-cp.sh \
 		--install-symlinks "$(INSTALL_SYMLINKS)" \
 		$< $@
 
@@ -2558,8 +2557,7 @@  git-http-push$X: http.o http-push.o GIT-LDFLAGS $(GITLIBS)
 
 $(REMOTE_CURL_ALIASES): GIT-LNCPFLAGS
 $(REMOTE_CURL_ALIASES): $(REMOTE_CURL_PRIMARY)
-	$(QUIET_LNCP)$(RM) $@ && \
-	./ln-or-cp.sh \
+	$(QUIET_LNCP)./ln-or-cp.sh \
 		--install-symlinks "$(INSTALL_SYMLINKS)" \
 		$< $@
 
@@ -3021,7 +3019,6 @@  endif
 	destdir_from_execdir_SQ=$$(echo '$(gitexecdir_relative_SQ)' | sed -e 's|[^/][^/]*|..|g') && \
 	{ test "$$bindir/" = "$$execdir/" || \
 	  for p in git$X $(filter $(install_bindir_programs),$(ALL_PROGRAMS)); do \
-		$(RM) "$$execdir/$$p" && \
 		./ln-or-cp.sh \
 			--install-symlinks "$(INSTALL_SYMLINKS)" \
 			--no-install-hardlinks "$(NO_INSTALL_HARDLINKS)" \
@@ -3031,7 +3028,6 @@  endif
 	  done; \
 	} && \
 	for p in $(filter $(install_bindir_programs),$(BUILT_INS)); do \
-		$(RM) "$$bindir/$$p" && \
 		./ln-or-cp.sh \
 			--install-symlinks "$(INSTALL_SYMLINKS)" \
 			--no-install-hardlinks "$(NO_INSTALL_HARDLINKS)" \
@@ -3039,7 +3035,6 @@  endif
 			"$$bindir/git$X" "$$bindir/$$p"; \
 	done && \
 	for p in $(BUILT_INS); do \
-		$(RM) "$$execdir/$$p" && \
 		if test -z "$(SKIP_DASHED_BUILT_INS)"; \
 		then \
 			./ln-or-cp.sh \
@@ -3051,7 +3046,6 @@  endif
 	done && \
 	remote_curl_aliases="$(REMOTE_CURL_ALIASES)" && \
 	for p in $$remote_curl_aliases; do \
-		$(RM) "$$execdir/$$p" && \
 		./ln-or-cp.sh \
 			--install-symlinks "$(INSTALL_SYMLINKS)" \
 			--no-install-hardlinks "$(NO_INSTALL_HARDLINKS)" \
diff --git a/ln-or-cp.sh b/ln-or-cp.sh
index 663ffd0489d..37380993c64 100755
--- a/ln-or-cp.sh
+++ b/ln-or-cp.sh
@@ -40,11 +40,10 @@  link="$2"
 hardlink_or_cp () {
 	if test -z "$no_install_hardlinks" -a -z "$no_cross_directory_hardlinks"
 	then
-		if ! ln "$target" "$link"
+		if ! ln -f "$target" "$link"
 		then
 			cp "$target" "$link"
 		fi
-
 	else
 		cp "$target" "$link"
 	fi
@@ -53,7 +52,7 @@  hardlink_or_cp () {
 main_with_fallbacks () {
 	if test -n "$install_symlinks" -o -n "$no_install_hardlinks"
 	then
-		if ! ln -s "$symlink_target" "$link"
+		if ! ln -f -s "$symlink_target" "$link"
 		then
 			hardlink_or_cp
 		fi