Subject: [PATCH] sync: use syncfs(2) if any argument is specified

From: Giuseppe Scrivano <[email-masked]>
Date: Sun, 25 Jan 2015 14:03:04 +0100

* configure.ac: Check if syncfs(2) is available.
* NEWS: Mention the new feature.
* doc/coreutils.texi (sync invocation): Document the new feature.
* src/sync.c (usage): Describe that arguments are now accepted.
(main): Use syncfs(2) to flush buffers for the file system which
contain the specified arguments.  Silently fallback to sync(2) on
errors.
---

I've amended the suggested fixes in this version.

 NEWS               |  3 +++
 configure.ac       |  2 ++
 doc/coreutils.texi |  7 ++++++-
 src/sync.c         | 37 +++++++++++++++++++++++++++++++++++--
 4 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index e0a2893..611fde6 100644
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   split accepts a new --separator option to select a record separator character
   other than the default newline character.
 
+  sync no longer ignores arguments, and now uses syncfs(2) to sync
+  the file systems associated with each specified path.
+
 ** Changes in behavior
 
   df no longer suppresses separate exports of the same remote device, as
diff --git a/configure.ac b/configure.ac
index 3918f43..8fcfec9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -328,6 +328,8 @@ if test $ac_cv_func_syslog = no; then
   done
 fi
 
+AC_CHECK_FUNCS([syncfs])
+
 AC_CACHE_CHECK([for 3-argument setpriority function],
   [utils_cv_func_setpriority],
   [AC_LINK_IFELSE(
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 5a3c31a..6cc7414 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12053,6 +12053,10 @@ crashes, data may be lost or the file system corrupted as a
 result.  The @command{sync} command ensures everything in memory
 is written to disk.
 
+If any argument is specified and the system supports the synfcs(2)
+syscall, then only the file systems containing these paths will be
+synchronized.  If multiple paths point to the same file system, the
+syncfs(2) syscall will be invoked for each one of them.
 Any arguments are ignored, except for a lone @option{--help} or
 @option{--version} (@pxref{Common options}).
 
@@ -12081,7 +12085,8 @@ If a @var{file} is larger than the specified size, the extra data is lost.
 If a @var{file} is shorter, it is extended and the extended part (or hole)
 reads as zero bytes.
 
-The program accepts the following options.  Also see @ref{Common options}.
+The only options are a lone @option{--help} or @option{--version}.
+@xref{Common options}.
 
 @table @samp
 
diff --git a/src/sync.c b/src/sync.c
index e9f4d7e..c160e54 100644
--- a/src/sync.c
+++ b/src/sync.c
@@ -37,10 +37,13 @@ usage (int status)
     emit_try_help ();
   else
     {
-      printf (_("Usage: %s [OPTION]\n"), program_name);
+      printf (_("Usage: %s [OPTION] [PATH]...\n"), program_name);
       fputs (_("\
 Force changed blocks to disk, update the super block.\n\
 \n\
+If one or more file paths are specified, update only the\n\
+file-systems which contain those files.\n\
+\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -52,6 +55,7 @@ Force changed blocks to disk, update the super block.\n\
 int
 main (int argc, char **argv)
 {
+  bool args_specified;
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
   setlocale (LC_ALL, "");
@@ -65,7 +69,36 @@ main (int argc, char **argv)
   if (getopt_long (argc, argv, "", NULL, NULL) != -1)
     usage (EXIT_FAILURE);
 
-  if (optind < argc)
+  args_specified = optind < argc;
+
+#if HAVE_SYNCFS
+  /* If arguments are specified, use syncfs on each of them.
+     On any error, silently fallback to sync.  */
+  if (args_specified)
+    {
+      while (optind < argc)
+        {
+          int fd = open (argv[optind], O_RDONLY);
+          if (fd < 0)
+            goto sync;
+
+          if (syncfs (fd) < 0)
+            {
+              close (fd);
+              goto sync;
+            }
+
+          if (close (fd) < 0)
+            goto sync;
+
+          optind++;
+        }
+      return EXIT_SUCCESS;
+    }
+#endif
+
+sync:
+  if (args_specified)
     error (0, 0, _("ignoring all arguments"));
 
   sync ();
-- 
2.1.0