pcu-fadvise: fall back if O_NOATIME fails due to EPERM
[pcu.git] / fadvise.c
blobb4b85d7ff372b46c93561e47d7c1c3fab5fe5384
1 #include "compat-util.h"
3 static struct fa_advice {
4 const char *name;
5 const int nr;
6 } advice_table[] = {
7 { "normal", POSIX_FADV_NORMAL },
8 { "sequential", POSIX_FADV_SEQUENTIAL },
9 { "random", POSIX_FADV_RANDOM },
10 { "noreuse", POSIX_FADV_NOREUSE },
11 { "willneed", POSIX_FADV_WILLNEED },
12 { "dontneed" , POSIX_FADV_DONTNEED }
15 static int usage(const char * argv0)
17 int i;
19 fprintf(stderr,
20 "Usage: %s [-a ADVICE] [-o OFFSET] "
21 "[-l LENGTH] FILE...\n", argv0);
22 fprintf(stderr, "\nPossible values for advice:\n");
23 for (i = 0; i < ARRAY_SIZE(advice_table); ++i)
24 fprintf(stderr, "\t%s\n", advice_table[i].name);
26 return 1;
29 static void apply_fadvise(const char *path, off_t offset, off_t len, int advice)
31 int fd;
33 if ((fd = open(path, O_RDONLY|O_NOATIME)) < 0) {
34 if (errno == EPERM && O_NOATIME != 0) {
35 fd = open(path, O_RDONLY);
36 if (fd >= 0)
37 goto ok;
39 fprintf(stderr, "%s: open(): %s\n", path, strerror(errno));
40 return;
42 ok:
44 if (len <= 0) {
45 /* for compatibility with kernels < 2.6.6 */
46 struct stat sb;
48 if (fstat(fd, &sb) < 0) {
49 fprintf(stderr, "%s: fstat(%d): %s\n",
50 path, fd, strerror(errno));
51 goto out;
53 len = sb.st_size;
56 if (posix_fadvise(fd, offset, len, advice) < 0)
57 fprintf(stderr,
58 "%s: posix_fadvise("
59 "offset=%lu,len=%lu,advice=%d): %s\n",
60 path,
61 (unsigned long)offset,
62 (unsigned long)len,
63 advice, strerror(errno));
65 out:
66 close(fd);
69 int main(int argc, char * const argv[])
71 off_t offset = 0;
72 off_t len = 0;
73 int advice = POSIX_FADV_NORMAL;
74 int opt;
75 int argi = 1;
77 while ((opt = getopt(argc, argv, "o:l:a:h")) != -1) {
78 int i;
79 char *err;
81 argi += 2;
82 switch(opt) {
83 case 'o':
84 offset = cstr_to_off_t(optarg, &err, 10);
85 if (*err || offset < 0) {
86 fprintf(stderr, "offset must be >= 0\n");
87 return 1;
89 break;
90 case 'l':
91 len = cstr_to_off_t(optarg, &err, 10);
92 if (*err || len < 0) {
93 fprintf(stderr, "length must be >= 0\n");
94 return 1;
96 break;
97 case 'a':
98 for (i = 0; i < ARRAY_SIZE(advice_table); ++i) {
99 if (strcmp(advice_table[i].name, optarg))
100 continue;
101 advice = advice_table[i].nr;
102 break;
104 if (i < ARRAY_SIZE(advice_table))
105 break;
106 fprintf(stderr, "advice '%s' not understood\n", optarg);
107 /* fall-through */
108 default:
109 return usage(argv[0]);
113 if (argi >= argc)
114 return usage(argv[0]);
116 for (; argi < argc; ++argi)
117 apply_fadvise(argv[argi], offset, len, advice);
118 return 0;