1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * CDDL HEADER START 4 * 5 * The contents of this file are subject to the terms of the 6 * Common Development and Distribution License (the "License"). 7 * You may not use this file except in compliance with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or https://opensource.org/licenses/CDDL-1.0. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 23 /* 24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include "file_common.h" 29 #include <libgen.h> 30 #include <string.h> 31 #include <inttypes.h> 32 #include <sys/types.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <time.h> 36 #include <stdint.h> 37 38 static unsigned char bigbuffer[BIGBUFFERSIZE]; 39 40 /* 41 * Writes (or appends) a given value to a file repeatedly. 42 * See header file for defaults. 43 */ 44 45 static void usage(char *); 46 47 /* 48 * pseudo-randomize the buffer 49 */ 50 static void randomize_buffer(int block_size) { 51 int i; 52 char rnd = rand() & 0xff; 53 for (i = 0; i < block_size; i++) 54 bigbuffer[i] ^= rnd; 55 } 56 57 int 58 main(int argc, char **argv) 59 { 60 int bigfd; 61 int c; 62 int oflag = 0; 63 int err = 0; 64 int k; 65 long i; 66 int64_t good_writes = 0; 67 uchar_t nxtfillchar; 68 char *prog = argv[0]; 69 /* 70 * Default Parameters 71 */ 72 int write_count = BIGFILESIZE; 73 uchar_t fillchar = DATA; 74 int block_size = BLOCKSZ; 75 char *filename = NULL; 76 char *operation = NULL; 77 offset_t noffset, offset = 0; 78 int verbose = 0; 79 int rsync = 0; 80 int wsync = 0; 81 82 /* 83 * Process Arguments 84 */ 85 while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) { 86 switch (c) { 87 case 'b': 88 block_size = atoi(optarg); 89 break; 90 case 'c': 91 write_count = atoi(optarg); 92 break; 93 case 'd': 94 if (optarg[0] == 'R') 95 fillchar = 'R'; /* R = random data */ 96 else 97 fillchar = atoi(optarg); 98 break; 99 case 's': 100 offset = atoll(optarg); 101 break; 102 case 'f': 103 filename = optarg; 104 break; 105 case 'o': 106 operation = optarg; 107 break; 108 case 'v': 109 verbose = 1; 110 break; 111 case 'w': 112 wsync = 1; 113 break; 114 case 'r': 115 rsync = 1; 116 break; 117 case '?': 118 (void) printf("unknown arg %c\n", optopt); 119 usage(prog); 120 break; 121 } 122 } 123 124 /* 125 * Validate Parameters 126 */ 127 if (!filename) { 128 (void) printf("Filename not specified (-f <file>)\n"); 129 err++; 130 } 131 132 if (!operation) { 133 (void) printf("Operation not specified (-o <operation>).\n"); 134 err++; 135 } 136 137 if (block_size > BIGBUFFERSIZE) { 138 (void) printf("block_size is too large max==%d.\n", 139 BIGBUFFERSIZE); 140 err++; 141 } 142 143 if (err) { 144 usage(prog); /* no return */ 145 return (1); 146 } 147 148 /* 149 * Prepare the buffer and determine the requested operation 150 */ 151 nxtfillchar = fillchar; 152 k = 0; 153 154 if (fillchar == 'R') 155 srand(time(NULL)); 156 157 for (i = 0; i < block_size; i++) { 158 bigbuffer[i] = nxtfillchar; 159 160 if (fillchar == 0) { 161 if ((k % DATA_RANGE) == 0) { 162 k = 0; 163 } 164 nxtfillchar = k++; 165 } else if (fillchar == 'R') { 166 nxtfillchar = rand() & 0xff; 167 } 168 } 169 170 /* 171 * using the strncmp of operation will make the operation match the 172 * first shortest match - as the operations are unique from the first 173 * character this means that we match single character operations 174 */ 175 if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 || 176 (strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) { 177 oflag = (O_RDWR|O_CREAT); 178 } else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) { 179 oflag = (O_RDWR|O_APPEND); 180 } else { 181 (void) printf("valid operations are <create|append> not '%s'\n", 182 operation); 183 usage(prog); 184 } 185 186 if (rsync) { 187 oflag = oflag | O_RSYNC; 188 } 189 190 if (wsync) { 191 oflag = oflag | O_SYNC; 192 } 193 194 /* 195 * Given an operation (create/overwrite/append), open the file 196 * accordingly and perform a write of the appropriate type. 197 */ 198 if ((bigfd = open(filename, oflag, 0666)) == -1) { 199 (void) printf("open %s: failed [%s]%d. Aborting!\n", filename, 200 strerror(errno), errno); 201 exit(errno); 202 } 203 noffset = lseek64(bigfd, offset, SEEK_SET); 204 if (noffset != offset) { 205 (void) printf("llseek %s (%lld/%lld) failed [%s]%d.Aborting!\n", 206 filename, offset, noffset, strerror(errno), errno); 207 exit(errno); 208 } 209 210 if (verbose) { 211 (void) printf("%s: block_size = %d, write_count = %d, " 212 "offset = %lld, ", filename, block_size, 213 write_count, offset); 214 if (fillchar == 'R') { 215 (void) printf("data = [random]\n"); 216 } else { 217 (void) printf("data = %s%d\n", 218 (fillchar == 0) ? "0->" : "", 219 (fillchar == 0) ? DATA_RANGE : fillchar); 220 } 221 } 222 223 for (i = 0; i < write_count; i++) { 224 ssize_t n; 225 if (fillchar == 'R') 226 randomize_buffer(block_size); 227 228 if ((n = write(bigfd, &bigbuffer, block_size)) == -1) { 229 (void) printf("write failed (%ld), good_writes = %" 230 PRId64 ", " "error: %s[%d]\n", 231 (long)n, good_writes, 232 strerror(errno), 233 errno); 234 exit(errno); 235 } 236 good_writes++; 237 } 238 239 if (verbose) { 240 (void) printf("Success: good_writes = %" PRId64 "(%" 241 PRId64 ")\n", good_writes, (good_writes * block_size)); 242 } 243 244 return (0); 245 } 246 247 static void 248 usage(char *prog) 249 { 250 (void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name" 251 " [-b block_size]\n" 252 "\t[-s offset] [-c write_count] [-d data]\n\n" 253 "Where [data] equal to zero causes chars " 254 "0->%d to be repeated throughout, or [data]\n" 255 "equal to 'R' for pseudorandom data.\n", 256 prog, DATA_RANGE); 257 258 exit(1); 259 } 260