]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/openzfs/tests/zfs-tests/cmd/stride_dd.c
zfs: merge openzfs/zfs@deb121309
[FreeBSD/FreeBSD.git] / sys / contrib / openzfs / tests / zfs-tests / cmd / stride_dd.c
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11
12 /*
13  * Copyright (c) 2018 by Delphix. All rights reserved.
14  */
15
16 #include <sys/types.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 static int bsize = 0;
25 static int count = 0;
26 static char *ifile = NULL;
27 static char *ofile = NULL;
28 static int stride = 0;
29 static int seek = 0;
30 static char *execname = "stride_dd";
31
32 static void usage(void);
33 static void parse_options(int argc, char *argv[]);
34
35 static void
36 usage(void)
37 {
38         (void) fprintf(stderr,
39             "usage: %s -i inputfile -o outputfile -b blocksize -c count \n"
40             "           -s stride [ -k seekblocks]\n"
41             "\n"
42             "Simplified version of dd that supports the stride option.\n"
43             "A stride of n means that for each block written, n - 1 blocks\n"
44             "are skipped in both the input and output file. A stride of 1\n"
45             "means that blocks are read and written consecutively.\n"
46             "All numeric parameters must be integers.\n"
47             "\n"
48             "    inputfile:  File to read from\n"
49             "    outputfile: File to write to\n"
50             "    blocksize:  Size of each block to read/write\n"
51             "    count:      Number of blocks to read/write\n"
52             "    stride:     Read/write a block then skip (stride - 1) blocks\n"
53             "    seekblocks: Number of blocks to skip at start of output\n",
54             execname);
55         (void) exit(1);
56 }
57
58 static void
59 parse_options(int argc, char *argv[])
60 {
61         int c;
62         int errflag = 0;
63
64         execname = argv[0];
65
66         extern char *optarg;
67         extern int optind, optopt;
68
69         while ((c = getopt(argc, argv, ":b:c:i:o:s:k:")) != -1) {
70                 switch (c) {
71                         case 'b':
72                                 bsize = atoi(optarg);
73                                 break;
74
75                         case 'c':
76                                 count = atoi(optarg);
77                                 break;
78
79                         case 'i':
80                                 ifile = optarg;
81                                 break;
82
83                         case 'o':
84                                 ofile = optarg;
85                                 break;
86
87                         case 's':
88                                 stride = atoi(optarg);
89                                 break;
90
91                         case 'k':
92                                 seek = atoi(optarg);
93                                 break;
94
95                         case ':':
96                                 (void) fprintf(stderr,
97                                     "Option -%c requires an operand\n", optopt);
98                                 errflag++;
99                                 break;
100
101                         case '?':
102                         default:
103                                 (void) fprintf(stderr,
104                                     "Unrecognized option: -%c\n", optopt);
105                                 errflag++;
106                                 break;
107                 }
108
109                 if (errflag) {
110                         (void) usage();
111                 }
112         }
113
114         if (bsize <= 0 || count <= 0 || stride <= 0 || ifile == NULL ||
115             ofile == NULL || seek < 0) {
116                 (void) fprintf(stderr,
117                     "Required parameter(s) missing or invalid.\n");
118                 (void) usage();
119         }
120 }
121
122 int
123 main(int argc, char *argv[])
124 {
125         int i;
126         int ifd;
127         int ofd;
128         void *buf;
129         int c;
130
131         parse_options(argc, argv);
132
133         ifd = open(ifile, O_RDONLY);
134         if (ifd == -1) {
135                 (void) fprintf(stderr, "%s: %s: ", execname, ifile);
136                 perror("open");
137                 exit(2);
138         }
139
140         ofd = open(ofile, O_WRONLY | O_CREAT, 0666);
141         if (ofd == -1) {
142                 (void) fprintf(stderr, "%s: %s: ", execname, ofile);
143                 perror("open");
144                 exit(2);
145         }
146
147         /*
148          * We use valloc because some character block devices expect a
149          * page-aligned buffer.
150          */
151         int err = posix_memalign(&buf, 4096, bsize);
152         if (err != 0) {
153                 (void) fprintf(stderr,
154                     "%s: %s\n", execname, strerror(err));
155                 exit(2);
156         }
157
158         if (seek > 0) {
159                 if (lseek(ofd, seek * bsize, SEEK_CUR) == -1) {
160                         perror("output lseek");
161                         exit(2);
162                 }
163         }
164
165         for (i = 0; i < count; i++) {
166                 c = read(ifd, buf, bsize);
167                 if (c != bsize) {
168
169                         perror("read");
170                         exit(2);
171                 }
172                 if (c != bsize) {
173                         if (c < 0) {
174                                 perror("read");
175                         } else {
176                                 (void) fprintf(stderr,
177                                     "%s: unexpected short read, read %d "
178                                     "bytes, expected %d\n", execname,
179                                     c, bsize);
180                         }
181                         exit(2);
182                 }
183
184                 c = write(ofd, buf, bsize);
185                 if (c != bsize) {
186                         if (c < 0) {
187                                 perror("write");
188                         } else {
189                                 (void) fprintf(stderr,
190                                     "%s: unexpected short write, wrote %d "
191                                     "bytes, expected %d\n", execname,
192                                     c, bsize);
193                         }
194                         exit(2);
195                 }
196
197                 if (stride > 1) {
198                         if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {
199                                 perror("input lseek");
200                                 exit(2);
201                         }
202                         if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {
203                                 perror("output lseek");
204                                 exit(2);
205                         }
206                 }
207         }
208         free(buf);
209
210         (void) close(ofd);
211         (void) close(ifd);
212
213         return (0);
214 }