Makefile: ghetto generation task for the website
[pcu.git] / fsync.c
blobebf039fb1a3de1a0e5e7f3b765e8d00d19c22c20
1 #include "compat-util.h"
2 #include <dirent.h>
3 #include <libgen.h>
4 #include <dlfcn.h>
6 #if defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
7 static int have_fdatasync = 1;
8 #else
9 static int have_fdatasync;
10 #endif
12 /* TODO: sync_file_range() if on Linux */
14 static int usage(const char * argv0)
16 fprintf(stderr, "Usage: %s [-d] [-D] FILE...\n", argv0);
17 return 1;
20 #define FN_NOT_FOUND ((void *)(1))
22 static int fs_sync(const char *path)
24 int rc = 0;
25 #if defined(__linux__) && defined(RTLD_NEXT)
26 static int (*syncfs_fn)(int);
28 if (syncfs_fn == NULL) {
29 syncfs_fn = dlsym(RTLD_DEFAULT, "syncfs");
30 if (syncfs_fn == NULL || dlerror())
31 syncfs_fn = FN_NOT_FOUND;
33 if (syncfs_fn != NULL && syncfs_fn != FN_NOT_FOUND) {
34 int fd = open(path, O_RDONLY|O_NOATIME);
36 if (fd >= 0) {
37 int err;
38 rc = syncfs_fn(fd);
39 err = errno;
40 close(fd);
43 * if glibc has syncfs(2) but we're running an
44 * old kernel, fall back to sync(2) below
46 if (err != ENOSYS)
47 return rc;
48 rc = 0;
51 #endif /* ! __linux__ */
52 sync();
53 return rc;
56 static int do_sync(const char *path, int data_only, int directory)
58 int fd;
59 const char *errfunc = "";
61 if ((fd = open(path, O_RDWR|O_NOATIME)) < 0) {
62 if (errno == EISDIR) {
63 directory = 1;
64 goto sync_dir;
66 errfunc = "open";
67 goto err;
70 if (data_only && have_fdatasync) {
71 if (fdatasync(fd) < 0) {
72 errfunc = "fdatasync";
73 goto err;
75 } else {
76 if (fsync(fd) < 0) {
77 errfunc = "fsync";
78 goto err;
82 if (close(fd) < 0) {
83 errfunc = "close";
84 goto err;
87 sync_dir:
88 if (directory) {
89 char *dpath;
90 DIR *dir;
92 if (!(dpath = strdup(path))){
93 errfunc = "strdup";
94 goto err;
96 if (!(dir = opendir(dirname(dpath)))) {
97 errfunc = "opendir";
98 goto err;
100 if (fsync(dirfd(dir)) < 0) {
101 errfunc = "(directory) fsync";
102 goto err;
104 if (closedir(dir) < 0) {
105 errfunc = "closedir";
106 goto err;
108 free(dpath);
111 return 0;
112 err:
113 fprintf(stderr, "%s: %s(): %s\n", path, errfunc, strerror(errno));
114 return -1;
117 int main(int argc, char * const argv[])
119 int data_only = 0;
120 int fs = 0;
121 int directory = 0;
122 int opt;
123 int argi = 1;
125 while ((opt = getopt(argc, argv, "dDf")) != -1) {
126 ++argi;
127 switch(opt) {
128 case 'd':
129 data_only = 1;
130 break;
131 case 'D':
132 directory = 1;
133 break;
134 case 'f':
135 fs = 1;
136 break;
137 default:
138 return usage(argv[0]);
142 if (argi >= argc)
143 return usage(argv[0]);
145 for (; argi < argc; ++argi) {
146 if (fs) {
147 if (fs_sync(argv[argi]) < 0)
148 return 1;
149 } else {
150 if (do_sync(argv[argi], data_only, directory) < 0)
151 return 1;
155 return 0;