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