xref: /freebsd-src/sys/contrib/openzfs/tests/zfs-tests/cmd/file/file_append.c (revision 271171e0d97b88ba2a7c3bf750c9672b484c1c13)
1716fd348SMartin Matuska /*
2716fd348SMartin Matuska  * CDDL HEADER START
3716fd348SMartin Matuska  *
4716fd348SMartin Matuska  * The contents of this file are subject to the terms of the
5716fd348SMartin Matuska  * Common Development and Distribution License (the "License").
6716fd348SMartin Matuska  * You may not use this file except in compliance with the License.
7716fd348SMartin Matuska  *
8716fd348SMartin Matuska  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*271171e0SMartin Matuska  * or https://opensource.org/licenses/CDDL-1.0.
10716fd348SMartin Matuska  * See the License for the specific language governing permissions
11716fd348SMartin Matuska  * and limitations under the License.
12716fd348SMartin Matuska  *
13716fd348SMartin Matuska  * When distributing Covered Code, include this CDDL HEADER in each
14716fd348SMartin Matuska  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15716fd348SMartin Matuska  * If applicable, add the following below this CDDL HEADER, with the
16716fd348SMartin Matuska  * fields enclosed by brackets "[]" replaced with your own identifying
17716fd348SMartin Matuska  * information: Portions Copyright [yyyy] [name of copyright owner]
18716fd348SMartin Matuska  *
19716fd348SMartin Matuska  * CDDL HEADER END
20716fd348SMartin Matuska  */
21716fd348SMartin Matuska 
22716fd348SMartin Matuska /*
23716fd348SMartin Matuska  * Copyright (c) 2022 by Triad National Security, LLC
24716fd348SMartin Matuska  */
25716fd348SMartin Matuska 
26716fd348SMartin Matuska #include "file_common.h"
27716fd348SMartin Matuska #include <unistd.h>
28716fd348SMartin Matuska #include <sys/sysmacros.h>
29716fd348SMartin Matuska 
30716fd348SMartin Matuska static char *filename = NULL;
31716fd348SMartin Matuska static int expected_offset = -1;
32716fd348SMartin Matuska static int blocksize = 131072; /* 128KiB */
33716fd348SMartin Matuska static int numblocks = 8;
34716fd348SMartin Matuska static const char *execname = "file_append";
35716fd348SMartin Matuska static int use_odirect = 0;
36716fd348SMartin Matuska 
37716fd348SMartin Matuska static void
usage(void)38716fd348SMartin Matuska usage(void)
39716fd348SMartin Matuska {
40716fd348SMartin Matuska 	(void) fprintf(stderr,
41716fd348SMartin Matuska 	    "usage %s -f filename -e expected_offset [-b blocksize] \n"
42716fd348SMartin Matuska 	    "         [-n numblocks] [-d use_odirect] [-h help]\n"
43716fd348SMartin Matuska 	    "\n"
44716fd348SMartin Matuska 	    "Opens a file using O_APPEND and writes numblocks blocksize\n"
45716fd348SMartin Matuska 	    "blocks to filename.\n"
46716fd348SMartin Matuska 	    "Checks if expected_offst == lseek(fd, 0, SEEK_CUR)).\n"
47716fd348SMartin Matuska 	    "\n"
48716fd348SMartin Matuska 	    "    filename:         File to open with O_APPEND and write to.\n"
49716fd348SMartin Matuska 	    "    expected_offset:  Expected file offset after writing\n"
50716fd348SMartin Matuska 	    "                      blocksize numblocks to filename\n"
51716fd348SMartin Matuska 	    "    blocksize:        Size of each block to writei (must be at\n"
52716fd348SMartin Matuska 	    "                      least >= 512). If using use_odirect (-d)\n"
53716fd348SMartin Matuska 	    "                      must be a mutltiple of _SC_PAGE_SIZE\n"
54716fd348SMartin Matuska 	    "    numblocks:        Total number of blocksized blocks to\n"
55716fd348SMartin Matuska 	    "                      write.\n"
56716fd348SMartin Matuska 	    "    use_odirect:      Open file using O_DIRECT.\n"
57716fd348SMartin Matuska 	    "    help:             Print usage information and exit.\n"
58716fd348SMartin Matuska 	    "\n"
59716fd348SMartin Matuska 	    "    Required parameters:\n"
60716fd348SMartin Matuska 	    "    filename\n"
61716fd348SMartin Matuska 	    "    expected_offset\n"
62716fd348SMartin Matuska 	    "\n"
63716fd348SMartin Matuska 	    "    Default values:\n"
64716fd348SMartin Matuska 	    "    blocksize   -> 131072 (128 KiB)\n"
65716fd348SMartin Matuska 	    "    numblocks   -> 8\n"
66716fd348SMartin Matuska 	    "    use_odirect -> False\n",
67716fd348SMartin Matuska 	    execname);
68716fd348SMartin Matuska 	(void) exit(1);
69716fd348SMartin Matuska }
70716fd348SMartin Matuska 
71716fd348SMartin Matuska static void
parse_options(int argc,char * argv[])72716fd348SMartin Matuska parse_options(int argc, char *argv[])
73716fd348SMartin Matuska {
74716fd348SMartin Matuska 	int c;
75716fd348SMartin Matuska 	int errflag = 0;
76716fd348SMartin Matuska 	extern char *optarg;
77716fd348SMartin Matuska 	extern int optind, optopt;
78716fd348SMartin Matuska 
79716fd348SMartin Matuska 	while ((c = getopt(argc, argv, "b:de:f:hn:")) != -1) {
80716fd348SMartin Matuska 		switch (c) {
81716fd348SMartin Matuska 			case 'b':
82716fd348SMartin Matuska 				blocksize = atoi(optarg);
83716fd348SMartin Matuska 				break;
84716fd348SMartin Matuska 			case 'd':
85716fd348SMartin Matuska 				use_odirect = 1;
86716fd348SMartin Matuska 				break;
87716fd348SMartin Matuska 			case 'e':
88716fd348SMartin Matuska 				expected_offset = atoi(optarg);
89716fd348SMartin Matuska 				break;
90716fd348SMartin Matuska 			case 'f':
91716fd348SMartin Matuska 				filename = optarg;
92716fd348SMartin Matuska 				break;
93716fd348SMartin Matuska 			case 'h':
94716fd348SMartin Matuska 				(void) usage();
95716fd348SMartin Matuska 				break;
96716fd348SMartin Matuska 			case 'n':
97716fd348SMartin Matuska 				numblocks = atoi(optarg);
98716fd348SMartin Matuska 				break;
99716fd348SMartin Matuska 			case ':':
100716fd348SMartin Matuska 				(void) fprintf(stderr,
101716fd348SMartin Matuska 				    "Option -%c requires an operand\n",
102716fd348SMartin Matuska 				    optopt);
103716fd348SMartin Matuska 				errflag++;
104716fd348SMartin Matuska 				break;
105716fd348SMartin Matuska 			case '?':
106716fd348SMartin Matuska 			default:
107716fd348SMartin Matuska 				(void) fprintf(stderr,
108716fd348SMartin Matuska 				    "Unrecognized option: -%c\n", optopt);
109716fd348SMartin Matuska 				errflag++;
110716fd348SMartin Matuska 				break;
111716fd348SMartin Matuska 		}
112716fd348SMartin Matuska 	}
113716fd348SMartin Matuska 
114716fd348SMartin Matuska 	if (errflag)
115716fd348SMartin Matuska 		(void) usage();
116716fd348SMartin Matuska 
117716fd348SMartin Matuska 	if (use_odirect && ((blocksize % sysconf(_SC_PAGE_SIZE)) != 0)) {
118716fd348SMartin Matuska 		(void) fprintf(stderr,
119716fd348SMartin Matuska 		    "blocksize parameter invalid when using O_DIRECT.\n");
120716fd348SMartin Matuska 		(void) usage();
121716fd348SMartin Matuska 	}
122716fd348SMartin Matuska 
123716fd348SMartin Matuska 	if (blocksize < 512 || expected_offset < 0 || filename == NULL ||
124716fd348SMartin Matuska 	    numblocks <= 0) {
125716fd348SMartin Matuska 		(void) fprintf(stderr,
126716fd348SMartin Matuska 		    "Required parameters(s) missing or invalid value for "
127716fd348SMartin Matuska 		    "parameter.\n");
128716fd348SMartin Matuska 		(void) usage();
129716fd348SMartin Matuska 	}
130716fd348SMartin Matuska }
131716fd348SMartin Matuska 
132716fd348SMartin Matuska int
main(int argc,char * argv[])133716fd348SMartin Matuska main(int argc, char *argv[])
134716fd348SMartin Matuska {
135716fd348SMartin Matuska 	int		err;
136716fd348SMartin Matuska 	const char	*datapattern = "0xf00ba3";
137716fd348SMartin Matuska 	int		fd = -1;
138716fd348SMartin Matuska 	int		fd_flags = O_WRONLY | O_CREAT | O_APPEND;
139716fd348SMartin Matuska 	int		buf_offset = 0;
140716fd348SMartin Matuska 	char		*buf;
141716fd348SMartin Matuska 
142716fd348SMartin Matuska 	parse_options(argc, argv);
143716fd348SMartin Matuska 
144716fd348SMartin Matuska 	if (use_odirect)
145716fd348SMartin Matuska 		fd_flags |= O_DIRECT;
146716fd348SMartin Matuska 
147716fd348SMartin Matuska 	fd = open(filename, fd_flags, 0666);
148716fd348SMartin Matuska 	if (fd == -1) {
149716fd348SMartin Matuska 		(void) fprintf(stderr, "%s: %s: ", execname, filename);
150716fd348SMartin Matuska 		perror("open");
151716fd348SMartin Matuska 		(void) exit(2);
152716fd348SMartin Matuska 	}
153716fd348SMartin Matuska 
154716fd348SMartin Matuska 	err = posix_memalign((void **)&buf, sysconf(_SC_PAGE_SIZE),
155716fd348SMartin Matuska 	    blocksize);
156716fd348SMartin Matuska 
157716fd348SMartin Matuska 	if (err != 0) {
158716fd348SMartin Matuska 		(void) fprintf(stderr,
159716fd348SMartin Matuska 		    "%s: %s\n", execname, strerror(err));
160716fd348SMartin Matuska 		(void) exit(2);
161716fd348SMartin Matuska 	}
162716fd348SMartin Matuska 
163716fd348SMartin Matuska 	/* Putting known data pattern in buffer */
164716fd348SMartin Matuska 	int left = blocksize;
165716fd348SMartin Matuska 	while (left) {
166716fd348SMartin Matuska 		size_t amt = MIN(strlen(datapattern), left);
167716fd348SMartin Matuska 		memcpy(&buf[buf_offset], datapattern, amt);
168716fd348SMartin Matuska 		buf_offset += amt;
169716fd348SMartin Matuska 		left -= amt;
170716fd348SMartin Matuska 	}
171716fd348SMartin Matuska 
172716fd348SMartin Matuska 	for (int i = 0; i < numblocks; i++) {
173716fd348SMartin Matuska 		int wrote = write(fd, buf, blocksize);
174716fd348SMartin Matuska 
175716fd348SMartin Matuska 		if (wrote != blocksize) {
176716fd348SMartin Matuska 			if (wrote < 0) {
177716fd348SMartin Matuska 				perror("write");
178716fd348SMartin Matuska 			} else {
179716fd348SMartin Matuska 				(void) fprintf(stderr,
180716fd348SMartin Matuska 				    "%s: unexpected short write, wrote %d "
181716fd348SMartin Matuska 				    "byte, expected %d\n", execname, wrote,
182716fd348SMartin Matuska 				    blocksize);
183716fd348SMartin Matuska 			}
184716fd348SMartin Matuska 			(void) exit(2);
185716fd348SMartin Matuska 		}
186716fd348SMartin Matuska 	}
187716fd348SMartin Matuska 
188716fd348SMartin Matuska 	/* Getting current file offset */
189716fd348SMartin Matuska 	off_t off = lseek(fd, 0, SEEK_CUR);
190716fd348SMartin Matuska 
191716fd348SMartin Matuska 	if (off == -1) {
192716fd348SMartin Matuska 		perror("output seek");
193716fd348SMartin Matuska 		(void) exit(2);
194716fd348SMartin Matuska 	} else if (off != expected_offset) {
195716fd348SMartin Matuska 		(void) fprintf(stderr,
196716fd348SMartin Matuska 		    "%s: expected offset %d but current offset in %s is set "
197716fd348SMartin Matuska 		    "to %ld\n", execname, expected_offset, filename,
198716fd348SMartin Matuska 		    (long int)off);
199716fd348SMartin Matuska 		(void) exit(2);
200716fd348SMartin Matuska 	}
201716fd348SMartin Matuska 
202716fd348SMartin Matuska 	(void) close(fd);
203716fd348SMartin Matuska 	free(buf);
204716fd348SMartin Matuska 
205716fd348SMartin Matuska 	return (0);
206716fd348SMartin Matuska }
207