Path: blob/main/sys/contrib/openzfs/tests/zfs-tests/cmd/stride_dd.c
48529 views
// SPDX-License-Identifier: CDDL-1.01/*2* This file and its contents are supplied under the terms of the3* Common Development and Distribution License ("CDDL"), version 1.0.4* You may only use this file in accordance with the terms of version5* 1.0 of the CDDL.6*7* A full copy of the text of the CDDL should have accompanied this8* source. A copy of the CDDL is also available via the Internet at9* http://www.illumos.org/license/CDDL.10*/1112/*13* Copyright (c) 2018 by Delphix. All rights reserved.14*/1516#include <sys/types.h>17#include <errno.h>18#include <fcntl.h>19#include <stdio.h>20#include <unistd.h>21#include <stdlib.h>22#include <string.h>2324static int alignment = 0;25static int bsize = 0;26static int count = 0;27static char *ifile = NULL;28static char *ofile = NULL;29static off_t stride = 1;30static off_t seek = 0;31static int seekbytes = 0;32static int if_o_direct = 0;33static int of_o_direct = 0;34static int skip = 0;35static int skipbytes = 0;36static int entire_file = 0;37static const char *execname = "stride_dd";3839static void usage(void);40static void parse_options(int argc, char *argv[]);4142static void43usage(void)44{45(void) fprintf(stderr,46"usage: %s -i inputfile -o outputfile -b blocksize [-c count]\n"47" [-s stride] [-k seekblocks] [-K seekbytes]\n"48" [-a alignment] [-d if_o_direct] [-D of_o_direct]\n"49" [-p skipblocks] [-P skipbytes] [-e entire_file]\n"50"\n"51"Simplified version of dd that supports the stride option.\n"52"A stride of n means that for each block written, n - 1 blocks\n"53"are skipped in both the input and output file. A stride of 1\n"54"means that blocks are read and written consecutively.\n"55"All numeric parameters must be integers.\n"56"\n"57" inputfile: File to read from\n"58" outputfile: File to write to\n"59" blocksize: Size of each block to read/write\n"60" count: Number of blocks to read/write (Required"61" unless -e is used)\n"62" stride: Read/write a block then skip (stride - 1) blocks"63"\n"64" seekblocks: Number of blocks to skip at start of output\n"65" seekbytes: Treat seekblocks as byte count\n"66" alignment: Alignment passed to posix_memalign() (default"67" PAGE_SIZE)\n"68" if_o_direct: Use O_DIRECT with inputfile (default no O_DIRECT)"69"\n"70" of_o_direct: Use O_DIRECT with outputfile (default no "71" O_DIRECT)\n"72" skipblocks: Number of blocks to skip at start of input "73" (default 0)\n"74" skipbytes: Treat skipblocks as byte count\n"75" entire_file: When used the entire inputfile will be read and"76" count will be ignored\n",77execname);78(void) exit(1);79}8081/*82* posix_memalign() only allows for alignments which are postive, powers of two83* and a multiple of sizeof (void *).84*/85static int86invalid_alignment(int alignment)87{88if ((alignment < 0) || (alignment & (alignment - 1)) ||89((alignment % sizeof (void *)))) {90(void) fprintf(stderr,91"Alignment must be a postive, power of two, and multiple "92"of sizeof (void *).\n");93return (1);94}95return (0);96}9798static void99parse_options(int argc, char *argv[])100{101int c;102int errflag = 0;103104execname = argv[0];105alignment = sysconf(_SC_PAGE_SIZE);106107extern char *optarg;108extern int optind, optopt;109110while ((c = getopt(argc, argv, "a:b:c:deDi:o:s:k:Kp:P")) != -1) {111switch (c) {112case 'a':113alignment = atoi(optarg);114break;115116case 'b':117bsize = atoi(optarg);118break;119120case 'c':121count = atoi(optarg);122break;123124case 'd':125if_o_direct = 1;126break;127128case 'e':129entire_file = 1;130break;131132case 'D':133of_o_direct = 1;134break;135136case 'i':137ifile = optarg;138break;139140case 'o':141ofile = optarg;142break;143144case 's':145stride = atoi(optarg);146break;147148case 'k':149seek = atoi(optarg);150break;151152case 'K':153seekbytes = 1;154break;155156case 'p':157skip = atoi(optarg);158break;159160case 'P':161skipbytes = 1;162break;163164case ':':165(void) fprintf(stderr,166"Option -%c requires an operand\n", optopt);167errflag++;168break;169170case '?':171default:172(void) fprintf(stderr,173"Unrecognized option: -%c\n", optopt);174errflag++;175break;176}177178if (errflag) {179(void) usage();180}181}182183if (bsize <= 0 || stride <= 0 || ifile == NULL || ofile == NULL ||184seek < 0 || invalid_alignment(alignment) || skip < 0) {185(void) fprintf(stderr,186"Required parameter(s) missing or invalid.\n");187(void) usage();188}189190if (count <= 0 && entire_file == 0) {191(void) fprintf(stderr,192"Required parameter(s) missing or invalid.\n");193(void) usage();194}195}196197static void198read_entire_file(int ifd, int ofd, void *buf)199{200int c;201202do {203c = read(ifd, buf, bsize);204if (c < 0) {205perror("read");206exit(2);207} else if (c != 0) {208c = write(ofd, buf, bsize);209if (c < 0) {210perror("write");211exit(2);212}213214}215if (stride > 1) {216if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {217perror("input lseek");218exit(2);219}220if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {221perror("output lseek");222exit(2);223}224}225} while (c != 0);226}227228static void229read_on_count(int ifd, int ofd, void *buf)230{231int i;232int c;233234for (i = 0; i < count; i++) {235c = read(ifd, buf, bsize);236if (c != bsize) {237if (c < 0) {238perror("read");239} else {240(void) fprintf(stderr,241"%s: unexpected short read, read %d "242"bytes, expected %d\n", execname,243c, bsize);244}245exit(2);246}247248c = write(ofd, buf, bsize);249if (c != bsize) {250if (c < 0) {251perror("write");252} else {253(void) fprintf(stderr,254"%s: unexpected short write, wrote %d "255"bytes, expected %d\n", execname,256c, bsize);257}258exit(2);259}260261if (stride > 1) {262if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) {263perror("input lseek");264exit(2);265}266if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) {267perror("output lseek");268exit(2);269}270}271}272}273274int275main(int argc, char *argv[])276{277int ifd;278int ofd;279int ifd_flags = O_RDONLY;280int ofd_flags = O_WRONLY | O_CREAT;281void *buf;282283parse_options(argc, argv);284285if (if_o_direct)286ifd_flags |= O_DIRECT;287288if (of_o_direct)289ofd_flags |= O_DIRECT;290291ifd = open(ifile, ifd_flags);292if (ifd == -1) {293(void) fprintf(stderr, "%s: %s: ", execname, ifile);294perror("open");295exit(2);296}297298ofd = open(ofile, ofd_flags, 0666);299if (ofd == -1) {300(void) fprintf(stderr, "%s: %s: ", execname, ofile);301perror("open");302exit(2);303}304305/*306* We use valloc because some character block devices expect a307* page-aligned buffer.308*/309int err = posix_memalign(&buf, alignment, bsize);310if (err != 0) {311(void) fprintf(stderr,312"%s: %s\n", execname, strerror(err));313exit(2);314}315316if (skip > 0) {317int skipamt = skipbytes == 1 ? skip : skip * bsize;318if (lseek(ifd, skipamt, SEEK_CUR) == -1) {319perror("input lseek");320exit(2);321}322}323324if (seek > 0) {325int seekamt = seekbytes == 1 ? seek : seek * bsize;326if (lseek(ofd, seekamt, SEEK_CUR) == -1) {327perror("output lseek");328exit(2);329}330}331332if (entire_file == 1)333read_entire_file(ifd, ofd, buf);334else335read_on_count(ifd, ofd, buf);336337free(buf);338339(void) close(ofd);340(void) close(ifd);341342return (0);343}344345346