aboutsummaryrefslogtreecommitdiff
path: root/tests/zfs-tests/cmd/stride_dd/stride_dd.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/zfs-tests/cmd/stride_dd/stride_dd.c')
-rw-r--r--tests/zfs-tests/cmd/stride_dd/stride_dd.c214
1 files changed, 214 insertions, 0 deletions
diff --git a/tests/zfs-tests/cmd/stride_dd/stride_dd.c b/tests/zfs-tests/cmd/stride_dd/stride_dd.c
new file mode 100644
index 000000000000..88bd532923c7
--- /dev/null
+++ b/tests/zfs-tests/cmd/stride_dd/stride_dd.c
@@ -0,0 +1,214 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source. A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2018 by Delphix. All rights reserved.
+ */
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int bsize = 0;
+static int count = 0;
+static char *ifile = NULL;
+static char *ofile = NULL;
+static int stride = 0;
+static int seek = 0;
+static char *execname = "stride_dd";
+
+static void usage(void);
+static void parse_options(int argc, char *argv[]);
+
+static void
+usage(void)
+{
+ (void) fprintf(stderr,
+ "usage: %s -i inputfile -o outputfile -b blocksize -c count \n"
+ " -s stride [ -k seekblocks]\n"
+ "\n"
+ "Simplified version of dd that supports the stride option.\n"
+ "A stride of n means that for each block written, n - 1 blocks\n"
+ "are skipped in both the input and output file. A stride of 1\n"
+ "means that blocks are read and written consecutively.\n"
+ "All numeric parameters must be integers.\n"
+ "\n"
+ " inputfile: File to read from\n"
+ " outputfile: File to write to\n"
+ " blocksize: Size of each block to read/write\n"
+ " count: Number of blocks to read/write\n"
+ " stride: Read/write a block then skip (stride - 1) blocks\n"
+ " seekblocks: Number of blocks to skip at start of output\n",
+ execname);
+ (void) exit(1);
+}
+
+static void
+parse_options(int argc, char *argv[])
+{
+ int c;
+ int errflag = 0;
+
+ execname = argv[0];
+
+ extern char *optarg;
+ extern int optind, optopt;
+
+ while ((c = getopt(argc, argv, ":b:c:i:o:s:k:")) != -1) {
+ switch (c) {
+ case 'b':
+ bsize = atoi(optarg);
+ break;
+
+ case 'c':
+ count = atoi(optarg);
+ break;
+
+ case 'i':
+ ifile = optarg;
+ break;
+
+ case 'o':
+ ofile = optarg;
+ break;
+
+ case 's':
+ stride = atoi(optarg);
+ break;
+
+ case 'k':
+ seek = 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 (bsize <= 0 || count <= 0 || stride <= 0 || ifile == NULL ||
+ ofile == NULL || seek < 0) {
+ (void) fprintf(stderr,
+ "Required parameter(s) missing or invalid.\n");
+ (void) usage();
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ int i;
+ int ifd;
+ int ofd;
+ void *buf;
+ int c;
+
+ parse_options(argc, argv);
+
+ ifd = open(ifile, O_RDONLY);
+ if (ifd == -1) {
+ (void) fprintf(stderr, "%s: %s: ", execname, ifile);
+ perror("open");
+ exit(2);
+ }
+
+ ofd = open(ofile, O_WRONLY | O_CREAT, 0666);
+ if (ofd == -1) {
+ (void) fprintf(stderr, "%s: %s: ", execname, ofile);
+ perror("open");
+ exit(2);
+ }
+
+ /*
+ * We use valloc because some character block devices expect a
+ * page-aligned buffer.
+ */
+ int err = posix_memalign(&buf, 4096, bsize);
+ if (err != 0) {
+ (void) fprintf(stderr,
+ "%s: %s\n", execname, strerror(err));
+ exit(2);
+ }
+
+ if (seek > 0) {
+ if (lseek(ofd, seek * bsize, SEEK_CUR) == -1) {
+ perror("output lseek");
+ exit(2);
+ }
+ }
+
+ for (i = 0; i < count; i++) {
+ c = read(ifd, buf, bsize);
+ if (c != bsize) {
+
+ perror("read");
+ exit(2);
+ }
+ if (c != bsize) {
+ if (c < 0) {
+ perror("read");
+ } else {
+ (void) fprintf(stderr,
+ "%s: unexpected short read, read %d "
+ "bytes, expected %d\n", execname,
+ c, bsize);
+ }
+ exit(2);
+ }
+
+ c = write(ofd, buf, bsize);
+ if (c != bsize) {
+ if (c < 0) {
+ perror("write");
+ } else {
+ (void) fprintf(stderr,
+ "%s: unexpected short write, wrote %d "
+ "bytes, expected %d\n", execname,
+ c, bsize);
+ }
+ exit(2);
+ }
+
+ if (stride > 1) {
+ if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {
+ perror("input lseek");
+ exit(2);
+ }
+ if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {
+ perror("output lseek");
+ exit(2);
+ }
+ }
+ }
+ free(buf);
+
+ (void) close(ofd);
+ (void) close(ifd);
+
+ return (0);
+}