1 /* Simple block pattern reader/writer for testing FBD */
2
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <unistd.h>
7 #include <fcntl.h>
8
9 #define BLOCK_SIZE 4096 /* set to match root FS to prevent partial I/O */
10
flush_buf(int fd,char * buf,size_t size,size_t write_size)11 static int flush_buf(int fd, char *buf, size_t size, size_t write_size)
12 {
13 ssize_t r;
14
15 while (write_size <= size) {
16 if ((r = write(fd, buf, write_size)) != write_size) {
17 if (r < 0)
18 perror("write");
19 else
20 fprintf(stderr, "short write (%d < %d)\n",
21 r, write_size);
22
23 return EXIT_FAILURE;
24 }
25
26 sync();
27
28 buf += write_size;
29 size -= write_size;
30 }
31
32 return EXIT_SUCCESS;
33 }
34
write_pattern(int fd,char * pattern,int write_size)35 static int write_pattern(int fd, char *pattern, int write_size)
36 {
37 char *buf, *ptr;
38 size_t size;
39 int r, count, nblocks;
40
41 /* Only write sizes that are a multiple or a
42 * divisor of the block size, are supported.
43 */
44 nblocks = write_size / BLOCK_SIZE;
45 if (!nblocks) nblocks = 1;
46 size = nblocks * BLOCK_SIZE;
47
48 if ((buf = malloc(size)) == NULL) {
49 perror("malloc");
50
51 return EXIT_FAILURE;
52 }
53
54 count = 0;
55
56 do {
57 ptr = &buf[count * BLOCK_SIZE];
58
59 switch (*pattern) {
60 case 'A':
61 case 'B':
62 case 'C':
63 case 'D':
64 case 'U':
65 memset(ptr, *pattern, BLOCK_SIZE);
66 break;
67
68 case '0':
69 memset(ptr, 0, BLOCK_SIZE);
70 break;
71
72 case '\0':
73 memset(ptr, 0, BLOCK_SIZE);
74 ptr[0] = 'E';
75 ptr[1] = 'O';
76 ptr[2] = 'F';
77 }
78
79 if (++count == nblocks) {
80 if ((r = flush_buf(fd, buf, size, write_size)) !=
81 EXIT_SUCCESS) {
82 free(buf);
83
84 return r;
85 }
86
87 count = 0;
88 }
89 } while (*pattern++);
90
91 if (count > 0)
92 r = flush_buf(fd, buf, count * BLOCK_SIZE, write_size);
93 else
94 r = EXIT_SUCCESS;
95
96 free(buf);
97
98 return r;
99 }
100
read_pattern(int fd)101 static int read_pattern(int fd)
102 {
103 char buf[BLOCK_SIZE];
104 unsigned int i, val;
105 ssize_t r;
106
107 for (;;) {
108 memset(buf, '?', sizeof(buf));
109
110 if ((r = read(fd, buf, sizeof(buf))) != sizeof(buf)) {
111 putchar('#');
112
113 if (!r) break; /* stop at hard EOF */
114
115 lseek(fd, sizeof(buf), SEEK_CUR);
116
117 continue;
118 }
119
120 if (buf[0] == 'E' && buf[1] == 'O' && buf[2] == 'F') {
121 for (i = 3; i < sizeof(buf); i++)
122 if (buf[i] != 0) break;
123
124 if (i == sizeof(buf)) break;
125 }
126
127 for (i = 1; i < sizeof(buf); i++)
128 if (buf[i] != buf[0]) break;
129
130 if (i == sizeof(buf)) {
131 switch (buf[0]) {
132 case 'A':
133 case 'B':
134 case 'C':
135 case 'D':
136 case 'U':
137 case '?':
138 printf("%c", buf[0]);
139 break;
140
141 case '\0':
142 printf("0");
143 break;
144
145 default:
146 printf("X");
147 }
148
149 continue;
150 }
151
152 for (i = val = 0; i < sizeof(buf); i++)
153 val += buf[i];
154
155 printf("%c", 'a' + val % 26);
156 }
157
158 printf("\n");
159
160 return EXIT_SUCCESS;
161 }
162
main(int argc,char ** argv)163 int main(int argc, char **argv)
164 {
165 int fd, r;
166
167 if (argc < 2) {
168 fprintf(stderr, "usage: %s <device> [pattern [writesz]]\n",
169 argv[0]);
170
171 return EXIT_FAILURE;
172 }
173
174 fd = open(argv[1], (argc > 2) ? O_WRONLY : O_RDONLY);
175 if (fd < 0) {
176 perror("open");
177
178 return EXIT_FAILURE;
179 }
180
181 if (argc > 2)
182 r = write_pattern(fd, argv[2],
183 argv[3] ? atoi(argv[3]) : BLOCK_SIZE);
184 else
185 r = read_pattern(fd);
186
187 close(fd);
188
189 return r;
190 }
191