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/*
28 * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <limits.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <sys/statvfs.h>
40#include <sys/time.h>
41#include <sys/ioctl.h>
42#include <sys/wait.h>
43#include <sys/param.h>
44#include <string.h>
45#include <time.h>
46#include <inttypes.h>
47
48#define	FSIZE	256*1024*1024
49#define	BSIZE	512
50
51/* Initialize Globals */
52static long	fsize = FSIZE;
53static size_t	bsize = BSIZE;
54static int	count = 0;
55static int	rflag = 0;
56static uint_t	seed = 0;
57static int	vflag = 0;
58static int	errflag = 0;
59static off_t	offset = 0;
60static char	*filename = NULL;
61
62static void usage(char *execname);
63static void parse_options(int argc, char *argv[]);
64static void do_write(int fd);
65static void do_trunc(int fd);
66
67static void
68usage(char *execname)
69{
70	(void) fprintf(stderr,
71	    "usage: %s [-b blocksize] [-c count] [-f filesize]"
72	    " [-o offset] [-s seed] [-r] [-v] filename\n", execname);
73	(void) exit(1);
74}
75
76int
77main(int argc, char *argv[])
78{
79	int i = 0;
80	int fd = -1;
81
82	parse_options(argc, argv);
83
84	fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666);
85	if (fd < 0) {
86		perror("open");
87		exit(3);
88	}
89
90	for (i = 0; count == 0 || i < count; i++) {
91		(void) do_write(fd);
92		(void) do_trunc(fd);
93	}
94
95	(void) close(fd);
96	return (0);
97}
98
99static void
100parse_options(int argc, char *argv[])
101{
102	int c;
103
104	extern char *optarg;
105	extern int optind, optopt;
106
107	count = fsize / bsize;
108	seed = (uint_t)time(NULL);
109	while ((c = getopt(argc, argv, "b:c:f:o:rs:v")) != -1) {
110		switch (c) {
111			case 'b':
112				bsize = atoi(optarg);
113				break;
114
115			case 'c':
116				count = atoi(optarg);
117				break;
118
119			case 'f':
120				fsize = atoi(optarg);
121				break;
122
123			case 'o':
124				offset = atoi(optarg);
125				break;
126
127			case 'r':
128				rflag++;
129				break;
130
131			case 's':
132				seed = atoi(optarg);
133				break;
134
135			case 'v':
136				vflag++;
137				break;
138
139			case ':':
140				(void) fprintf(stderr,
141				    "Option -%c requires an operand\n", optopt);
142				errflag++;
143				break;
144
145			case '?':
146				(void) fprintf(stderr,
147				    "Unrecognized option: -%c\n", optopt);
148				errflag++;
149				break;
150		}
151
152		if (errflag) {
153			(void) usage(argv[0]);
154		}
155	}
156	if (argc <= optind) {
157		(void) fprintf(stderr,
158		    "No filename specified\n");
159		usage(argv[0]);
160	}
161	filename = argv[optind];
162
163	if (vflag) {
164		(void) fprintf(stderr, "Seed = %d\n", seed);
165	}
166	srandom(seed);
167}
168
169static void
170do_write(int fd)
171{
172	off_t	roffset = 0;
173	char	*buf = NULL;
174	char	*rbuf = NULL;
175
176	buf = (char *)calloc(1, bsize);
177	rbuf = (char *)calloc(1, bsize);
178	if (buf == NULL || rbuf == NULL) {
179		perror("malloc");
180		exit(4);
181	}
182
183	roffset = random() % fsize;
184	if (lseek64(fd, (offset + roffset), SEEK_SET) < 0) {
185		perror("lseek");
186		exit(5);
187	}
188
189	(void) strcpy(buf, "ZFS Test Suite Truncation Test");
190	if (write(fd, buf, bsize) < bsize) {
191		perror("write");
192		exit(6);
193	}
194
195	if (rflag) {
196		if (lseek64(fd, (offset + roffset), SEEK_SET) < 0) {
197			perror("lseek");
198			exit(7);
199		}
200
201		if (read(fd, rbuf, bsize) < bsize) {
202			perror("read");
203			exit(8);
204		}
205
206		if (memcmp(buf, rbuf, bsize) != 0) {
207			perror("memcmp");
208			exit(9);
209		}
210	}
211	if (vflag) {
212		(void) fprintf(stderr,
213		    "Wrote to offset %" PRId64 "\n", (offset + roffset));
214		if (rflag) {
215			(void) fprintf(stderr,
216			    "Read back from offset %" PRId64 "\n",
217			    (offset + roffset));
218		}
219	}
220
221	(void) free(buf);
222	(void) free(rbuf);
223}
224
225static void
226do_trunc(int fd)
227{
228	off_t   roffset = 0;
229
230	roffset = random() % fsize;
231	if (ftruncate64(fd, (offset + roffset))  < 0) {
232		perror("truncate");
233		exit(7);
234	}
235
236	if (vflag) {
237		(void) fprintf(stderr, "Truncated at offset %" PRId64 "\n",
238		    (offset + roffset));
239	}
240}
241