1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright (c) 2018 by Delphix. All rights reserved. 14 */ 15 16 #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> 23 24 static int bsize = 0; 25 static int count = 0; 26 static char *ifile = NULL; 27 static char *ofile = NULL; 28 static off_t stride = 0; 29 static off_t seek = 0; 30 static const char *execname = "stride_dd"; 31 32 static void usage(void); 33 static void parse_options(int argc, char *argv[]); 34 35 static void 36 usage(void) 37 { 38 (void) fprintf(stderr, 39 "usage: %s -i inputfile -o outputfile -b blocksize -c count \n" 40 " -s stride [ -k seekblocks]\n" 41 "\n" 42 "Simplified version of dd that supports the stride option.\n" 43 "A stride of n means that for each block written, n - 1 blocks\n" 44 "are skipped in both the input and output file. A stride of 1\n" 45 "means that blocks are read and written consecutively.\n" 46 "All numeric parameters must be integers.\n" 47 "\n" 48 " inputfile: File to read from\n" 49 " outputfile: File to write to\n" 50 " blocksize: Size of each block to read/write\n" 51 " count: Number of blocks to read/write\n" 52 " stride: Read/write a block then skip (stride - 1) blocks\n" 53 " seekblocks: Number of blocks to skip at start of output\n", 54 execname); 55 (void) exit(1); 56 } 57 58 static void 59 parse_options(int argc, char *argv[]) 60 { 61 int c; 62 int errflag = 0; 63 64 execname = argv[0]; 65 66 extern char *optarg; 67 extern int optind, optopt; 68 69 while ((c = getopt(argc, argv, ":b:c:i:o:s:k:")) != -1) { 70 switch (c) { 71 case 'b': 72 bsize = atoi(optarg); 73 break; 74 75 case 'c': 76 count = atoi(optarg); 77 break; 78 79 case 'i': 80 ifile = optarg; 81 break; 82 83 case 'o': 84 ofile = optarg; 85 break; 86 87 case 's': 88 stride = atoi(optarg); 89 break; 90 91 case 'k': 92 seek = atoi(optarg); 93 break; 94 95 case ':': 96 (void) fprintf(stderr, 97 "Option -%c requires an operand\n", optopt); 98 errflag++; 99 break; 100 101 case '?': 102 default: 103 (void) fprintf(stderr, 104 "Unrecognized option: -%c\n", optopt); 105 errflag++; 106 break; 107 } 108 109 if (errflag) { 110 (void) usage(); 111 } 112 } 113 114 if (bsize <= 0 || count <= 0 || stride <= 0 || ifile == NULL || 115 ofile == NULL || seek < 0) { 116 (void) fprintf(stderr, 117 "Required parameter(s) missing or invalid.\n"); 118 (void) usage(); 119 } 120 } 121 122 int 123 main(int argc, char *argv[]) 124 { 125 int i; 126 int ifd; 127 int ofd; 128 void *buf; 129 int c; 130 131 parse_options(argc, argv); 132 133 ifd = open(ifile, O_RDONLY); 134 if (ifd == -1) { 135 (void) fprintf(stderr, "%s: %s: ", execname, ifile); 136 perror("open"); 137 exit(2); 138 } 139 140 ofd = open(ofile, O_WRONLY | O_CREAT, 0666); 141 if (ofd == -1) { 142 (void) fprintf(stderr, "%s: %s: ", execname, ofile); 143 perror("open"); 144 exit(2); 145 } 146 147 /* 148 * We use valloc because some character block devices expect a 149 * page-aligned buffer. 150 */ 151 int err = posix_memalign(&buf, 4096, bsize); 152 if (err != 0) { 153 (void) fprintf(stderr, 154 "%s: %s\n", execname, strerror(err)); 155 exit(2); 156 } 157 158 if (seek > 0) { 159 if (lseek(ofd, seek * bsize, SEEK_CUR) == -1) { 160 perror("output lseek"); 161 exit(2); 162 } 163 } 164 165 for (i = 0; i < count; i++) { 166 c = read(ifd, buf, bsize); 167 if (c != bsize) { 168 169 perror("read"); 170 exit(2); 171 } 172 if (c != bsize) { 173 if (c < 0) { 174 perror("read"); 175 } else { 176 (void) fprintf(stderr, 177 "%s: unexpected short read, read %d " 178 "bytes, expected %d\n", execname, 179 c, bsize); 180 } 181 exit(2); 182 } 183 184 c = write(ofd, buf, bsize); 185 if (c != bsize) { 186 if (c < 0) { 187 perror("write"); 188 } else { 189 (void) fprintf(stderr, 190 "%s: unexpected short write, wrote %d " 191 "bytes, expected %d\n", execname, 192 c, bsize); 193 } 194 exit(2); 195 } 196 197 if (stride > 1) { 198 if (lseek(ifd, (stride - 1) * bsize, SEEK_CUR) == -1) { 199 perror("input lseek"); 200 exit(2); 201 } 202 if (lseek(ofd, (stride - 1) * bsize, SEEK_CUR) == -1) { 203 perror("output lseek"); 204 exit(2); 205 } 206 } 207 } 208 free(buf); 209 210 (void) close(ofd); 211 (void) close(ifd); 212 213 return (0); 214 } 215