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

From: Pádraig Brady <[email-masked]>
Date: Sun, 25 Jan 2015 03:42:00 +0000

thanks I like it!
Tweaks below...

On 25/01/15 00:48, Giuseppe Scrivano wrote:
> * 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.
> ---
>  NEWS               |  3 +++
>  configure.ac       |  2 ++
>  doc/coreutils.texi |  7 ++++++-
>  src/sync.c         | 31 +++++++++++++++++++++++++++++--
>  4 files changed, 40 insertions(+), 3 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index e0a2893..42bd02f 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 accepts arguments, and if any is specified use syncfs(2) to
> +  flush the buffers for the file systems which cointain these paths.

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..940836e 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);
> @@ -65,9 +68,33 @@ main (int argc, char **argv)
>    if (getopt_long (argc, argv, "", NULL, NULL) != -1)
>      usage (EXIT_FAILURE);
>  
> +#if HAVE_SYNCFS
> +  /* If arguments are specified, use syncfs on any of them.
> +     On any error, silently fallback to sync.  */
>    if (optind < argc)
> -    error (0, 0, _("ignoring all arguments"));

The warning above should be moved down to the sync: case
rather than removing it.

> +    {
> +      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:
>    sync ();
>    return EXIT_SUCCESS;
>  }
> 

thanks!
Pádraig