1132624Smarcel/*
2132624Smarcel * CDDL HEADER START
3132624Smarcel *
4132624Smarcel * The contents of this file are subject to the terms of the
5132624Smarcel * Common Development and Distribution License (the "License").
6132624Smarcel * You may not use this file except in compliance with the License.
7132624Smarcel *
8132624Smarcel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9132624Smarcel * or https://opensource.org/licenses/CDDL-1.0.
10132624Smarcel * See the License for the specific language governing permissions
11132624Smarcel * and limitations under the License.
12132624Smarcel *
13132624Smarcel * When distributing Covered Code, include this CDDL HEADER in each
14132624Smarcel * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15132624Smarcel * If applicable, add the following below this CDDL HEADER, with the
16132624Smarcel * fields enclosed by brackets "[]" replaced with your own identifying
17132624Smarcel * information: Portions Copyright [yyyy] [name of copyright owner]
18132624Smarcel *
19132624Smarcel * CDDL HEADER END
20132624Smarcel */
21132624Smarcel
22132624Smarcel/*
23132624Smarcel * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24132624Smarcel * Use is subject to license terms.
25132624Smarcel */
26132624Smarcel
27132624Smarcel#include "file_common.h"
28132624Smarcel#include <libgen.h>
29132624Smarcel#include <string.h>
30142151Skan#include <inttypes.h>
31142151Skan#include <sys/types.h>
32142151Skan#include <unistd.h>
33142151Skan#include <stdlib.h>
34175808Sjhb#include <time.h>
35178670Sjhb#include <stdint.h>
36132624Smarcel
37132624Smarcelstatic unsigned char bigbuffer[BIGBUFFERSIZE];
38132624Smarcel
39178670Sjhb/*
40178670Sjhb * Writes (or appends) a given value to a file repeatedly.
41142151Skan * See header file for defaults.
42175808Sjhb */
43149954Smarcel
44178713Sjhbstatic void usage(char *);
45178670Sjhb
46132624Smarcel/*
47132624Smarcel * pseudo-randomize the buffer
48178670Sjhb */
49142151Skanstatic void randomize_buffer(int block_size) {
50178670Sjhb	int i;
51132624Smarcel	char rnd = rand() & 0xff;
52178713Sjhb	for (i = 0; i < block_size; i++)
53132624Smarcel		bigbuffer[i] ^= rnd;
54142151Skan}
55142151Skan
56246893Smarcelint
57246893Smarcelmain(int argc, char **argv)
58178670Sjhb{
59178670Sjhb	int		bigfd;
60178670Sjhb	int		c;
61132624Smarcel	int		oflag = 0;
62132624Smarcel	int		err = 0;
63178670Sjhb	int		k;
64178670Sjhb	long		i;
65175808Sjhb	int64_t		good_writes = 0;
66163439Sjhb	uchar_t		nxtfillchar;
67286305Skib	char		*prog = argv[0];
68163439Sjhb	/*
69163439Sjhb	 * Default Parameters
70163439Sjhb	 */
71163439Sjhb	int		write_count = BIGFILESIZE;
72163439Sjhb	uchar_t		fillchar = DATA;
73163439Sjhb	int		block_size = BLOCKSZ;
74163439Sjhb	char		*filename = NULL;
75163439Sjhb	char		*operation = NULL;
76163439Sjhb	offset_t	noffset, offset = 0;
77163439Sjhb	int		verbose = 0;
78163439Sjhb	int		rsync = 0;
79163439Sjhb	int		wsync = 0;
80163439Sjhb
81163439Sjhb	/*
82163439Sjhb	 * Process Arguments
83163439Sjhb	 */
84163439Sjhb	while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) {
85163439Sjhb		switch (c) {
86178670Sjhb			case 'b':
87178670Sjhb				block_size = atoi(optarg);
88178670Sjhb				break;
89178670Sjhb			case 'c':
90178670Sjhb				write_count = atoi(optarg);
91178670Sjhb				break;
92178670Sjhb			case 'd':
93178670Sjhb				if (optarg[0] == 'R')
94178670Sjhb					fillchar = 'R'; /* R = random data */
95178670Sjhb				else
96178670Sjhb					fillchar = atoi(optarg);
97178670Sjhb				break;
98178670Sjhb			case 's':
99178670Sjhb				offset = atoll(optarg);
100178670Sjhb				break;
101178670Sjhb			case 'f':
102178670Sjhb				filename = optarg;
103178670Sjhb				break;
104178670Sjhb			case 'o':
105178670Sjhb				operation = optarg;
106178670Sjhb				break;
107178670Sjhb			case 'v':
108178670Sjhb				verbose = 1;
109178670Sjhb				break;
110178670Sjhb			case 'w':
111178670Sjhb				wsync = 1;
112178670Sjhb				break;
113178670Sjhb			case 'r':
114178670Sjhb				rsync = 1;
115178670Sjhb				break;
116178670Sjhb			case '?':
117178670Sjhb				(void) printf("unknown arg %c\n", optopt);
118178670Sjhb				usage(prog);
119178670Sjhb				break;
120178670Sjhb		}
121178670Sjhb	}
122178670Sjhb
123178670Sjhb	/*
124178670Sjhb	 * Validate Parameters
125178670Sjhb	 */
126178670Sjhb	if (!filename) {
127178670Sjhb		(void) printf("Filename not specified (-f <file>)\n");
128178670Sjhb		err++;
129178670Sjhb	}
130178670Sjhb
131178670Sjhb	if (!operation) {
132178713Sjhb		(void) printf("Operation not specified (-o <operation>).\n");
133178670Sjhb		err++;
134178670Sjhb	}
135178670Sjhb
136178713Sjhb	if (block_size > BIGBUFFERSIZE) {
137178670Sjhb		(void) printf("block_size is too large max==%d.\n",
138178670Sjhb		    BIGBUFFERSIZE);
139178670Sjhb		err++;
140178670Sjhb	}
141178670Sjhb
142178670Sjhb	if (err) {
143178670Sjhb		usage(prog); /* no return */
144178670Sjhb		return (1);
145178670Sjhb	}
146178670Sjhb
147178670Sjhb	/*
148178670Sjhb	 * Prepare the buffer and determine the requested operation
149178670Sjhb	 */
150178670Sjhb	nxtfillchar = fillchar;
151178670Sjhb	k = 0;
152178670Sjhb
153178670Sjhb	if (fillchar == 'R')
154178670Sjhb		srand(time(NULL));
155178670Sjhb
156178670Sjhb	for (i = 0; i < block_size; i++) {
157178670Sjhb		bigbuffer[i] = nxtfillchar;
158178670Sjhb
159178670Sjhb		if (fillchar == 0) {
160178670Sjhb			if ((k % DATA_RANGE) == 0) {
161178670Sjhb				k = 0;
162178670Sjhb			}
163178670Sjhb			nxtfillchar = k++;
164178670Sjhb		} else if (fillchar == 'R') {
165178670Sjhb			nxtfillchar = rand() & 0xff;
166178670Sjhb		}
167178670Sjhb	}
168178670Sjhb
169178670Sjhb	/*
170178670Sjhb	 * using the strncmp of operation will make the operation match the
171178670Sjhb	 * first shortest match - as the operations are unique from the first
172178670Sjhb	 * character this means that we match single character operations
173178670Sjhb	 */
174178670Sjhb	if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 ||
175178670Sjhb	    (strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) {
176178670Sjhb		oflag = (O_RDWR|O_CREAT);
177178670Sjhb	} else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) {
178178670Sjhb		oflag = (O_RDWR|O_APPEND);
179178670Sjhb	} else {
180178670Sjhb		(void) printf("valid operations are <create|append> not '%s'\n",
181178670Sjhb		    operation);
182178670Sjhb		usage(prog);
183178670Sjhb	}
184178670Sjhb
185178670Sjhb	if (rsync) {
186178670Sjhb		oflag = oflag | O_RSYNC;
187178670Sjhb	}
188178670Sjhb
189178670Sjhb	if (wsync) {
190178670Sjhb		oflag = oflag | O_SYNC;
191148802Smarcel	}
192148802Smarcel
193148802Smarcel	/*
194142151Skan	 * Given an operation (create/overwrite/append), open the file
195178713Sjhb	 * accordingly and perform a write of the appropriate type.
196142151Skan	 */
197142151Skan	if ((bigfd = open(filename, oflag, 0666)) == -1) {
198148802Smarcel		(void) printf("open %s: failed [%s]%d. Aborting!\n", filename,
199148802Smarcel		    strerror(errno), errno);
200132624Smarcel		exit(errno);
201148802Smarcel	}
202178670Sjhb	noffset = lseek64(bigfd, offset, SEEK_SET);
203178670Sjhb	if (noffset != offset) {
204178670Sjhb		(void) printf("llseek %s (%lld/%lld) failed [%s]%d.Aborting!\n",
205132624Smarcel		    filename, offset, noffset, strerror(errno), errno);
206132624Smarcel		exit(errno);
207132624Smarcel	}
208132624Smarcel
209132624Smarcel	if (verbose) {
210148802Smarcel		(void) printf("%s: block_size = %d, write_count = %d, "
211148802Smarcel		    "offset = %lld, ", filename, block_size,
212148802Smarcel		    write_count, offset);
213148802Smarcel		if (fillchar == 'R') {
214148802Smarcel			(void) printf("data = [random]\n");
215148802Smarcel		} else {
216148802Smarcel			(void) printf("data = %s%d\n",
217148802Smarcel			    (fillchar == 0) ? "0->" : "",
218132624Smarcel			    (fillchar == 0) ? DATA_RANGE : fillchar);
219132624Smarcel		}
220132624Smarcel	}
221132624Smarcel
222132624Smarcel	for (i = 0; i < write_count; i++) {
223142151Skan		ssize_t n;
224132624Smarcel		if (fillchar == 'R')
225178713Sjhb			randomize_buffer(block_size);
226132624Smarcel
227132624Smarcel		if ((n = write(bigfd, &bigbuffer, block_size)) == -1) {
228132624Smarcel			(void) printf("write failed (%ld), good_writes = %"
229132624Smarcel			    PRId64 ", " "error: %s[%d]\n",
230132624Smarcel			    (long)n, good_writes,
231132624Smarcel			    strerror(errno),
232178713Sjhb			    errno);
233132624Smarcel			exit(errno);
234132624Smarcel		}
235132624Smarcel		good_writes++;
236132624Smarcel	}
237148802Smarcel
238132624Smarcel	if (verbose) {
239148802Smarcel		(void) printf("Success: good_writes = %" PRId64 "(%"
240132624Smarcel		    PRId64 ")\n", good_writes, (good_writes * block_size));
241148802Smarcel	}
242148802Smarcel
243148802Smarcel	return (0);
244148802Smarcel}
245148802Smarcel
246148802Smarcelstatic void
247148802Smarcelusage(char *prog)
248142151Skan{
249148802Smarcel	(void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name"
250148802Smarcel	    " [-b block_size]\n"
251142151Skan	    "\t[-s offset] [-c write_count] [-d data]\n\n"
252142151Skan	    "Where [data] equal to zero causes chars "
253178670Sjhb	    "0->%d to be repeated throughout, or [data]\n"
254178670Sjhb	    "equal to 'R' for pseudorandom data.\n",
255178670Sjhb	    prog, DATA_RANGE);
256178670Sjhb
257178670Sjhb	exit(1);
258178670Sjhb}
259178670Sjhb