1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-04-10 22:24:12 +02:00
Files
coreutils/src/sync.c
Paul Eggert 6d61667d0d maint: go back to using ‘error’
Now that Gnulib’s ‘error’ module does proper static checking
for not returning, we need no longer use the ‘die’ macro.
This makes code easier to read for people that are used to ‘error’.
* cfg.mk (error_fns, exclude_file_name_regexp): Remove ‘die’.
(sc_die_EXIT_FAILURE): Remove.
* src/die.h: Remove.  All includes removed.  All calls to ‘die’
changed back to calls to ‘error’.
* src/install.c (get_ids): Use quoteaf (problem found with
make syntax-check).
* src/system.h: Include error.h, since some of our macros call ‘error’.
Stop including error.h elsewhere.
2023-07-01 11:51:16 -07:00

235 lines
5.4 KiB
C

/* sync - update the super block
Copyright (C) 1994-2023 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
/* Written by Jim Meyering */
#include <config.h>
#include <getopt.h>
#include <stdio.h>
#include <sys/types.h>
#include "system.h"
/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "sync"
#define AUTHORS \
proper_name ("Jim Meyering"), \
proper_name ("Giuseppe Scrivano")
#ifndef HAVE_SYNCFS
# define HAVE_SYNCFS 0
#endif
enum sync_mode
{
MODE_FILE,
MODE_DATA,
MODE_FILE_SYSTEM,
MODE_SYNC
};
static struct option const long_options[] =
{
{"data", no_argument, nullptr, 'd'},
{"file-system", no_argument, nullptr, 'f'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{nullptr, 0, nullptr, 0}
};
void
usage (int status)
{
if (status != EXIT_SUCCESS)
emit_try_help ();
else
{
printf (_("Usage: %s [OPTION] [FILE]...\n"), program_name);
fputs (_("\
Synchronize cached writes to persistent storage\n\
\n\
If one or more files are specified, sync only them,\n\
or their containing file systems.\n\
\n\
"), stdout);
fputs (_("\
-d, --data sync only file data, no unneeded metadata\n\
"), stdout);
fputs (_("\
-f, --file-system sync the file systems that contain the files\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
/* Sync the specified FILE, or file systems associated with FILE.
Return 1 on success. */
static bool
sync_arg (enum sync_mode mode, char const *file)
{
bool ret = true;
int open_flags = O_RDONLY | O_NONBLOCK;
int fd;
#if defined _AIX || defined __CYGWIN__
/* AIX 7.1, CYGWIN 2.9.0, fsync requires write access to file. */
if (mode == MODE_FILE)
open_flags = O_WRONLY | O_NONBLOCK;
#endif
/* Note O_PATH might be supported with syncfs(),
though as of Linux 3.18 is not. */
fd = open (file, open_flags);
if (fd < 0)
{
/* Use the O_RDONLY errno, which is significant
with directories for example. */
int rd_errno = errno;
if (open_flags != (O_WRONLY | O_NONBLOCK))
fd = open (file, O_WRONLY | O_NONBLOCK);
if (fd < 0)
{
error (0, rd_errno, _("error opening %s"), quoteaf (file));
return false;
}
}
/* We used O_NONBLOCK above to not hang with fifos,
so reset that here. */
int fdflags = fcntl (fd, F_GETFL);
if (fdflags == -1
|| fcntl (fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
{
error (0, errno, _("couldn't reset non-blocking mode %s"),
quoteaf (file));
ret = false;
}
if (ret == true)
{
int sync_status = -1;
switch (mode)
{
case MODE_DATA:
sync_status = fdatasync (fd);
break;
case MODE_FILE:
sync_status = fsync (fd);
break;
#if HAVE_SYNCFS
case MODE_FILE_SYSTEM:
sync_status = syncfs (fd);
break;
#endif
default:
unreachable ();
}
if (sync_status < 0)
{
error (0, errno, _("error syncing %s"), quoteaf (file));
ret = false;
}
}
if (close (fd) < 0)
{
error (0, errno, _("failed to close %s"), quoteaf (file));
ret = false;
}
return ret;
}
int
main (int argc, char **argv)
{
int c;
bool args_specified;
bool arg_data = false, arg_file_system = false;
enum sync_mode mode;
bool ok = true;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
while ((c = getopt_long (argc, argv, "df", long_options, nullptr))
!= -1)
{
switch (c)
{
case 'd':
arg_data = true;
break;
case 'f':
arg_file_system = true;
break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
usage (EXIT_FAILURE);
}
}
args_specified = optind < argc;
if (arg_data && arg_file_system)
error (EXIT_FAILURE, 0,
_("cannot specify both --data and --file-system"));
if (!args_specified && arg_data)
error (EXIT_FAILURE, 0, _("--data needs at least one argument"));
if (! args_specified || (arg_file_system && ! HAVE_SYNCFS))
mode = MODE_SYNC;
else if (arg_file_system)
mode = MODE_FILE_SYSTEM;
else if (! arg_data)
mode = MODE_FILE;
else
mode = MODE_DATA;
if (mode == MODE_SYNC)
sync ();
else
{
for (; optind < argc; optind++)
ok &= sync_arg (mode, argv[optind]);
}
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
}