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  */
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
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
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