xref: /minix3/minix/tests/fbdtest/rwblocks.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
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