886e95
From 0f92b1425c26adfaae1ff5bc70500bdeffdb9dba Mon Sep 17 00:00:00 2001
886e95
From: Giuseppe Scrivano <gscrivano@gnu.org>
886e95
Date: Sun, 25 Jan 2015 01:33:45 +0100
886e95
Subject: [PATCH 1/2] sync: support syncing specified arguments
886e95
886e95
* m4/jm-macros.m4 (coreutils_MACROS): Check for syncfs().
886e95
* man/sync.x: Add references to syncfs, fsync and fdatasync.
886e95
* doc/coreutils.texi (sync invocation): Document the new feature.
886e95
* src/sync.c: Include "quote.h".
886e95
(AUTHORS): Include myself.
886e95
(MODE_FILE, MODE_DATA, MODE_FILE_SYSTEM, MODE_SYNC): New enum values.
886e95
(long_options): Define.
886e95
(sync_arg): New function.
886e95
(usage): Describe that arguments are now accepted.
886e95
(main): Add arguments parsing and add support for fsync(2),
886e95
fdatasync(2) and syncfs(2).
886e95
* tests/misc/sync.sh: New (and only) test for sync.
886e95
* tests/local.mk: Reference the new test.
886e95
* AUTHORS: Add myself to sync's authors.
886e95
886e95
Upstream-commit: 8b2bf5295f353016d4f5e6a2317d55b6a8e7fd00
886e95
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
886e95
---
886e95
 AUTHORS            |   2 +-
886e95
 doc/coreutils.texi |  52 ++++++++++---
886e95
 m4/jm-macros.m4    |   1 +
886e95
 man/sync.x         |   4 +-
886e95
 src/sync.c         | 177 ++++++++++++++++++++++++++++++++++++++++++---
886e95
 tests/local.mk     |   1 +
886e95
 tests/misc/sync.sh |  50 +++++++++++++
886e95
 7 files changed, 262 insertions(+), 25 deletions(-)
886e95
 create mode 100755 tests/misc/sync.sh
886e95
886e95
diff --git a/AUTHORS b/AUTHORS
886e95
index df21e90..12b2196 100644
886e95
--- a/AUTHORS
886e95
+++ b/AUTHORS
886e95
@@ -82,7 +82,7 @@ stat: Michael Meskes
886e95
 stdbuf: Pádraig Brady
886e95
 stty: David MacKenzie
886e95
 sum: Kayvan Aghaiepour, David MacKenzie
886e95
-sync: Jim Meyering
886e95
+sync: Jim Meyering, Giuseppe Scrivano
886e95
 tac: Jay Lepreau, David MacKenzie
886e95
 tail: Paul Rubin, David MacKenzie, Ian Lance Taylor, Jim Meyering
886e95
 tee: Mike Parker, Richard M. Stallman, David MacKenzie
886e95
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
886e95
index 772aab6..28b42d0 100644
886e95
--- a/doc/coreutils.texi
886e95
+++ b/doc/coreutils.texi
886e95
@@ -111,7 +111,7 @@
886e95
 * stdbuf: (coreutils)stdbuf invocation.         Modify stdio buffering.
886e95
 * stty: (coreutils)stty invocation.             Print/change terminal settings.
886e95
 * sum: (coreutils)sum invocation.               Print traditional checksum.
886e95
-* sync: (coreutils)sync invocation.             Synchronize memory and disk.
886e95
+* sync: (coreutils)sync invocation.             Synchronize memory to disk.
886e95
 * tac: (coreutils)tac invocation.               Reverse files.
886e95
 * tail: (coreutils)tail invocation.             Output the last part of files.
886e95
 * tee: (coreutils)tee invocation.               Redirect to multiple files.
886e95
@@ -342,7 +342,7 @@ Disk usage
886e95
 * df invocation::                Report file system disk space usage
886e95
 * du invocation::                Estimate file space usage
886e95
 * stat invocation::              Report file or file system status
886e95
-* sync invocation::              Synchronize data on disk with memory
886e95
+* sync invocation::              Synchronize cached writes to persistent storage
886e95
 * truncate invocation::          Shrink or extend the size of a file
886e95
 
886e95
 Printing text
886e95
@@ -11097,7 +11097,7 @@ file status information, and write buffers to disk.
886e95
 * df invocation::               Report file system disk space usage.
886e95
 * du invocation::               Estimate file space usage.
886e95
 * stat invocation::             Report file or file system status.
886e95
-* sync invocation::             Synchronize memory and disk.
886e95
+* sync invocation::             Synchronize cached writes to persistent storage.
886e95
 * truncate invocation::         Shrink or extend the size of a file.
886e95
 @end menu
886e95
 
886e95
@@ -11927,28 +11927,60 @@ with @env{TZ}, libc, The GNU C Library Reference Manual}.
886e95
 
886e95
 
886e95
 @node sync invocation
886e95
-@section @command{sync}: Synchronize data on disk with memory
886e95
+@section @command{sync}: Synchronize cached writes to persistent storage
886e95
 
886e95
 @pindex sync
886e95
 @cindex synchronize disk and memory
886e95
+@cindex Synchronize cached writes to persistent storage
886e95
+
886e95
+@command{sync} synchronizes in memory files or file systems to persistent
886e95
+storage.  Synopsis:
886e95
+
886e95
+@example
886e95
+sync [@var{option}] [@var{file}]@dots{}
886e95
+@end example
886e95
 
886e95
 @cindex superblock, writing
886e95
 @cindex inodes, written buffered
886e95
 @command{sync} writes any data buffered in memory out to disk.  This can
886e95
 include (but is not limited to) modified superblocks, modified inodes,
886e95
 and delayed reads and writes.  This must be implemented by the kernel;
886e95
-The @command{sync} program does nothing but exercise the @code{sync} system
886e95
-call.
886e95
+The @command{sync} program does nothing but exercise the @code{sync},
886e95
+@code{syncfs}, @code{fsync}, and @code{fdatasync} system calls.
886e95
 
886e95
 @cindex crashes and corruption
886e95
 The kernel keeps data in memory to avoid doing (relatively slow) disk
886e95
 reads and writes.  This improves performance, but if the computer
886e95
 crashes, data may be lost or the file system corrupted as a
886e95
-result.  The @command{sync} command ensures everything in memory
886e95
-is written to disk.
886e95
+result.  The @command{sync} command instructs the kernel to write
886e95
+data in memory to persistent storage.
886e95
 
886e95
-Any arguments are ignored, except for a lone @option{--help} or
886e95
-@option{--version} (@pxref{Common options}).
886e95
+If any argument is specified then only those files will be
886e95
+synchronized using the fsync(2) syscall by default.
886e95
+
886e95
+If at least one file is specified, it is possible to change the
886e95
+synchronization method with the following options.  Also see
886e95
+@ref{Common options}.
886e95
+
886e95
+@table @samp
886e95
+@item -d
886e95
+@itemx --data
886e95
+@opindex --data
886e95
+Use fdatasync(2) to sync only the data for the file,
886e95
+and any metadata required to maintain file system consistency.
886e95
+
886e95
+@item -f
886e95
+@itemx --file-system
886e95
+@opindex --file-system
886e95
+Synchronize all the I/O waiting for the file systems that contain the file,
886e95
+using the syscall syncfs(2).  Note you would usually @emph{not} specify
886e95
+this option if passing a device node like @samp{/dev/sda} for example,
886e95
+as that would sync the containing file system rather than the referenced one.
886e95
+Note also that depending on the system, passing individual device nodes or files
886e95
+may have different sync characteristics than using no arguments.
886e95
+I.E. arguments passed to fsync(2) may provide greater guarantees through
886e95
+write barriers, than a global sync(2) used when no arguments are provided.
886e95
+@end table
886e95
 
886e95
 @exitstatus
886e95
 
886e95
diff --git a/m4/jm-macros.m4 b/m4/jm-macros.m4
886e95
index a84e3a3..b825e68 100644
886e95
--- a/m4/jm-macros.m4
886e95
+++ b/m4/jm-macros.m4
886e95
@@ -87,6 +87,7 @@ AC_DEFUN([coreutils_MACROS],
886e95
     sethostname
886e95
     siginterrupt
886e95
     sync
886e95
+    syncfs
886e95
     sysctl
886e95
     sysinfo
886e95
     tcgetpgrp
886e95
diff --git a/man/sync.x b/man/sync.x
886e95
index 7947bb7..79fee22 100644
886e95
--- a/man/sync.x
886e95
+++ b/man/sync.x
886e95
@@ -1,6 +1,6 @@
886e95
 [NAME]
886e95
-sync \- flush file system buffers
886e95
+sync \- Synchronize cached writes to persistent storage
886e95
 [DESCRIPTION]
886e95
 .\" Add any additional description here
886e95
 [SEE ALSO]
886e95
-sync(2)
886e95
+fdatasync(2), fsync(2), sync(2), syncfs(2)
886e95
diff --git a/src/sync.c b/src/sync.c
886e95
index 03b8e53..08ef6ff 100644
886e95
--- a/src/sync.c
886e95
+++ b/src/sync.c
886e95
@@ -17,18 +17,42 @@
886e95
 /* Written by Jim Meyering */
886e95
 
886e95
 #include <config.h>
886e95
+#include <assert.h>
886e95
 #include <getopt.h>
886e95
 #include <stdio.h>
886e95
 #include <sys/types.h>
886e95
 
886e95
 #include "system.h"
886e95
 #include "error.h"
886e95
-#include "long-options.h"
886e95
+#include "quote.h"
886e95
 
886e95
 /* The official name of this program (e.g., no 'g' prefix).  */
886e95
 #define PROGRAM_NAME "sync"
886e95
 
886e95
-#define AUTHORS proper_name ("Jim Meyering")
886e95
+#define AUTHORS                                 \
886e95
+  proper_name ("Jim Meyering"),                 \
886e95
+  proper_name ("Giuseppe Scrivano")
886e95
+
886e95
+#ifndef HAVE_SYNCFS
886e95
+# define HAVE_SYNCFS 0
886e95
+#endif
886e95
+
886e95
+enum sync_mode
886e95
+{
886e95
+  MODE_FILE,
886e95
+  MODE_DATA,
886e95
+  MODE_FILE_SYSTEM,
886e95
+  MODE_SYNC
886e95
+};
886e95
+
886e95
+static struct option const long_options[] =
886e95
+{
886e95
+  {"data", no_argument, NULL, 'd'},
886e95
+  {"file-system", no_argument, NULL, 'f'},
886e95
+  {GETOPT_HELP_OPTION_DECL},
886e95
+  {GETOPT_VERSION_OPTION_DECL},
886e95
+  {NULL, 0, NULL, 0}
886e95
+};
886e95
 
886e95
 void
886e95
 usage (int status)
886e95
@@ -37,11 +61,22 @@ usage (int status)
886e95
     emit_try_help ();
886e95
   else
886e95
     {
886e95
-      printf (_("Usage: %s [OPTION]\n"), program_name);
886e95
+      printf (_("Usage: %s [OPTION] [FILE]...\n"), program_name);
886e95
       fputs (_("\
886e95
-Force changed blocks to disk, update the super block.\n\
886e95
+Synchronize cached writes to persistent storage\n\
886e95
+\n\
886e95
+If one or more files are specified, sync only them,\n\
886e95
+or their containing file systems.\n\
886e95
 \n\
886e95
 "), stdout);
886e95
+
886e95
+      fputs (_("\
886e95
+  -d, --data             sync only file data, no unneeded metadata\n\
886e95
+"), stdout);
886e95
+      fputs (_("\
886e95
+  -f, --file-system      sync the file systems that contain the files\n\
886e95
+"), stdout);
886e95
+
886e95
       fputs (HELP_OPTION_DESCRIPTION, stdout);
886e95
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
886e95
       emit_ancillary_info ();
886e95
@@ -49,9 +84,86 @@ Force changed blocks to disk, update the super block.\n\
886e95
   exit (status);
886e95
 }
886e95
 
886e95
+/* Sync the specified FILE, or file systems associated with FILE.
886e95
+   Return 1 on success.  */
886e95
+
886e95
+static bool
886e95
+sync_arg (enum sync_mode mode, char const *file)
886e95
+{
886e95
+  bool ret = true;
886e95
+  int fd;
886e95
+
886e95
+  /* Note O_PATH might be supported with syncfs(),
886e95
+     though as of Linux 3.18 is not.  */
886e95
+  if ((fd = open (file, O_RDONLY | O_NONBLOCK)) < 0)
886e95
+    {
886e95
+      /* Use the O_RDONLY errno, which is significant
886e95
+         with directories for example.  */
886e95
+      int rd_errno = errno;
886e95
+      if ((fd = open (file, O_WRONLY | O_NONBLOCK)) < 0)
886e95
+        error (0, rd_errno, _("error opening %s"), quote (file));
886e95
+      return false;
886e95
+    }
886e95
+
886e95
+  /* We used O_NONBLOCK above to not hang with fifos,
886e95
+     so reset that here.  */
886e95
+  int fdflags;
886e95
+  if ((fdflags = fcntl (fd, F_GETFL)) == -1
886e95
+      || fcntl (fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
886e95
+    {
886e95
+      error (0, errno, _("couldn't reset non-blocking mode %s"), quote (file));
886e95
+      ret = false;
886e95
+    }
886e95
+
886e95
+  if (ret == true)
886e95
+    {
886e95
+      int sync_status = -1;
886e95
+
886e95
+      switch (mode)
886e95
+        {
886e95
+        case MODE_DATA:
886e95
+          sync_status = fdatasync (fd);
886e95
+          break;
886e95
+
886e95
+        case MODE_FILE:
886e95
+          sync_status = fsync (fd);
886e95
+          break;
886e95
+
886e95
+#if HAVE_SYNCFS
886e95
+        case MODE_FILE_SYSTEM:
886e95
+          sync_status = syncfs (fd);
886e95
+          break;
886e95
+#endif
886e95
+
886e95
+        default:
886e95
+          assert ("invalid sync_mode");
886e95
+        }
886e95
+
886e95
+      if (sync_status < 0)
886e95
+        {
886e95
+          error (0, errno, _("error syncing %s"), quote (file));
886e95
+          ret = false;
886e95
+        }
886e95
+    }
886e95
+
886e95
+  if (close (fd) < 0)
886e95
+    {
886e95
+      error (0, errno, _("failed to close %s"), quote (file));
886e95
+      ret = false;
886e95
+    }
886e95
+
886e95
+  return ret;
886e95
+}
886e95
+
886e95
 int
886e95
 main (int argc, char **argv)
886e95
 {
886e95
+  int c;
886e95
+  bool args_specified;
886e95
+  bool arg_data = false, arg_file_system = false;
886e95
+  enum sync_mode mode;
886e95
+  bool ok = true;
886e95
+
886e95
   initialize_main (&argc, &argv);
886e95
   set_program_name (argv[0]);
886e95
   setlocale (LC_ALL, "");
886e95
@@ -60,14 +172,55 @@ main (int argc, char **argv)
886e95
 
886e95
   atexit (close_stdout);
886e95
 
886e95
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE, Version,
886e95
-                      usage, AUTHORS, (char const *) NULL);
886e95
-  if (getopt_long (argc, argv, "", NULL, NULL) != -1)
886e95
-    usage (EXIT_FAILURE);
886e95
+  while ((c = getopt_long (argc, argv, "df", long_options, NULL))
886e95
+         != -1)
886e95
+    {
886e95
+      switch (c)
886e95
+        {
886e95
+        case 'd':
886e95
+          arg_data = true;
886e95
+          break;
886e95
+
886e95
+        case 'f':
886e95
+          arg_file_system = true;
886e95
+          break;
886e95
+
886e95
+        case_GETOPT_HELP_CHAR;
886e95
+
886e95
+        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
886e95
 
886e95
-  if (optind < argc)
886e95
-    error (0, 0, _("ignoring all arguments"));
886e95
+        default:
886e95
+          usage (EXIT_FAILURE);
886e95
+        }
886e95
+    }
886e95
+
886e95
+  args_specified = optind < argc;
886e95
+
886e95
+  if (arg_data && arg_file_system)
886e95
+    {
886e95
+      error (EXIT_FAILURE, 0,
886e95
+             _("cannot specify both --data and --file-system"));
886e95
+    }
886e95
+
886e95
+  if (!args_specified && arg_data)
886e95
+    error (EXIT_FAILURE, 0, _("--data needs at least one argument"));
886e95
+
886e95
+  if (! args_specified || (arg_file_system && ! HAVE_SYNCFS))
886e95
+    mode = MODE_SYNC;
886e95
+  else if (arg_file_system)
886e95
+    mode = MODE_FILE_SYSTEM;
886e95
+  else if (! arg_data)
886e95
+    mode = MODE_FILE;
886e95
+  else
886e95
+    mode = MODE_DATA;
886e95
+
886e95
+  if (mode == MODE_SYNC)
886e95
+    sync ();
886e95
+  else
886e95
+    {
886e95
+      for (; optind < argc; optind++)
886e95
+        ok &= sync_arg (mode, argv[optind]);
886e95
+    }
886e95
 
886e95
-  sync ();
886e95
-  exit (EXIT_SUCCESS);
886e95
+  return ok ? EXIT_SUCCESS : EXIT_FAILURE;
886e95
 }
886e95
diff --git a/tests/local.mk b/tests/local.mk
886e95
index 8487b3b..ba766b4 100644
886e95
--- a/tests/local.mk
886e95
+++ b/tests/local.mk
886e95
@@ -364,6 +364,7 @@ all_tests =					\
886e95
   tests/misc/stty-row-col.sh			\
886e95
   tests/misc/sum.pl				\
886e95
   tests/misc/sum-sysv.sh			\
886e95
+  tests/misc/sync.sh				\
886e95
   tests/misc/tac.pl				\
886e95
   tests/misc/tac-continue.sh			\
886e95
   tests/misc/tac-2-nonseekable.sh		\
886e95
diff --git a/tests/misc/sync.sh b/tests/misc/sync.sh
886e95
new file mode 100755
886e95
index 0000000..a204630
886e95
--- /dev/null
886e95
+++ b/tests/misc/sync.sh
886e95
@@ -0,0 +1,50 @@
886e95
+#!/bin/sh
886e95
+# Test various sync(1) operations
886e95
+
886e95
+# Copyright (C) 2015 Free Software Foundation, Inc.
886e95
+
886e95
+# This program is free software: you can redistribute it and/or modify
886e95
+# it under the terms of the GNU General Public License as published by
886e95
+# the Free Software Foundation, either version 3 of the License, or
886e95
+# (at your option) any later version.
886e95
+
886e95
+# This program is distributed in the hope that it will be useful,
886e95
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
886e95
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
886e95
+# GNU General Public License for more details.
886e95
+
886e95
+# You should have received a copy of the GNU General Public License
886e95
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
886e95
+
886e95
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
886e95
+print_ver_ sync
886e95
+
886e95
+touch file
886e95
+
886e95
+# fdatasync+syncfs is nonsensical
886e95
+returns_ 1 sync --data --file-system || fail=1
886e95
+
886e95
+# fdatasync needs an operand
886e95
+returns_ 1 sync -d || fail=1
886e95
+
886e95
+# Test syncing of file (fsync) (little side effects)
886e95
+sync file || fail=1
886e95
+
886e95
+# Ensure multiple args are processed and diagnosed
886e95
+returns_ 1 sync file nofile || fail=1
886e95
+
886e95
+# Ensure inaccessible dirs give an appropriate error
886e95
+mkdir norw || framework_failure_
886e95
+chmod 0 norw || framework_failure_
886e95
+sync norw 2>err
886e95
+printf "sync: error opening 'norw': Permission denied\n" >exp
886e95
+compare exp err || fail=1
886e95
+
886e95
+if test "$fail" != '1'; then
886e95
+  # Ensure a fifo doesn't block
886e95
+  mkfifo_or_skip_ fifo
886e95
+  timeout 10 sync fifo
886e95
+  test $? = 124 && fail=1
886e95
+fi
886e95
+
886e95
+Exit $fail
886e95
-- 
886e95
2.21.3
886e95
886e95
886e95
From 7b4398be327fa2ad0516ab92230d5856cc3f5098 Mon Sep 17 00:00:00 2001
886e95
From: Paul Eggert <eggert@cs.ucla.edu>
886e95
Date: Tue, 6 Nov 2018 10:35:16 -0800
886e95
Subject: [PATCH 2/2] sync: fix open fallback bug
886e95
886e95
Problem caught by Coverity Analysis
886e95
and reported by Kamil Dudka (Bug#33287).
886e95
* src/sync.c (sync_arg): Fix typo in fallback code.
886e95
886e95
Upstream-commit: 94d364f157f007f2b23c70863ac8eefe9b21229d
886e95
Signed-off-by: Kamil Dudka <kdudka@redhat.com>
886e95
---
886e95
 src/sync.c | 9 ++++++---
886e95
 1 file changed, 6 insertions(+), 3 deletions(-)
886e95
886e95
diff --git a/src/sync.c b/src/sync.c
886e95
index 08ef6ff..63d7e92 100644
886e95
--- a/src/sync.c
886e95
+++ b/src/sync.c
886e95
@@ -100,9 +100,12 @@ sync_arg (enum sync_mode mode, char const *file)
886e95
       /* Use the O_RDONLY errno, which is significant
886e95
          with directories for example.  */
886e95
       int rd_errno = errno;
886e95
-      if ((fd = open (file, O_WRONLY | O_NONBLOCK)) < 0)
886e95
-        error (0, rd_errno, _("error opening %s"), quote (file));
886e95
-      return false;
886e95
+      fd = open (file, O_WRONLY | O_NONBLOCK);
886e95
+      if (fd < 0)
886e95
+        {
886e95
+          error (0, rd_errno, _("error opening %s"), quote (file));
886e95
+          return false;
886e95
+        }
886e95
     }
886e95
 
886e95
   /* We used O_NONBLOCK above to not hang with fifos,
886e95
-- 
886e95
2.25.4
886e95