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