Tizen 2.1 base
[platform/upstream/fsync.git] / fsync.c
1 /*      /\
2  *     /  \             (C) Copyright 2009 Parliament Hill Computers Ltd.
3  *     \  /             All rights reserved.
4  *      \/
5  *       .              Author: Alain Williams, <addw@phcomp.co.uk> 2009
6  *       .
7  *        .             SCCS: @(#)fsync.c       1.3 11/14/11 22:46:01
8  *          .
9  *
10  */
11
12 #include "config.h"
13
14 #include <stdio.h>
15 #include <sys/types.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22
23
24 extern  int     optind;
25 extern  char*   optarg;
26
27 char*   progname;       /* What this program is called - name of binary */
28 int     exit_c;         /* Exit status to return to O/S */
29 int     datasync;       /* Use fdatasync */
30 int     quiet;          /* Do not report errors */
31 int     verbose;        /* Chatty mode */
32 char*   flushname;      /* Name of how we flush */
33 int (*flushfn)(int);    /* Pointer to system call to use */
34
35 /* Usage message.
36  */
37 char*   usagem[] = {
38         "Ensure that named files are flushed to disk",
39         "Usage: %s [options] file ...",
40         "-d     do not flush metadata (fdatasync())",
41         "-q     do not report errors (eg file open fails), still set exit code",
42         "-v     verbose",
43         "-x     eXplain",
44         "Version: 1.3 11/14/11",
45         (char*)NULL     /* Must end the list */
46 };
47
48 /* Functions defined in this module, in alphabetic order */
49 void    read_opts(int argc, char* argv[]);
50 void    usage(int exitc);
51 void    process(const char* file);
52
53 int     main(int argc, char* argv[])
54 {
55         read_opts(argc, argv);
56
57         flushname = datasync ? "fdatasync" : "fsync";
58         flushfn = datasync ? fdatasync : fsync;
59
60         argv += optind;
61         while(*argv)
62                 process(*argv++);
63
64         return(exit_c);
65 }
66
67 /* Interpret '-' arguments -options.
68  * If there is an error in the arguments, print the options list and exit.
69  */
70 void    read_opts(int argc, char* argv[])
71 {
72         register int    c;
73         register int    error;
74
75         error = 0;
76         progname = argv[0];
77
78         while((c = getopt(argc, argv, "dqvx")) != EOF)
79                 switch(c) {
80                 case 'd':       /* Use fdatasync() */
81                         datasync = 1;
82                         break;
83                 case 'q':       /* Quiet */
84                         quiet = 1;
85                         break;
86                 case 'v':       /* Verbose */
87                         verbose = 1;
88                         break;
89                 case 'x':       /* eXplain */
90                         usage(0);
91                         /*NOTREACHED*/
92                 case '?':
93                         error = 1;
94                         break;
95                 }
96
97         if(error)
98                 usage(2);
99 }
100
101 /* Output a usage message and end with exit status exitc.
102  */
103 void    usage(int exitc)
104 {
105         register char** mes;
106         
107         for(mes = usagem; *mes != (char*)NULL; mes++) {
108                 (void) fprintf(stderr, *mes, progname);
109                 fputc('\n', stderr);
110         }
111         
112         exit(exitc);
113         /*NOTREACHED*/
114 }
115
116 /* Flush the named file to disk -- use the fsync or fdatasync system call
117  */
118 void    process(const char* file)
119 {
120         int     fd;
121
122         if(verbose)
123                 fprintf(stderr, "%s: about to %s '%s'\n", progname,
124                         flushname, file);
125
126         /* Need to open read/write for fsync to work.
127          * But we can't open directories to write to, so try to open one read only.
128          * Linux (2.6.18 anyway) doesn't seem to check that the fd to fsync is for
129          * writing - but that is what the manual says it must be.
130          */
131         if((fd = open(file, O_WRONLY)) == -1 &&
132            (errno == EISDIR && (fd = open(file, O_RDONLY)) == -1)) {
133                 if( ! quiet)
134                         fprintf(stderr, "%s: Cannot open '%s' as: %s\n", progname, file,
135                                 strerror(errno));
136                 exit_c = 1;
137                 return;
138         }
139
140         if((*flushfn)(fd) == -1) {
141                 if( ! quiet)
142                         fprintf(stderr, "%s: Cannot %s '%s' as: %s\n", progname, flushname, file,
143                                 strerror(errno));
144                 exit_c = 1;
145         }
146
147         if(close(fd)) {
148                 if( ! quiet)
149                         fprintf(stderr, "%s: Error on close of '%s' as: %s\n", progname, file,
150                                 strerror(errno));
151                 exit_c = 1;
152         }
153 }
154
155 /* end */