Fix -S with -b not atomically updating the destination file.

With both of these flags, the backup was created via rename(dest, backup)
followed by rename(tmp, dest).  This left the destination file missing
for a moment which contradicts the point of -S.

This fixes a race with installworld where PRECIOUSPROG and PRECIOUSLIB
files (which use -S for installation) would briefly be missing.  In the
case of installing rtld with parallel installworld it could render an
error due to not having rtld present to run install/cp in another
process.

Reported by:	jhb
Reviewed by:	jhb
MFC after:	1 week
Sponsored by:	EMC / Isilon Storage Division
Differential Revision:	https://reviews.freebsd.org/D7451
This commit is contained in:
bdrewery 2016-08-10 18:19:02 +00:00
parent e96f85f48f
commit 032a51f8f0

View File

@ -892,11 +892,17 @@ install(const char *from_name, const char *to_name, u_long fset, u_int flags)
}
if (verbose)
(void)printf("install: %s -> %s\n", to_name, backup);
if (rename(to_name, backup) < 0) {
if (unlink(backup) < 0 && errno != ENOENT) {
serrno = errno;
unlink(tempfile);
errno = serrno;
err(EX_OSERR, "rename: %s to %s", to_name,
err(EX_OSERR, "unlink: %s", backup);
}
if (link(to_name, backup) < 0) {
serrno = errno;
unlink(tempfile);
errno = serrno;
err(EX_OSERR, "link: %s to %s", to_name,
backup);
}
}