Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/stride_dd.c
48529 views
1
// SPDX-License-Identifier: CDDL-1.0
2
/*
3
* This file and its contents are supplied under the terms of the
4
* Common Development and Distribution License ("CDDL"), version 1.0.
5
* You may only use this file in accordance with the terms of version
6
* 1.0 of the CDDL.
7
*
8
* A full copy of the text of the CDDL should have accompanied this
9
* source. A copy of the CDDL is also available via the Internet at
10
* http://www.illumos.org/license/CDDL.
11
*/
12
13
/*
14
* Copyright (c) 2018 by Delphix. All rights reserved.
15
*/
16
17
#include <sys/types.h>
18
#include <errno.h>
19
#include <fcntl.h>
20
#include <stdio.h>
21
#include <unistd.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
static int alignment = 0;
26
static int bsize = 0;
27
static int count = 0;
28
static char *ifile = NULL;
29
static char *ofile = NULL;
30
static off_t stride = 1;
31
static off_t seek = 0;
32
static int seekbytes = 0;
33
static int if_o_direct = 0;
34
static int of_o_direct = 0;
35
static int skip = 0;
36
static int skipbytes = 0;
37
static int entire_file = 0;
38
static const char *execname = "stride_dd";
39
40
static void usage(void);
41
static void parse_options(int argc, char *argv[]);
42
43
static void
44
usage(void)
45
{
46
(void) fprintf(stderr,
47
"usage: %s -i inputfile -o outputfile -b blocksize [-c count]\n"
48
" [-s stride] [-k seekblocks] [-K seekbytes]\n"
49
" [-a alignment] [-d if_o_direct] [-D of_o_direct]\n"
50
" [-p skipblocks] [-P skipbytes] [-e entire_file]\n"
51
"\n"
52
"Simplified version of dd that supports the stride option.\n"
53
"A stride of n means that for each block written, n - 1 blocks\n"
54
"are skipped in both the input and output file. A stride of 1\n"
55
"means that blocks are read and written consecutively.\n"
56
"All numeric parameters must be integers.\n"
57
"\n"
58
" inputfile: File to read from\n"
59
" outputfile: File to write to\n"
60
" blocksize: Size of each block to read/write\n"
61
" count: Number of blocks to read/write (Required"
62
" unless -e is used)\n"
63
" stride: Read/write a block then skip (stride - 1) blocks"
64
"\n"
65
" seekblocks: Number of blocks to skip at start of output\n"
66
" seekbytes: Treat seekblocks as byte count\n"
67
" alignment: Alignment passed to posix_memalign() (default"
68
" PAGE_SIZE)\n"
69
" if_o_direct: Use O_DIRECT with inputfile (default no O_DIRECT)"
70
"\n"
71
" of_o_direct: Use O_DIRECT with outputfile (default no "
72
" O_DIRECT)\n"
73
" skipblocks: Number of blocks to skip at start of input "
74
" (default 0)\n"
75
" skipbytes: Treat skipblocks as byte count\n"
76
" entire_file: When used the entire inputfile will be read and"
77
" count will be ignored\n",
78
execname);
79
(void) exit(1);
80
}
81
82
/*
83
* posix_memalign() only allows for alignments which are postive, powers of two
84
* and a multiple of sizeof (void *).
85
*/
86
static int
87
invalid_alignment(int alignment)
88
{
89
if ((alignment < 0) || (alignment & (alignment - 1)) ||
90
((alignment % sizeof (void *)))) {
91
(void) fprintf(stderr,
92
"Alignment must be a postive, power of two, and multiple "
93
"of sizeof (void *).\n");
94
return (1);
95
}
96
return (0);
97
}
98
99
static void
100
parse_options(int argc, char *argv[])
101
{
102
int c;
103
int errflag = 0;
104
105
execname = argv[0];
106
alignment = sysconf(_SC_PAGE_SIZE);
107
108
extern char *optarg;
109
extern int optind, optopt;
110
111
while ((c = getopt(argc, argv, "a:b:c:deDi:o:s:k:Kp:P")) != -1) {
112
switch (c) {
113
case 'a':
114
alignment = atoi(optarg);
115
break;
116
117
case 'b':
118
bsize = atoi(optarg);
119
break;
120
121
case 'c':
122
count = atoi(optarg);
123
break;
124
125
case 'd':
126
if_o_direct = 1;
127
break;
128
129
case 'e':
130
entire_file = 1;
131
break;
132
133
case 'D':
134
of_o_direct = 1;
135
break;
136
137
case 'i':
138
ifile = optarg;
139
break;
140
141
case 'o':
142
ofile = optarg;
143
break;
144
145
case 's':
146
stride = atoi(optarg);
147
break;
148
149
case 'k':
150
seek = atoi(optarg);
151
break;
152
153
case 'K':
154
seekbytes = 1;
155
break;
156
157
case 'p':
158
skip = atoi(optarg);
159
break;
160
161
case 'P':
162
skipbytes = 1;
163
break;
164
165
case ':':
166
(void) fprintf(stderr,
167
"Option -%c requires an operand\n", optopt);
168
errflag++;
169
break;
170
171
case '?':
172
default:
173
(void) fprintf(stderr,
174
"Unrecognized option: -%c\n", optopt);
175
errflag++;
176
break;
177
}
178
179
if (errflag) {
180
(void) usage();
181
}
182
}
183
184
if (bsize <= 0 || stride <= 0 || ifile == NULL || ofile == NULL ||
185
seek < 0 || invalid_alignment(alignment) || skip < 0) {
186
(void) fprintf(stderr,
187
"Required parameter(s) missing or invalid.\n");
188
(void) usage();
189
}
190
191
if (count <= 0 && entire_file == 0) {
192
(void) fprintf(stderr,
193
"Required parameter(s) missing or invalid.\n");
194
(void) usage();
195
}
196
}
197
198
static void
199
read_entire_file(int ifd, int ofd, void *buf)
200
{
201
int c;
202
203
do {
204
c = read(ifd, buf, bsize);
205
if (c < 0) {
206
perror("read");
207
exit(2);
208
} else if (c != 0) {
209
c = write(ofd, buf, bsize);
210
if (c < 0) {
211
perror("write");
212
exit(2);
213
}
214
215
}
216
if (stride > 1) {
217
if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {
218
perror("input lseek");
219
exit(2);
220
}
221
if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {
222
perror("output lseek");
223
exit(2);
224
}
225
}
226
} while (c != 0);
227
}
228
229
static void
230
read_on_count(int ifd, int ofd, void *buf)
231
{
232
int i;
233
int c;
234
235
for (i = 0; i < count; i++) {
236
c = read(ifd, buf, bsize);
237
if (c != bsize) {
238
if (c < 0) {
239
perror("read");
240
} else {
241
(void) fprintf(stderr,
242
"%s: unexpected short read, read %d "
243
"bytes, expected %d\n", execname,
244
c, bsize);
245
}
246
exit(2);
247
}
248
249
c = write(ofd, buf, bsize);
250
if (c != bsize) {
251
if (c < 0) {
252
perror("write");
253
} else {
254
(void) fprintf(stderr,
255
"%s: unexpected short write, wrote %d "
256
"bytes, expected %d\n", execname,
257
c, bsize);
258
}
259
exit(2);
260
}
261
262
if (stride > 1) {
263
if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {
264
perror("input lseek");
265
exit(2);
266
}
267
if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {
268
perror("output lseek");
269
exit(2);
270
}
271
}
272
}
273
}
274
275
int
276
main(int argc, char *argv[])
277
{
278
int ifd;
279
int ofd;
280
int ifd_flags = O_RDONLY;
281
int ofd_flags = O_WRONLY | O_CREAT;
282
void *buf;
283
284
parse_options(argc, argv);
285
286
if (if_o_direct)
287
ifd_flags |= O_DIRECT;
288
289
if (of_o_direct)
290
ofd_flags |= O_DIRECT;
291
292
ifd = open(ifile, ifd_flags);
293
if (ifd == -1) {
294
(void) fprintf(stderr, "%s: %s: ", execname, ifile);
295
perror("open");
296
exit(2);
297
}
298
299
ofd = open(ofile, ofd_flags, 0666);
300
if (ofd == -1) {
301
(void) fprintf(stderr, "%s: %s: ", execname, ofile);
302
perror("open");
303
exit(2);
304
}
305
306
/*
307
* We use valloc because some character block devices expect a
308
* page-aligned buffer.
309
*/
310
int err = posix_memalign(&buf, alignment, bsize);
311
if (err != 0) {
312
(void) fprintf(stderr,
313
"%s: %s\n", execname, strerror(err));
314
exit(2);
315
}
316
317
if (skip > 0) {
318
int skipamt = skipbytes == 1 ? skip : skip * bsize;
319
if (lseek(ifd, skipamt, SEEK_CUR) == -1) {
320
perror("input lseek");
321
exit(2);
322
}
323
}
324
325
if (seek > 0) {
326
int seekamt = seekbytes == 1 ? seek : seek * bsize;
327
if (lseek(ofd, seekamt, SEEK_CUR) == -1) {
328
perror("output lseek");
329
exit(2);
330
}
331
}
332
333
if (entire_file == 1)
334
read_entire_file(ifd, ofd, buf);
335
else
336
read_on_count(ifd, ofd, buf);
337
338
free(buf);
339
340
(void) close(ofd);
341
(void) close(ifd);
342
343
return (0);
344
}
345
346