btrfs: test delayed subvolume deletion on mount and remount
[xfstests-dev.git] / src / punch-alternating.c
1 /*
2  * Punch out every other block in a file.
3  * Copyright (C) 2016 Oracle.
4  */
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include "global.h"
13
14 void usage(char *cmd)
15 {
16         printf("Usage: %s [-o offset] [-i interval] [-s size] file\n", cmd);
17         printf("Punches every other block in the file by default,\n");
18         printf("or 'size' blocks every 'interval' blocks starting at\n");
19         printf("'offset'.  Units are in fstatfs blocks.\n");
20         exit(1);
21 }
22
23 int main(int argc, char *argv[])
24 {
25         struct stat     s;
26         struct statfs   sf;
27         off_t           offset;
28         off_t           start_offset = 0;
29         int             fd;
30         blksize_t       blksz;
31         off_t           sz;
32         int             mode;
33         int             error;
34         int             c;
35         int             size = 1;       /* punch $SIZE blocks ... */
36         int             interval = 2;   /* every $INTERVAL blocks */
37
38         while ((c = getopt(argc, argv, "i:o:s:")) != EOF) {
39                 switch (c) {
40                 case 'i':
41                         interval = atoi(optarg);
42                         break;
43                 case 'o':
44                         errno = 0;
45                         start_offset = strtoull(optarg, NULL, 0);
46                         if (errno) {
47                                 fprintf(stderr, "invalid offset '%s'\n", optarg);
48                                 return 1;
49                         }
50                         break;
51                 case 's':
52                         size = atoi(optarg);
53                         break;
54                 default:
55                         usage(argv[0]);
56                 }
57         }
58
59         if (interval <= 0) {
60                 printf("interval must be > 0\n");
61                 usage(argv[0]);
62         }
63
64         if (size <= 0) {
65                 printf("size must be > 0\n");
66                 usage(argv[0]);
67         }
68
69         if (optind != argc - 1)
70                 usage(argv[0]);
71
72         fd = open(argv[optind], O_WRONLY);
73         if (fd < 0)
74                 goto err;
75
76         error = fstat(fd, &s);
77         if (error)
78                 goto err;
79
80         error = fstatfs(fd, &sf);
81         if (error)
82                 goto err;
83
84         sz = s.st_size;
85         blksz = sf.f_bsize;
86
87         mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
88         for (offset = start_offset * blksz;
89              offset < sz;
90              offset += blksz * interval) {
91                 error = fallocate(fd, mode, offset, blksz * size);
92                 if (error)
93                         goto err;
94         }
95
96         error = fsync(fd);
97         if (error)
98                 goto err;
99
100         error = close(fd);
101         if (error)
102                 goto err;
103         return 0;
104 err:
105         perror(argv[optind]);
106         return 2;
107 }