diff options
author | Eric Wong <normalperson@yhbt.net> | 2009-08-09 15:33:48 -0700 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2009-08-09 15:36:25 -0700 |
commit | d4581cb9a1d178cb31416eb30d501a0e46878e45 (patch) | |
tree | 77e141f88b76eec83b368aba5222455077356c9b | |
parent | 8947b985335cbf9b30cffb9e79f9ed7a1899e298 (diff) | |
download | pcu-d4581cb9a1d178cb31416eb30d501a0e46878e45.tar.gz |
Add `pcu-sync' command
This can be useful for calling fsync(2)/fdatasync(2) on individual files (and/or their containing directories). This can be used when a system-wide sync(2) is too expensive on a busy system.
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | sync.c | 110 |
3 files changed, 113 insertions, 1 deletions
@@ -1,5 +1,6 @@ pcu-mincore pcu-fadvise +pcu-sync GIT-VERSION-FILE *.1 *.html @@ -22,8 +22,9 @@ LDFLAGS = -Wl,-O1 pcu-mincore: mincore.c compat-util.h pcu-fadvise: fadvise.c compat-util.h +pcu-sync: sync.c compat-util.h -PCU_BIN := pcu-fadvise pcu-mincore +PCU_BIN := pcu-fadvise pcu-mincore pcu-sync $(PCU_BIN): $(CC) $(CFLAGS) $(LDFLAGS) -o $@+ $< @@ -0,0 +1,110 @@ +#include "compat-util.h" +#include <dirent.h> +#include <libgen.h> + +#if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0 +static int have_fdatasync = 1; +#else +static int have_fdatasync; +#endif + +/* TODO: sync_file_range() if on Linux */ + +static int usage(const char * argv0) +{ + fprintf(stderr, "Usage: %s [-d] [-D] FILE...\n", argv0); + return 1; +} + +static int do_sync(const char *path, int data_only, int directory) +{ + int fd; + const char *errfunc = ""; + + if ((fd = open(path, O_RDWR|O_NOATIME)) < 0) { + if (errno == EISDIR) { + directory = 1; + goto sync_dir; + } + errfunc = "open"; + goto err; + } + + if (data_only && have_fdatasync) { + if (fdatasync(fd) < 0) { + errfunc = "fdatasync"; + goto err; + } + } else { + if (fsync(fd) < 0) { + errfunc = "fsync"; + goto err; + } + } + + if (close(fd) < 0) { + errfunc = "close"; + goto err; + } + +sync_dir: + if (directory) { + char *dpath; + DIR *dir; + + if (!(dpath = strdup(path))){ + errfunc = "strdup"; + goto err; + } + if (!(dir = opendir(dirname(dpath)))) { + errfunc = "opendir"; + goto err; + } + if (fsync(dirfd(dir)) < 0) { + errfunc = "(directory) fsync"; + goto err; + } + if (closedir(dir) < 0) { + errfunc = "closedir"; + goto err; + } + free(dpath); + } + + return 0; +err: + fprintf(stderr, "%s: %s(): %s\n", path, errfunc, strerror(errno)); + return -1; +} + +int main(int argc, char * const argv[]) +{ + int data_only = 0; + int directory = 0; + int opt; + int argi = 1; + + while ((opt = getopt(argc, argv, "dD")) != -1) { + ++argi; + switch(opt) { + case 'd': + data_only = 1; + break; + case 'D': + directory = 1; + break; + default: + return usage(argv[0]); + } + } + + if (argi >= argc) + return usage(argv[0]); + + for (; argi < argc; ++argi) { + if (do_sync(argv[argi], data_only, directory) < 0) + return 1; + } + + return 0; +} |