diff options
Diffstat (limited to 'fsync.c')
-rw-r--r-- | fsync.c | 52 |
1 files changed, 49 insertions, 3 deletions
@@ -1,6 +1,7 @@ #include "compat-util.h" #include <dirent.h> #include <libgen.h> +#include <dlfcn.h> #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 static int have_fdatasync = 1; @@ -16,6 +17,42 @@ static int usage(const char * argv0) return 1; } +#define FN_NOT_FOUND ((void *)(1)) + +static int fs_sync(const char *path) +{ + int rc = 0; +#if defined(__linux__) && defined(RTLD_NEXT) + static int (*syncfs_fn)(int); + + if (syncfs_fn == NULL) { + syncfs_fn = dlsym(RTLD_DEFAULT, "syncfs"); + if (syncfs_fn == NULL || dlerror()) + syncfs_fn = FN_NOT_FOUND; + } + if (syncfs_fn != NULL && syncfs_fn != FN_NOT_FOUND) { + int fd = open(path, O_RDONLY|O_NOATIME); + + if (fd >= 0) { + int err; + rc = syncfs_fn(fd); + err = errno; + close(fd); + + /* + * if glibc has syncfs(2) but we're running an + * old kernel, fall back to sync(2) below + */ + if (err != ENOSYS) + return rc; + rc = 0; + } + } +#endif /* ! __linux__ */ + sync(); + return rc; +} + static int do_sync(const char *path, int data_only, int directory) { int fd; @@ -80,11 +117,12 @@ err: int main(int argc, char * const argv[]) { int data_only = 0; + int fs = 0; int directory = 0; int opt; int argi = 1; - while ((opt = getopt(argc, argv, "dD")) != -1) { + while ((opt = getopt(argc, argv, "dDf")) != -1) { ++argi; switch(opt) { case 'd': @@ -93,6 +131,9 @@ int main(int argc, char * const argv[]) case 'D': directory = 1; break; + case 'f': + fs = 1; + break; default: return usage(argv[0]); } @@ -102,8 +143,13 @@ int main(int argc, char * const argv[]) return usage(argv[0]); for (; argi < argc; ++argi) { - if (do_sync(argv[argi], data_only, directory) < 0) - return 1; + if (fs) { + if (fs_sync(argv[argi]) < 0) + return 1; + } else { + if (do_sync(argv[argi], data_only, directory) < 0) + return 1; + } } return 0; |