1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "file_common.h"
28 #include <libgen.h>
29 #include <string.h>
30 #include <inttypes.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <stdint.h>
36
37 static unsigned char bigbuffer[BIGBUFFERSIZE];
38
39 /*
40 * Writes (or appends) a given value to a file repeatedly.
41 * See header file for defaults.
42 */
43
44 static void usage(char *);
45
46 /*
47 * pseudo-randomize the buffer
48 */
randomize_buffer(int block_size)49 static void randomize_buffer(int block_size) {
50 int i;
51 char rnd = rand() & 0xff;
52 for (i = 0; i < block_size; i++)
53 bigbuffer[i] ^= rnd;
54 }
55
56 int
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59 int bigfd;
60 int c;
61 int oflag = 0;
62 int err = 0;
63 int k;
64 long i;
65 int64_t good_writes = 0;
66 uchar_t nxtfillchar;
67 char *prog = argv[0];
68 /*
69 * Default Parameters
70 */
71 int write_count = BIGFILESIZE;
72 uchar_t fillchar = DATA;
73 int block_size = BLOCKSZ;
74 char *filename = NULL;
75 char *operation = NULL;
76 offset_t noffset, offset = 0;
77 int verbose = 0;
78 int rsync = 0;
79 int wsync = 0;
80
81 /*
82 * Process Arguments
83 */
84 while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) {
85 switch (c) {
86 case 'b':
87 block_size = atoi(optarg);
88 break;
89 case 'c':
90 write_count = atoi(optarg);
91 break;
92 case 'd':
93 if (optarg[0] == 'R')
94 fillchar = 'R'; /* R = random data */
95 else
96 fillchar = atoi(optarg);
97 break;
98 case 's':
99 offset = atoll(optarg);
100 break;
101 case 'f':
102 filename = optarg;
103 break;
104 case 'o':
105 operation = optarg;
106 break;
107 case 'v':
108 verbose = 1;
109 break;
110 case 'w':
111 wsync = 1;
112 break;
113 case 'r':
114 rsync = 1;
115 break;
116 case '?':
117 (void) printf("unknown arg %c\n", optopt);
118 usage(prog);
119 break;
120 }
121 }
122
123 /*
124 * Validate Parameters
125 */
126 if (!filename) {
127 (void) printf("Filename not specified (-f <file>)\n");
128 err++;
129 }
130
131 if (!operation) {
132 (void) printf("Operation not specified (-o <operation>).\n");
133 err++;
134 }
135
136 if (block_size > BIGBUFFERSIZE) {
137 (void) printf("block_size is too large max==%d.\n",
138 BIGBUFFERSIZE);
139 err++;
140 }
141
142 if (err) {
143 usage(prog); /* no return */
144 return (1);
145 }
146
147 /*
148 * Prepare the buffer and determine the requested operation
149 */
150 nxtfillchar = fillchar;
151 k = 0;
152
153 if (fillchar == 'R')
154 srand(time(NULL));
155
156 for (i = 0; i < block_size; i++) {
157 bigbuffer[i] = nxtfillchar;
158
159 if (fillchar == 0) {
160 if ((k % DATA_RANGE) == 0) {
161 k = 0;
162 }
163 nxtfillchar = k++;
164 } else if (fillchar == 'R') {
165 nxtfillchar = rand() & 0xff;
166 }
167 }
168
169 /*
170 * using the strncmp of operation will make the operation match the
171 * first shortest match - as the operations are unique from the first
172 * character this means that we match single character operations
173 */
174 if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 ||
175 (strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) {
176 oflag = (O_RDWR|O_CREAT);
177 } else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) {
178 oflag = (O_RDWR|O_APPEND);
179 } else {
180 (void) printf("valid operations are <create|append> not '%s'\n",
181 operation);
182 usage(prog);
183 }
184
185 if (rsync) {
186 oflag = oflag | O_RSYNC;
187 }
188
189 if (wsync) {
190 oflag = oflag | O_SYNC;
191 }
192
193 /*
194 * Given an operation (create/overwrite/append), open the file
195 * accordingly and perform a write of the appropriate type.
196 */
197 if ((bigfd = open(filename, oflag, 0666)) == -1) {
198 (void) printf("open %s: failed [%s]%d. Aborting!\n", filename,
199 strerror(errno), errno);
200 exit(errno);
201 }
202 noffset = lseek64(bigfd, offset, SEEK_SET);
203 if (noffset != offset) {
204 (void) printf("llseek %s (%lld/%lld) failed [%s]%d.Aborting!\n",
205 filename, offset, noffset, strerror(errno), errno);
206 exit(errno);
207 }
208
209 if (verbose) {
210 (void) printf("%s: block_size = %d, write_count = %d, "
211 "offset = %lld, ", filename, block_size,
212 write_count, offset);
213 if (fillchar == 'R') {
214 (void) printf("data = [random]\n");
215 } else {
216 (void) printf("data = %s%d\n",
217 (fillchar == 0) ? "0->" : "",
218 (fillchar == 0) ? DATA_RANGE : fillchar);
219 }
220 }
221
222 for (i = 0; i < write_count; i++) {
223 ssize_t n;
224 if (fillchar == 'R')
225 randomize_buffer(block_size);
226
227 if ((n = write(bigfd, &bigbuffer, block_size)) == -1) {
228 (void) printf("write failed (%ld), good_writes = %"
229 PRId64 ", " "error: %s[%d]\n",
230 (long)n, good_writes,
231 strerror(errno),
232 errno);
233 exit(errno);
234 }
235 good_writes++;
236 }
237
238 if (verbose) {
239 (void) printf("Success: good_writes = %" PRId64 "(%"
240 PRId64 ")\n", good_writes, (good_writes * block_size));
241 }
242
243 return (0);
244 }
245
246 static void
usage(char * prog)247 usage(char *prog)
248 {
249 (void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name"
250 " [-b block_size]\n"
251 "\t[-s offset] [-c write_count] [-d data]\n\n"
252 "Where [data] equal to zero causes chars "
253 "0->%d to be repeated throughout, or [data]\n"
254 "equal to 'R' for pseudorandom data.\n",
255 prog, DATA_RANGE);
256
257 exit(1);
258 }
259