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 http://www.opensolaris.org/os/licensing.
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 * $FreeBSD$
21 */
22
23/*
24 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 */
27
28#pragma ident	"@(#)file_write.c	1.4	07/10/09 SMI"
29
30#include "file_common.h"
31#include <inttypes.h>
32#include <libgen.h>
33
34static unsigned char bigbuffer[BIGBUFFERSIZE];
35
36/*
37 * Writes (or appends) a given value to a file repeatedly.
38 * See header file for defaults.
39 */
40
41static void usage(void);
42static char *execname;
43
44int
45main(int argc, char **argv)
46{
47	int		bigfd;
48	int		c;
49	int		oflag = 0;
50	int		err = 0;
51	int		k;
52	long		i;
53	int64_t		good_writes = 0;
54	uint8_t		nxtfillchar;
55	/*
56	 * Default Parameters
57	 */
58	int		write_count = BIGFILESIZE;
59	uint8_t		fillchar = DATA;
60	int		block_size = BLOCKSZ;
61	char		*filename = NULL;
62	char		*operation = NULL;
63	off_t		noffset, offset = 0;
64	int		verbose = 0;
65	int		rsync = 0;
66	int		wsync = 0;
67
68	execname = argv[0];
69
70	/*
71	 * Process Arguments
72	 */
73	while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) {
74		switch (c) {
75			case 'b':
76				block_size = atoi(optarg);
77				break;
78			case 'c':
79				write_count = atoi(optarg);
80				break;
81			case 'd':
82				fillchar = atoi(optarg);
83				break;
84			case 's':
85				offset = atoll(optarg);
86				break;
87			case 'f':
88				filename = optarg;
89				break;
90			case 'o':
91				operation = optarg;
92				break;
93			case 'v':
94				verbose = 1;
95				break;
96			case 'w':
97				wsync = 1;
98				break;
99			case 'r':
100				rsync = 1;
101				break;
102			case '?':
103				(void) printf("unknown arg %c\n", optopt);
104				usage();
105				break;
106		}
107	}
108
109	/*
110	 * Validate Parameters
111	 */
112	if (!filename) {
113		(void) printf("Filename not specified (-f <file>)\n");
114		err++;
115	}
116
117	if (!operation) {
118		(void) printf("Operation not specified (-o <operation>).\n");
119		err++;
120	}
121
122	if (block_size > BIGBUFFERSIZE) {
123		(void) printf("block_size is too large max==%d.\n",
124		    BIGBUFFERSIZE);
125		err++;
126	}
127
128	if (err) usage();
129
130	/*
131	 * Prepare the buffer and determine the requested operation
132	 */
133	nxtfillchar = fillchar;
134	k = 0;
135
136	for (i = 0; i < block_size; i++) {
137		bigbuffer[i] = nxtfillchar;
138
139		if (fillchar == 0) {
140			if ((k % DATA_RANGE) == 0) {
141				k = 0;
142			}
143			nxtfillchar = k++;
144		}
145	}
146
147	/*
148	 * using the strncmp of operation will make the operation match the
149	 * first shortest match - as the operations are unique from the first
150	 * character this means that we match single character operations
151	 */
152	if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 ||
153	    (strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) {
154		oflag = (O_RDWR|O_CREAT);
155	} else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) {
156		oflag = (O_RDWR|O_APPEND);
157	} else {
158		(void) printf("valid operations are <create|append> not '%s'\n",
159		    operation);
160		usage();
161	}
162
163#ifdef UNSUPPORTED
164	if (rsync) {
165		oflag = oflag | O_RSYNC;
166	}
167#endif
168
169	if (wsync) {
170		oflag = oflag | O_SYNC;
171	}
172
173	/*
174	 * Given an operation (create/overwrite/append), open the file
175	 * accordingly and perform a write of the appropriate type.
176	 */
177	if ((bigfd = open(filename, oflag, 0666)) == -1) {
178		(void) printf("open %s: failed [%s]%d. Aborting!\n", filename,
179		    strerror(errno), errno);
180		exit(errno);
181	}
182	noffset = lseek(bigfd, offset, SEEK_SET);
183	if (noffset != offset) {
184		(void) printf("lseek %s (%"PRId64"/%"PRId64") "
185		    "failed [%s]%d. Aborting!\n",
186		    filename, offset, noffset, strerror(errno), errno);
187		exit(errno);
188	}
189
190	if (verbose) {
191		(void) printf("%s: block_size = %d, write_count = %d, "
192		    "offset = %"PRId64", data = %s%d\n", filename, block_size,
193		    write_count, offset,
194		    (fillchar == 0) ? "0->" : "",
195		    (fillchar == 0) ? DATA_RANGE : fillchar);
196	}
197
198	for (i = 0; i < write_count; i++) {
199		ssize_t n;
200
201		if ((n = write(bigfd, &bigbuffer, block_size)) == -1) {
202			(void) printf("write failed (%ld), "
203			    "good_writes = %"PRId64", "
204			    "error: %s[%d]\n", (long)n, good_writes,
205			    strerror(errno), errno);
206			exit(errno);
207		}
208		good_writes++;
209	}
210
211	if (verbose) {
212		(void) printf("Success: good_writes = %"PRId64" (%"PRId64")\n",
213		    good_writes, (good_writes * block_size));
214	}
215
216	return (0);
217}
218
219static void
220usage(void)
221{
222	char *base = (char *)"file_write";
223	char *exec = (char *)execname;
224
225	if (exec != NULL)
226		exec = strdup(exec);
227	if (exec != NULL)
228		base = basename(exec);
229
230	(void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name"
231	    " [-b block_size]\n"
232	    "\t[-s offset] [-c write_count] [-d data]\n"
233	    "\twhere [data] equal to zero causes chars "
234	    "0->%d to be repeated throughout\n", base, DATA_RANGE);
235
236	if (exec) {
237		free(exec);
238	}
239
240	exit(1);
241}
242