zfs/tests/zfs-tests/cmd/file/file_append.c

207 lines
5.1 KiB
C

/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2022 by Triad National Security, LLC
*/
#include "file_common.h"
#include <unistd.h>
#include <sys/sysmacros.h>
static char *filename = NULL;
static int expected_offset = -1;
static int blocksize = 131072; /* 128KiB */
static int numblocks = 8;
static const char *execname = "file_append";
static int use_odirect = 0;
static void
usage(void)
{
(void) fprintf(stderr,
"usage %s -f filename -e expected_offset [-b blocksize] \n"
" [-n numblocks] [-d use_odirect] [-h help]\n"
"\n"
"Opens a file using O_APPEND and writes numblocks blocksize\n"
"blocks to filename.\n"
"Checks if expected_offst == lseek(fd, 0, SEEK_CUR)).\n"
"\n"
" filename: File to open with O_APPEND and write to.\n"
" expected_offset: Expected file offset after writing\n"
" blocksize numblocks to filename\n"
" blocksize: Size of each block to writei (must be at\n"
" least >= 512). If using use_odirect (-d)\n"
" must be a mutltiple of _SC_PAGE_SIZE\n"
" numblocks: Total number of blocksized blocks to\n"
" write.\n"
" use_odirect: Open file using O_DIRECT.\n"
" help: Print usage information and exit.\n"
"\n"
" Required parameters:\n"
" filename\n"
" expected_offset\n"
"\n"
" Default values:\n"
" blocksize -> 131072 (128 KiB)\n"
" numblocks -> 8\n"
" use_odirect -> False\n",
execname);
(void) exit(1);
}
static void
parse_options(int argc, char *argv[])
{
int c;
int errflag = 0;
extern char *optarg;
extern int optind, optopt;
while ((c = getopt(argc, argv, "b:de:f:hn:")) != -1) {
switch (c) {
case 'b':
blocksize = atoi(optarg);
break;
case 'd':
use_odirect = 1;
break;
case 'e':
expected_offset = atoi(optarg);
break;
case 'f':
filename = optarg;
break;
case 'h':
(void) usage();
break;
case 'n':
numblocks = atoi(optarg);
break;
case ':':
(void) fprintf(stderr,
"Option -%c requires an operand\n",
optopt);
errflag++;
break;
case '?':
default:
(void) fprintf(stderr,
"Unrecognized option: -%c\n", optopt);
errflag++;
break;
}
}
if (errflag)
(void) usage();
if (use_odirect && ((blocksize % sysconf(_SC_PAGE_SIZE)) != 0)) {
(void) fprintf(stderr,
"blocksize parameter invalid when using O_DIRECT.\n");
(void) usage();
}
if (blocksize < 512 || expected_offset < 0 || filename == NULL ||
numblocks <= 0) {
(void) fprintf(stderr,
"Required parameters(s) missing or invalid value for "
"parameter.\n");
(void) usage();
}
}
int
main(int argc, char *argv[])
{
int err;
const char *datapattern = "0xf00ba3";
int fd = -1;
int fd_flags = O_WRONLY | O_CREAT | O_APPEND;
int buf_offset = 0;
char *buf;
parse_options(argc, argv);
if (use_odirect)
fd_flags |= O_DIRECT;
fd = open(filename, fd_flags, 0666);
if (fd == -1) {
(void) fprintf(stderr, "%s: %s: ", execname, filename);
perror("open");
(void) exit(2);
}
err = posix_memalign((void **)&buf, sysconf(_SC_PAGE_SIZE),
blocksize);
if (err != 0) {
(void) fprintf(stderr,
"%s: %s\n", execname, strerror(err));
(void) exit(2);
}
/* Putting known data pattern in buffer */
int left = blocksize;
while (left) {
size_t amt = MIN(strlen(datapattern), left);
memcpy(&buf[buf_offset], datapattern, amt);
buf_offset += amt;
left -= amt;
}
for (int i = 0; i < numblocks; i++) {
int wrote = write(fd, buf, blocksize);
if (wrote != blocksize) {
if (wrote < 0) {
perror("write");
} else {
(void) fprintf(stderr,
"%s: unexpected short write, wrote %d "
"byte, expected %d\n", execname, wrote,
blocksize);
}
(void) exit(2);
}
}
/* Getting current file offset */
off_t off = lseek(fd, 0, SEEK_CUR);
if (off == -1) {
perror("output seek");
(void) exit(2);
} else if (off != expected_offset) {
(void) fprintf(stderr,
"%s: expected offset %d but current offset in %s is set "
"to %ld\n", execname, expected_offset, filename,
(long int)off);
(void) exit(2);
}
(void) close(fd);
free(buf);
return (0);
}