1/*
2 * Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved.
3 * Copyright (c) International Business Machines  Corp., 2002
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * DESCRIPTION
19 *	Copy the contents of the input file to output file using direct read
20 *	and direct write. The input file size is numblks*bufsize.
21 *	The read and write calls use bufsize to perform IO. Input and output
22 *	files can be specified through commandline and is useful for running
23 *	test with raw devices as files.
24 *
25 * USAGE
26 *	diotest1 [-b bufsize] [-n numblks] [-i infile] [-o outfile]
27 *
28 * History
29 *	04/22/2002	Narasimha Sharoff nsharoff@us.ibm.com
30 */
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <signal.h>
36#include <string.h>
37#include <fcntl.h>
38#include <errno.h>
39
40#include "diotest_routines.h"
41
42#include "test.h"
43#include "safe_macros.h"
44
45char *TCID = "diotest01";	/* Test program identifier.    */
46int TST_TOTAL = 1;		/* Total number of test conditions */
47
48#ifdef O_DIRECT
49
50#define	BUFSIZE	8192
51#define	NBLKS	20
52#define	LEN	30
53#define	TRUE 1
54
55static char infile[LEN];	/* Input file. Default "infile" */
56static char outfile[LEN];	/* Output file. Default "outfile" */
57static int fd1, fd2;
58
59/*
60 * prg_usage: display the program usage.
61*/
62void prg_usage(void)
63{
64	fprintf(stderr,
65		"Usage: diotest1 [-b bufsize] [-n numblks] [-i infile] [-o outfile]\n");
66	tst_brkm(TBROK, NULL, "usage");
67}
68
69void cleanup(void)
70{
71	if (fd1 > 0)
72		close(fd1);
73	if (fd2 > 0)
74		close(fd2);
75
76	tst_rmdir();
77}
78
79int main(int argc, char *argv[])
80{
81	int bufsize = BUFSIZE;	/* Buffer size. Default 8k */
82	int numblks = NBLKS;	/* Number of blocks. Default 20 */
83	int i, n, offset;
84	char *buf;
85
86	/* Options */
87	strcpy(infile, "infile");	/* Default input file */
88	strcpy(outfile, "outfile");	/* Default outfile file */
89	while ((i = getopt(argc, argv, "b:n:i:o:")) != -1) {
90		switch (i) {
91		case 'b':
92			if ((bufsize = atoi(optarg)) <= 0) {
93				fprintf(stderr, "bufsize must be > 0\n");
94				prg_usage();
95			}
96			if (bufsize % 4096 != 0) {
97				fprintf(stderr,
98					"bufsize must be multiple of 4k\n");
99				prg_usage();
100			}
101			break;
102		case 'n':
103			if ((numblks = atoi(optarg)) <= 0) {
104				fprintf(stderr, "numblks must be > 0\n");
105				prg_usage();
106			}
107			break;
108		case 'i':
109			strcpy(infile, optarg);
110			break;
111		case 'o':
112			strcpy(outfile, optarg);
113			break;
114		default:
115			prg_usage();
116		}
117	}
118
119	tst_tmpdir();
120
121	/* Test for filesystem support of O_DIRECT */
122	int fd = open(infile, O_DIRECT | O_RDWR | O_CREAT, 0666);
123
124	if (fd < 0)
125		tst_brkm(TCONF, cleanup, "O_DIRECT not supported by FS");
126	SAFE_CLOSE(cleanup, fd);
127
128	/* Open files */
129	fd1 = SAFE_OPEN(cleanup, infile, O_DIRECT | O_RDWR | O_CREAT, 0666);
130	fd2 = SAFE_OPEN(cleanup, outfile, O_DIRECT | O_RDWR | O_CREAT, 0666);
131
132	/* Allocate for buf, Create input file */
133	buf = valloc(bufsize);
134
135	if (!buf)
136		tst_brkm(TFAIL | TERRNO, cleanup, "valloc() failed");
137
138	for (i = 0; i < numblks; i++) {
139		fillbuf(buf, bufsize, (char)(i % 256));
140		SAFE_WRITE(cleanup, 1, fd1, buf, bufsize);
141	}
142
143	/* Copy infile to outfile using direct read and direct write */
144	offset = 0;
145	SAFE_LSEEK(cleanup, fd1, offset, SEEK_SET);
146
147	while ((n = read(fd1, buf, bufsize)) > 0) {
148		SAFE_LSEEK(cleanup, fd2, offset, SEEK_SET);
149
150		SAFE_WRITE(cleanup, 1, fd2, buf, n);
151
152		offset += n;
153		SAFE_LSEEK(cleanup, fd1, offset, SEEK_SET);
154	}
155
156	/* Verify */
157	if (filecmp(infile, outfile) != 0) {
158		tst_brkm(TFAIL, cleanup, "file compare failed for %s and %s",
159			 infile, outfile);
160	}
161
162	tst_resm(TPASS, "Test passed");
163
164	cleanup();
165	tst_exit();
166}
167
168#else /* O_DIRECT */
169
170int main()
171{
172	tst_brkm(TCONF, NULL, "O_DIRECT is not defined.");
173}
174#endif /* O_DIRECT */
175