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 * $FreeBSD$ 21 */ 22 23 /* 24 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #pragma ident "@(#)file_write.c 1.4 07/10/09 SMI" 29 30 #include "file_common.h" 31 #include <inttypes.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 static char *execname; 43 44 int 45 main(int argc, char **argv) 46 { 47 int bigfd; 48 int c; 49 int oflag = 0; 50 int err = 0; 51 int k; 52 long i; 53 int64_t good_writes = 0; 54 uint8_t nxtfillchar; 55 /* 56 * Default Parameters 57 */ 58 int write_count = BIGFILESIZE; 59 uint8_t fillchar = DATA; 60 int block_size = BLOCKSZ; 61 char *filename = NULL; 62 char *operation = NULL; 63 off_t noffset, offset = 0; 64 int verbose = 0; 65 int rsync = 0; 66 int wsync = 0; 67 68 execname = argv[0]; 69 70 /* 71 * Process Arguments 72 */ 73 while ((c = getopt(argc, argv, "b:c:d:s:f:o:vwr")) != -1) { 74 switch (c) { 75 case 'b': 76 block_size = atoi(optarg); 77 break; 78 case 'c': 79 write_count = atoi(optarg); 80 break; 81 case 'd': 82 fillchar = atoi(optarg); 83 break; 84 case 's': 85 offset = atoll(optarg); 86 break; 87 case 'f': 88 filename = optarg; 89 break; 90 case 'o': 91 operation = optarg; 92 break; 93 case 'v': 94 verbose = 1; 95 break; 96 case 'w': 97 wsync = 1; 98 break; 99 case 'r': 100 rsync = 1; 101 break; 102 case '?': 103 (void) printf("unknown arg %c\n", optopt); 104 usage(); 105 break; 106 } 107 } 108 109 /* 110 * Validate Parameters 111 */ 112 if (!filename) { 113 (void) printf("Filename not specified (-f <file>)\n"); 114 err++; 115 } 116 117 if (!operation) { 118 (void) printf("Operation not specified (-o <operation>).\n"); 119 err++; 120 } 121 122 if (block_size > BIGBUFFERSIZE) { 123 (void) printf("block_size is too large max==%d.\n", 124 BIGBUFFERSIZE); 125 err++; 126 } 127 128 if (err) usage(); 129 130 /* 131 * Prepare the buffer and determine the requested operation 132 */ 133 nxtfillchar = fillchar; 134 k = 0; 135 136 for (i = 0; i < block_size; i++) { 137 bigbuffer[i] = nxtfillchar; 138 139 if (fillchar == 0) { 140 if ((k % DATA_RANGE) == 0) { 141 k = 0; 142 } 143 nxtfillchar = k++; 144 } 145 } 146 147 /* 148 * using the strncmp of operation will make the operation match the 149 * first shortest match - as the operations are unique from the first 150 * character this means that we match single character operations 151 */ 152 if ((strncmp(operation, "create", strlen(operation) + 1)) == 0 || 153 (strncmp(operation, "overwrite", strlen(operation) + 1)) == 0) { 154 oflag = (O_RDWR|O_CREAT); 155 } else if ((strncmp(operation, "append", strlen(operation) + 1)) == 0) { 156 oflag = (O_RDWR|O_APPEND); 157 } else { 158 (void) printf("valid operations are <create|append> not '%s'\n", 159 operation); 160 usage(); 161 } 162 163 #ifdef UNSUPPORTED 164 if (rsync) { 165 oflag = oflag | O_RSYNC; 166 } 167 #endif 168 169 if (wsync) { 170 oflag = oflag | O_SYNC; 171 } 172 173 /* 174 * Given an operation (create/overwrite/append), open the file 175 * accordingly and perform a write of the appropriate type. 176 */ 177 if ((bigfd = open(filename, oflag, 0666)) == -1) { 178 (void) printf("open %s: failed [%s]%d. Aborting!\n", filename, 179 strerror(errno), errno); 180 exit(errno); 181 } 182 noffset = lseek(bigfd, offset, SEEK_SET); 183 if (noffset != offset) { 184 (void) printf("lseek %s (%"PRId64"/%"PRId64") " 185 "failed [%s]%d. Aborting!\n", 186 filename, offset, noffset, strerror(errno), errno); 187 exit(errno); 188 } 189 190 if (verbose) { 191 (void) printf("%s: block_size = %d, write_count = %d, " 192 "offset = %"PRId64", data = %s%d\n", filename, block_size, 193 write_count, offset, 194 (fillchar == 0) ? "0->" : "", 195 (fillchar == 0) ? DATA_RANGE : fillchar); 196 } 197 198 for (i = 0; i < write_count; i++) { 199 ssize_t n; 200 201 if ((n = write(bigfd, &bigbuffer, block_size)) == -1) { 202 (void) printf("write failed (%ld), " 203 "good_writes = %"PRId64", " 204 "error: %s[%d]\n", (long)n, good_writes, 205 strerror(errno), errno); 206 exit(errno); 207 } 208 good_writes++; 209 } 210 211 if (verbose) { 212 (void) printf("Success: good_writes = %"PRId64" (%"PRId64")\n", 213 good_writes, (good_writes * block_size)); 214 } 215 216 return (0); 217 } 218 219 static void 220 usage(void) 221 { 222 char *base = (char *)"file_write"; 223 char *exec = (char *)execname; 224 225 if (exec != NULL) 226 exec = strdup(exec); 227 if (exec != NULL) 228 base = basename(exec); 229 230 (void) printf("Usage: %s [-v] -o {create,overwrite,append} -f file_name" 231 " [-b block_size]\n" 232 "\t[-s offset] [-c write_count] [-d data]\n" 233 "\twhere [data] equal to zero causes chars " 234 "0->%d to be repeated throughout\n", base, DATA_RANGE); 235 236 if (exec) { 237 free(exec); 238 } 239 240 exit(1); 241 } 242