1716fd348SMartin Matuska /* 2716fd348SMartin Matuska * This file and its contents are supplied under the terms of the 3716fd348SMartin Matuska * Common Development and Distribution License ("CDDL"), version 1.0. 4716fd348SMartin Matuska * You may only use this file in accordance with the terms of version 5716fd348SMartin Matuska * 1.0 of the CDDL. 6716fd348SMartin Matuska * 7716fd348SMartin Matuska * A full copy of the text of the CDDL should have accompanied this 8716fd348SMartin Matuska * source. A copy of the CDDL is also available via the Internet at 9716fd348SMartin Matuska * http://www.illumos.org/license/CDDL. 10716fd348SMartin Matuska */ 11716fd348SMartin Matuska 12716fd348SMartin Matuska /* 13716fd348SMartin Matuska * Copyright (c) 2018 by Delphix. All rights reserved. 14716fd348SMartin Matuska */ 15716fd348SMartin Matuska 16716fd348SMartin Matuska #include <sys/types.h> 17716fd348SMartin Matuska #include <errno.h> 18716fd348SMartin Matuska #include <fcntl.h> 19716fd348SMartin Matuska #include <stdio.h> 20716fd348SMartin Matuska #include <unistd.h> 21716fd348SMartin Matuska #include <stdlib.h> 22716fd348SMartin Matuska #include <string.h> 23716fd348SMartin Matuska 24*7a7741afSMartin Matuska static int alignment = 0; 25716fd348SMartin Matuska static int bsize = 0; 26716fd348SMartin Matuska static int count = 0; 27716fd348SMartin Matuska static char *ifile = NULL; 28716fd348SMartin Matuska static char *ofile = NULL; 29*7a7741afSMartin Matuska static off_t stride = 1; 30dbd5678dSMartin Matuska static off_t seek = 0; 31*7a7741afSMartin Matuska static int seekbytes = 0; 32*7a7741afSMartin Matuska static int if_o_direct = 0; 33*7a7741afSMartin Matuska static int of_o_direct = 0; 34*7a7741afSMartin Matuska static int skip = 0; 35*7a7741afSMartin Matuska static int skipbytes = 0; 36*7a7741afSMartin Matuska static int entire_file = 0; 37a0b956f5SMartin Matuska static const char *execname = "stride_dd"; 38716fd348SMartin Matuska 39716fd348SMartin Matuska static void usage(void); 40716fd348SMartin Matuska static void parse_options(int argc, char *argv[]); 41716fd348SMartin Matuska 42716fd348SMartin Matuska static void 43716fd348SMartin Matuska usage(void) 44716fd348SMartin Matuska { 45716fd348SMartin Matuska (void) fprintf(stderr, 46*7a7741afSMartin Matuska "usage: %s -i inputfile -o outputfile -b blocksize [-c count]\n" 47*7a7741afSMartin Matuska " [-s stride] [-k seekblocks] [-K seekbytes]\n" 48*7a7741afSMartin Matuska " [-a alignment] [-d if_o_direct] [-D of_o_direct]\n" 49*7a7741afSMartin Matuska " [-p skipblocks] [-P skipbytes] [-e entire_file]\n" 50716fd348SMartin Matuska "\n" 51716fd348SMartin Matuska "Simplified version of dd that supports the stride option.\n" 52716fd348SMartin Matuska "A stride of n means that for each block written, n - 1 blocks\n" 53716fd348SMartin Matuska "are skipped in both the input and output file. A stride of 1\n" 54716fd348SMartin Matuska "means that blocks are read and written consecutively.\n" 55716fd348SMartin Matuska "All numeric parameters must be integers.\n" 56716fd348SMartin Matuska "\n" 57716fd348SMartin Matuska " inputfile: File to read from\n" 58716fd348SMartin Matuska " outputfile: File to write to\n" 59716fd348SMartin Matuska " blocksize: Size of each block to read/write\n" 60*7a7741afSMartin Matuska " count: Number of blocks to read/write (Required" 61*7a7741afSMartin Matuska " unless -e is used)\n" 62*7a7741afSMartin Matuska " stride: Read/write a block then skip (stride - 1) blocks" 63*7a7741afSMartin Matuska "\n" 64*7a7741afSMartin Matuska " seekblocks: Number of blocks to skip at start of output\n" 65*7a7741afSMartin Matuska " seekbytes: Treat seekblocks as byte count\n" 66*7a7741afSMartin Matuska " alignment: Alignment passed to posix_memalign() (default" 67*7a7741afSMartin Matuska " PAGE_SIZE)\n" 68*7a7741afSMartin Matuska " if_o_direct: Use O_DIRECT with inputfile (default no O_DIRECT)" 69*7a7741afSMartin Matuska "\n" 70*7a7741afSMartin Matuska " of_o_direct: Use O_DIRECT with outputfile (default no " 71*7a7741afSMartin Matuska " O_DIRECT)\n" 72*7a7741afSMartin Matuska " skipblocks: Number of blocks to skip at start of input " 73*7a7741afSMartin Matuska " (default 0)\n" 74*7a7741afSMartin Matuska " skipbytes: Treat skipblocks as byte count\n" 75*7a7741afSMartin Matuska " entire_file: When used the entire inputfile will be read and" 76*7a7741afSMartin Matuska " count will be ignored\n", 77716fd348SMartin Matuska execname); 78716fd348SMartin Matuska (void) exit(1); 79716fd348SMartin Matuska } 80716fd348SMartin Matuska 81*7a7741afSMartin Matuska /* 82*7a7741afSMartin Matuska * posix_memalign() only allows for alignments which are postive, powers of two 83*7a7741afSMartin Matuska * and a multiple of sizeof (void *). 84*7a7741afSMartin Matuska */ 85*7a7741afSMartin Matuska static int 86*7a7741afSMartin Matuska invalid_alignment(int alignment) 87*7a7741afSMartin Matuska { 88*7a7741afSMartin Matuska if ((alignment < 0) || (alignment & (alignment - 1)) || 89*7a7741afSMartin Matuska ((alignment % sizeof (void *)))) { 90*7a7741afSMartin Matuska (void) fprintf(stderr, 91*7a7741afSMartin Matuska "Alignment must be a postive, power of two, and multiple " 92*7a7741afSMartin Matuska "of sizeof (void *).\n"); 93*7a7741afSMartin Matuska return (1); 94*7a7741afSMartin Matuska } 95*7a7741afSMartin Matuska return (0); 96*7a7741afSMartin Matuska } 97*7a7741afSMartin Matuska 98716fd348SMartin Matuska static void 99716fd348SMartin Matuska parse_options(int argc, char *argv[]) 100716fd348SMartin Matuska { 101716fd348SMartin Matuska int c; 102716fd348SMartin Matuska int errflag = 0; 103716fd348SMartin Matuska 104716fd348SMartin Matuska execname = argv[0]; 105*7a7741afSMartin Matuska alignment = sysconf(_SC_PAGE_SIZE); 106716fd348SMartin Matuska 107716fd348SMartin Matuska extern char *optarg; 108716fd348SMartin Matuska extern int optind, optopt; 109716fd348SMartin Matuska 110*7a7741afSMartin Matuska while ((c = getopt(argc, argv, "a:b:c:deDi:o:s:k:Kp:P")) != -1) { 111716fd348SMartin Matuska switch (c) { 112*7a7741afSMartin Matuska case 'a': 113*7a7741afSMartin Matuska alignment = atoi(optarg); 114*7a7741afSMartin Matuska break; 115*7a7741afSMartin Matuska 116716fd348SMartin Matuska case 'b': 117716fd348SMartin Matuska bsize = atoi(optarg); 118716fd348SMartin Matuska break; 119716fd348SMartin Matuska 120716fd348SMartin Matuska case 'c': 121716fd348SMartin Matuska count = atoi(optarg); 122716fd348SMartin Matuska break; 123716fd348SMartin Matuska 124*7a7741afSMartin Matuska case 'd': 125*7a7741afSMartin Matuska if_o_direct = 1; 126*7a7741afSMartin Matuska break; 127*7a7741afSMartin Matuska 128*7a7741afSMartin Matuska case 'e': 129*7a7741afSMartin Matuska entire_file = 1; 130*7a7741afSMartin Matuska break; 131*7a7741afSMartin Matuska 132*7a7741afSMartin Matuska case 'D': 133*7a7741afSMartin Matuska of_o_direct = 1; 134*7a7741afSMartin Matuska break; 135*7a7741afSMartin Matuska 136716fd348SMartin Matuska case 'i': 137716fd348SMartin Matuska ifile = optarg; 138716fd348SMartin Matuska break; 139716fd348SMartin Matuska 140716fd348SMartin Matuska case 'o': 141716fd348SMartin Matuska ofile = optarg; 142716fd348SMartin Matuska break; 143716fd348SMartin Matuska 144716fd348SMartin Matuska case 's': 145716fd348SMartin Matuska stride = atoi(optarg); 146716fd348SMartin Matuska break; 147716fd348SMartin Matuska 148716fd348SMartin Matuska case 'k': 149716fd348SMartin Matuska seek = atoi(optarg); 150716fd348SMartin Matuska break; 151716fd348SMartin Matuska 152*7a7741afSMartin Matuska case 'K': 153*7a7741afSMartin Matuska seekbytes = 1; 154*7a7741afSMartin Matuska break; 155*7a7741afSMartin Matuska 156*7a7741afSMartin Matuska case 'p': 157*7a7741afSMartin Matuska skip = atoi(optarg); 158*7a7741afSMartin Matuska break; 159*7a7741afSMartin Matuska 160*7a7741afSMartin Matuska case 'P': 161*7a7741afSMartin Matuska skipbytes = 1; 162*7a7741afSMartin Matuska break; 163*7a7741afSMartin Matuska 164716fd348SMartin Matuska case ':': 165716fd348SMartin Matuska (void) fprintf(stderr, 166716fd348SMartin Matuska "Option -%c requires an operand\n", optopt); 167716fd348SMartin Matuska errflag++; 168716fd348SMartin Matuska break; 169716fd348SMartin Matuska 170716fd348SMartin Matuska case '?': 171716fd348SMartin Matuska default: 172716fd348SMartin Matuska (void) fprintf(stderr, 173716fd348SMartin Matuska "Unrecognized option: -%c\n", optopt); 174716fd348SMartin Matuska errflag++; 175716fd348SMartin Matuska break; 176716fd348SMartin Matuska } 177716fd348SMartin Matuska 178716fd348SMartin Matuska if (errflag) { 179716fd348SMartin Matuska (void) usage(); 180716fd348SMartin Matuska } 181716fd348SMartin Matuska } 182716fd348SMartin Matuska 183*7a7741afSMartin Matuska if (bsize <= 0 || stride <= 0 || ifile == NULL || ofile == NULL || 184*7a7741afSMartin Matuska seek < 0 || invalid_alignment(alignment) || skip < 0) { 185*7a7741afSMartin Matuska (void) fprintf(stderr, 186*7a7741afSMartin Matuska "Required parameter(s) missing or invalid.\n"); 187*7a7741afSMartin Matuska (void) usage(); 188*7a7741afSMartin Matuska } 189*7a7741afSMartin Matuska 190*7a7741afSMartin Matuska if (count <= 0 && entire_file == 0) { 191716fd348SMartin Matuska (void) fprintf(stderr, 192716fd348SMartin Matuska "Required parameter(s) missing or invalid.\n"); 193716fd348SMartin Matuska (void) usage(); 194716fd348SMartin Matuska } 195716fd348SMartin Matuska } 196716fd348SMartin Matuska 197*7a7741afSMartin Matuska static void 198*7a7741afSMartin Matuska read_entire_file(int ifd, int ofd, void *buf) 199716fd348SMartin Matuska { 200716fd348SMartin Matuska int c; 201716fd348SMartin Matuska 202*7a7741afSMartin Matuska do { 203*7a7741afSMartin Matuska c = read(ifd, buf, bsize); 204*7a7741afSMartin Matuska if (c < 0) { 205*7a7741afSMartin Matuska perror("read"); 206*7a7741afSMartin Matuska exit(2); 207*7a7741afSMartin Matuska } else if (c != 0) { 208*7a7741afSMartin Matuska c = write(ofd, buf, bsize); 209*7a7741afSMartin Matuska if (c < 0) { 210*7a7741afSMartin Matuska perror("write"); 211716fd348SMartin Matuska exit(2); 212716fd348SMartin Matuska } 213716fd348SMartin Matuska 214*7a7741afSMartin Matuska } 215*7a7741afSMartin Matuska if (stride > 1) { 216*7a7741afSMartin Matuska if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) { 217*7a7741afSMartin Matuska perror("input lseek"); 218716fd348SMartin Matuska exit(2); 219716fd348SMartin Matuska } 220*7a7741afSMartin Matuska if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) { 221716fd348SMartin Matuska perror("output lseek"); 222716fd348SMartin Matuska exit(2); 223716fd348SMartin Matuska } 224716fd348SMartin Matuska } 225*7a7741afSMartin Matuska } while (c != 0); 226*7a7741afSMartin Matuska } 227*7a7741afSMartin Matuska 228*7a7741afSMartin Matuska static void 229*7a7741afSMartin Matuska read_on_count(int ifd, int ofd, void *buf) 230*7a7741afSMartin Matuska { 231*7a7741afSMartin Matuska int i; 232*7a7741afSMartin Matuska int c; 233716fd348SMartin Matuska 234716fd348SMartin Matuska for (i = 0; i < count; i++) { 235716fd348SMartin Matuska c = read(ifd, buf, bsize); 236716fd348SMartin Matuska if (c != bsize) { 237716fd348SMartin Matuska if (c < 0) { 238716fd348SMartin Matuska perror("read"); 239716fd348SMartin Matuska } else { 240716fd348SMartin Matuska (void) fprintf(stderr, 241716fd348SMartin Matuska "%s: unexpected short read, read %d " 242716fd348SMartin Matuska "bytes, expected %d\n", execname, 243716fd348SMartin Matuska c, bsize); 244716fd348SMartin Matuska } 245716fd348SMartin Matuska exit(2); 246716fd348SMartin Matuska } 247716fd348SMartin Matuska 248716fd348SMartin Matuska c = write(ofd, buf, bsize); 249716fd348SMartin Matuska if (c != bsize) { 250716fd348SMartin Matuska if (c < 0) { 251716fd348SMartin Matuska perror("write"); 252716fd348SMartin Matuska } else { 253716fd348SMartin Matuska (void) fprintf(stderr, 254716fd348SMartin Matuska "%s: unexpected short write, wrote %d " 255716fd348SMartin Matuska "bytes, expected %d\n", execname, 256716fd348SMartin Matuska c, bsize); 257716fd348SMartin Matuska } 258716fd348SMartin Matuska exit(2); 259716fd348SMartin Matuska } 260716fd348SMartin Matuska 261716fd348SMartin Matuska if (stride > 1) { 262716fd348SMartin Matuska if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) { 263716fd348SMartin Matuska perror("input lseek"); 264716fd348SMartin Matuska exit(2); 265716fd348SMartin Matuska } 266716fd348SMartin Matuska if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) { 267716fd348SMartin Matuska perror("output lseek"); 268716fd348SMartin Matuska exit(2); 269716fd348SMartin Matuska } 270716fd348SMartin Matuska } 271716fd348SMartin Matuska } 272*7a7741afSMartin Matuska } 273*7a7741afSMartin Matuska 274*7a7741afSMartin Matuska int 275*7a7741afSMartin Matuska main(int argc, char *argv[]) 276*7a7741afSMartin Matuska { 277*7a7741afSMartin Matuska int ifd; 278*7a7741afSMartin Matuska int ofd; 279*7a7741afSMartin Matuska int ifd_flags = O_RDONLY; 280*7a7741afSMartin Matuska int ofd_flags = O_WRONLY | O_CREAT; 281*7a7741afSMartin Matuska void *buf; 282*7a7741afSMartin Matuska 283*7a7741afSMartin Matuska parse_options(argc, argv); 284*7a7741afSMartin Matuska 285*7a7741afSMartin Matuska if (if_o_direct) 286*7a7741afSMartin Matuska ifd_flags |= O_DIRECT; 287*7a7741afSMartin Matuska 288*7a7741afSMartin Matuska if (of_o_direct) 289*7a7741afSMartin Matuska ofd_flags |= O_DIRECT; 290*7a7741afSMartin Matuska 291*7a7741afSMartin Matuska ifd = open(ifile, ifd_flags); 292*7a7741afSMartin Matuska if (ifd == -1) { 293*7a7741afSMartin Matuska (void) fprintf(stderr, "%s: %s: ", execname, ifile); 294*7a7741afSMartin Matuska perror("open"); 295*7a7741afSMartin Matuska exit(2); 296*7a7741afSMartin Matuska } 297*7a7741afSMartin Matuska 298*7a7741afSMartin Matuska ofd = open(ofile, ofd_flags, 0666); 299*7a7741afSMartin Matuska if (ofd == -1) { 300*7a7741afSMartin Matuska (void) fprintf(stderr, "%s: %s: ", execname, ofile); 301*7a7741afSMartin Matuska perror("open"); 302*7a7741afSMartin Matuska exit(2); 303*7a7741afSMartin Matuska } 304*7a7741afSMartin Matuska 305*7a7741afSMartin Matuska /* 306*7a7741afSMartin Matuska * We use valloc because some character block devices expect a 307*7a7741afSMartin Matuska * page-aligned buffer. 308*7a7741afSMartin Matuska */ 309*7a7741afSMartin Matuska int err = posix_memalign(&buf, alignment, bsize); 310*7a7741afSMartin Matuska if (err != 0) { 311*7a7741afSMartin Matuska (void) fprintf(stderr, 312*7a7741afSMartin Matuska "%s: %s\n", execname, strerror(err)); 313*7a7741afSMartin Matuska exit(2); 314*7a7741afSMartin Matuska } 315*7a7741afSMartin Matuska 316*7a7741afSMartin Matuska if (skip > 0) { 317*7a7741afSMartin Matuska int skipamt = skipbytes == 1 ? skip : skip * bsize; 318*7a7741afSMartin Matuska if (lseek(ifd, skipamt, SEEK_CUR) == -1) { 319*7a7741afSMartin Matuska perror("input lseek"); 320*7a7741afSMartin Matuska exit(2); 321*7a7741afSMartin Matuska } 322*7a7741afSMartin Matuska } 323*7a7741afSMartin Matuska 324*7a7741afSMartin Matuska if (seek > 0) { 325*7a7741afSMartin Matuska int seekamt = seekbytes == 1 ? seek : seek * bsize; 326*7a7741afSMartin Matuska if (lseek(ofd, seekamt, SEEK_CUR) == -1) { 327*7a7741afSMartin Matuska perror("output lseek"); 328*7a7741afSMartin Matuska exit(2); 329*7a7741afSMartin Matuska } 330*7a7741afSMartin Matuska } 331*7a7741afSMartin Matuska 332*7a7741afSMartin Matuska if (entire_file == 1) 333*7a7741afSMartin Matuska read_entire_file(ifd, ofd, buf); 334*7a7741afSMartin Matuska else 335*7a7741afSMartin Matuska read_on_count(ifd, ofd, buf); 336*7a7741afSMartin Matuska 337716fd348SMartin Matuska free(buf); 338716fd348SMartin Matuska 339716fd348SMartin Matuska (void) close(ofd); 340716fd348SMartin Matuska (void) close(ifd); 341716fd348SMartin Matuska 342716fd348SMartin Matuska return (0); 343716fd348SMartin Matuska } 344