install has a "safe mode" -S option, although it's not as entirely safe as one
might assume. It relies on rename() being an atomic operation, which is good.
However, rename doesn't guarantee that a file's *contents* are on disk. Thus,
there is a window between the rename and the eventual flushing of the file's
data buffers where a crash will leave you with an incomplete file upon reboot.
Calling fsync() by default may be too expensive, and is probably unnecessary
for many files. But for some files, like libc, we may wish to be certain the
new file is committed before doing the rename. This adds a -F option to call
fsync.
Index: install.1
===================================================================
RCS file: /cvs/src/usr.bin/xinstall/install.1,v
retrieving revision 1.27
diff -u -p -r1.27 install.1
--- install.1 1 Feb 2016 15:54:58 -0000 1.27
+++ install.1 12 May 2016 19:50:56 -0000
@@ -38,7 +38,7 @@
.Nd install binaries
.Sh SYNOPSIS
.Nm install
-.Op Fl bCcDdpSs
+.Op Fl bCcDFdpSs
.Op Fl B Ar suffix
.Op Fl f Ar flags
.Op Fl g Ar group
@@ -105,6 +105,10 @@ This option cannot be used with the
or
.Fl s
options.
+.It Fl F
+Use
+.Xr fsync 2
+to ensure the created file is saved to disk.
.It Fl f Ar flags
Specify the target's file
.Ar flags .
Index: xinstall.c
===================================================================
RCS file: /cvs/src/usr.bin/xinstall/xinstall.c,v
retrieving revision 1.63
diff -u -p -r1.63 xinstall.c
--- xinstall.c 31 Dec 2015 16:16:54 -0000 1.63
+++ xinstall.c 12 May 2016 19:49:27 -0000
@@ -61,7 +61,7 @@
struct passwd *pp;
struct group *gp;
-int dobackup, docompare, dodest, dodir, dopreserve, dostrip, safecopy;
+int dobackup, docompare, dodest, dodir, dofsync, dopreserve, dostrip, safecopy;
int mode = S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
char pathbuf[PATH_MAX], tempfile[PATH_MAX];
char *suffix = BACKUP_SUFFIX;
@@ -90,7 +90,7 @@ main(int argc, char *argv[])
char *flags, *to_name, *group = NULL, *owner = NULL;
iflags = 0;
- while ((ch = getopt(argc, argv, "B:bCcDdf:g:m:o:pSs")) != -1)
+ while ((ch = getopt(argc, argv, "B:bCcDdFf:g:m:o:pSs")) != -1)
switch(ch) {
case 'C':
docompare = 1;
@@ -104,6 +104,9 @@ main(int argc, char *argv[])
case 'c':
/* For backwards compatibility. */
break;
+ case 'F':
+ dofsync = 1;
+ break;
case 'f':
flags = optarg;
if (strtofflags(&flags, &fset, NULL))
@@ -377,6 +380,8 @@ install(char *from_name, char *to_name,
safecopy ? tempfile :to_name, strerror(errno));
}
+ if (dofsync)
+ fsync(to_fd);
(void)close(to_fd);
if (!devnull)
(void)close(from_fd);
@@ -618,7 +623,7 @@ void
usage(void)
{
(void)fprintf(stderr, "\
-usage: install [-bCcDdpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o
owner]\n source ... target ...\n");
+usage: install [-bCcDdFpSs] [-B suffix] [-f flags] [-g group] [-m mode] [-o
owner]\n source ... target ...\n");
exit(1);
/* NOTREACHED */
}