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