| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * This file contains the ini and command liner parser main. | 
 | 3 |  */ | 
 | 4 | #include <stdio.h> | 
 | 5 | #include <stdlib.h> | 
 | 6 | #include <unistd.h> | 
 | 7 | #include <ctype.h> | 
 | 8 | #include <string.h> | 
 | 9 | #include <errno.h> | 
 | 10 | #include <limits.h> | 
 | 11 |  | 
 | 12 | #include "parse.h" | 
 | 13 |  | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 14 | static void show_option_range(struct fio_option *o) | 
 | 15 | { | 
 | 16 | 	if (!o->minval && !o->maxval) | 
 | 17 | 		return; | 
 | 18 |  | 
| Jens Axboe | ec1aee0 | 2007-02-26 13:18:47 +0100 | [diff] [blame] | 19 | 	printf("%20s: min=%d, max=%d\n", "range", o->minval, o->maxval); | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 20 | } | 
 | 21 |  | 
 | 22 | static void show_option_values(struct fio_option *o) | 
 | 23 | { | 
 | 24 | 	const char *msg; | 
 | 25 | 	int i = 0; | 
 | 26 |  | 
 | 27 | 	do { | 
 | 28 | 		msg = o->posval[i].ival; | 
 | 29 | 		if (!msg) | 
 | 30 | 			break; | 
 | 31 |  | 
 | 32 | 		if (!i) | 
| Jens Axboe | ec1aee0 | 2007-02-26 13:18:47 +0100 | [diff] [blame] | 33 | 			printf("%20s: ", "valid values"); | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 34 |  | 
 | 35 | 		printf("%s,", msg); | 
 | 36 | 		i++; | 
 | 37 | 	} while (i < PARSE_MAX_VP); | 
 | 38 |  | 
 | 39 | 	if (i) | 
 | 40 | 		printf("\n"); | 
 | 41 | } | 
 | 42 |  | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 43 | static unsigned long get_mult_time(char c) | 
 | 44 | { | 
 | 45 | 	switch (c) { | 
 | 46 | 		case 'm': | 
 | 47 | 		case 'M': | 
 | 48 | 			return 60; | 
 | 49 | 		case 'h': | 
 | 50 | 		case 'H': | 
 | 51 | 			return 60 * 60; | 
 | 52 | 		case 'd': | 
 | 53 | 		case 'D': | 
 | 54 | 			return 24 * 60 * 60; | 
 | 55 | 		default: | 
 | 56 | 			return 1; | 
 | 57 | 	} | 
 | 58 | } | 
 | 59 |  | 
 | 60 | static unsigned long get_mult_bytes(char c) | 
 | 61 | { | 
 | 62 | 	switch (c) { | 
 | 63 | 		case 'k': | 
 | 64 | 		case 'K': | 
 | 65 | 			return 1024; | 
 | 66 | 		case 'm': | 
 | 67 | 		case 'M': | 
 | 68 | 			return 1024 * 1024; | 
 | 69 | 		case 'g': | 
 | 70 | 		case 'G': | 
 | 71 | 			return 1024 * 1024 * 1024; | 
| Jens Axboe | f3502ba | 2007-02-14 01:27:09 +0100 | [diff] [blame] | 72 | 		case 'e': | 
 | 73 | 		case 'E': | 
 | 74 | 			return 1024 * 1024 * 1024 * 1024UL; | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 75 | 		default: | 
 | 76 | 			return 1; | 
 | 77 | 	} | 
 | 78 | } | 
 | 79 |  | 
 | 80 | /* | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 81 |  * convert string into decimal value, noting any size suffix | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 82 |  */ | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 83 | static int str_to_decimal(const char *str, long long *val, int kilo) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 84 | { | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 85 | 	int len; | 
 | 86 |  | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 87 | 	len = strlen(str); | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 88 | 	if (!len) | 
 | 89 | 		return 1; | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 90 |  | 
| Jens Axboe | 675de85 | 2007-02-10 19:01:07 +0100 | [diff] [blame] | 91 | 	*val = strtoll(str, NULL, 10); | 
| Jens Axboe | cda866c | 2007-01-10 16:02:32 +0100 | [diff] [blame] | 92 | 	if (*val == LONG_MAX && errno == ERANGE) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 93 | 		return 1; | 
 | 94 |  | 
 | 95 | 	if (kilo) | 
 | 96 | 		*val *= get_mult_bytes(str[len - 1]); | 
 | 97 | 	else | 
 | 98 | 		*val *= get_mult_time(str[len - 1]); | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 99 |  | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 100 | 	return 0; | 
 | 101 | } | 
 | 102 |  | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 103 | static int check_str_bytes(const char *p, long long *val) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 104 | { | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 105 | 	return str_to_decimal(p, val, 1); | 
 | 106 | } | 
 | 107 |  | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 108 | static int check_str_time(const char *p, long long *val) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 109 | { | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 110 | 	return str_to_decimal(p, val, 0); | 
 | 111 | } | 
 | 112 |  | 
 | 113 | void strip_blank_front(char **p) | 
 | 114 | { | 
 | 115 | 	char *s = *p; | 
 | 116 |  | 
 | 117 | 	while (isspace(*s)) | 
 | 118 | 		s++; | 
 | 119 | } | 
 | 120 |  | 
 | 121 | void strip_blank_end(char *p) | 
 | 122 | { | 
 | 123 | 	char *s = p + strlen(p) - 1; | 
 | 124 |  | 
 | 125 | 	while (isspace(*s) || iscntrl(*s)) | 
 | 126 | 		s--; | 
 | 127 |  | 
 | 128 | 	*(s + 1) = '\0'; | 
 | 129 | } | 
 | 130 |  | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 131 | static int check_range_bytes(const char *str, long *val) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 132 | { | 
 | 133 | 	char suffix; | 
 | 134 |  | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 135 | 	if (!strlen(str)) | 
 | 136 | 		return 1; | 
 | 137 |  | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 138 | 	if (sscanf(str, "%lu%c", val, &suffix) == 2) { | 
 | 139 | 		*val *= get_mult_bytes(suffix); | 
 | 140 | 		return 0; | 
 | 141 | 	} | 
 | 142 |  | 
 | 143 | 	if (sscanf(str, "%lu", val) == 1) | 
 | 144 | 		return 0; | 
 | 145 |  | 
 | 146 | 	return 1; | 
 | 147 | } | 
 | 148 |  | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 149 | static int check_int(const char *p, int *val) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 150 | { | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 151 | 	if (!strlen(p)) | 
 | 152 | 		return 1; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 153 | 	if (sscanf(p, "%u", val) == 1) | 
| Jens Axboe | cb2c86f | 2006-10-26 13:48:34 +0200 | [diff] [blame] | 154 | 		return 0; | 
 | 155 |  | 
 | 156 | 	return 1; | 
 | 157 | } | 
 | 158 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 159 | static struct fio_option *find_option(struct fio_option *options, | 
 | 160 | 				      const char *opt) | 
 | 161 | { | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 162 | 	struct fio_option *o; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 163 |  | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 164 | 	for (o = &options[0]; o->name; o++) { | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 165 | 		if (!strcmp(o->name, opt)) | 
 | 166 | 			return o; | 
| Jens Axboe | 03b74b3 | 2007-01-11 11:04:31 +0100 | [diff] [blame] | 167 | 		else if (o->alias && !strcmp(o->alias, opt)) | 
 | 168 | 			return o; | 
| Jens Axboe | 33963c6 | 2006-10-27 11:33:01 +0200 | [diff] [blame] | 169 | 	} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 170 |  | 
 | 171 | 	return NULL; | 
 | 172 | } | 
 | 173 |  | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 174 | #define val_store(ptr, val, off, data)			\ | 
 | 175 | 	do {						\ | 
 | 176 | 		ptr = td_var((data), (off));		\ | 
 | 177 | 		*ptr = (val);				\ | 
 | 178 | 	} while (0) | 
 | 179 |  | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 180 | static int __handle_option(struct fio_option *o, const char *ptr, void *data, | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 181 | 			   int first, int more) | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 182 | { | 
| Jens Axboe | 63f2937 | 2007-01-10 13:20:09 +0100 | [diff] [blame] | 183 | 	int il, *ilp; | 
 | 184 | 	long long ull, *ullp; | 
 | 185 | 	long ul1, ul2; | 
| Jens Axboe | b469282 | 2006-10-27 13:43:22 +0200 | [diff] [blame] | 186 | 	char **cp; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 187 | 	int ret = 0, is_time = 0; | 
 | 188 |  | 
| Jens Axboe | 08e26e3 | 2006-11-21 13:15:10 +0100 | [diff] [blame] | 189 | 	if (!ptr && o->type != FIO_OPT_STR_SET) { | 
 | 190 | 		fprintf(stderr, "Option %s requires an argument\n", o->name); | 
 | 191 | 		return 1; | 
 | 192 | 	} | 
 | 193 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 194 | 	switch (o->type) { | 
 | 195 | 	case FIO_OPT_STR: { | 
 | 196 | 		fio_opt_str_fn *fn = o->cb; | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 197 | 		const struct value_pair *vp; | 
 | 198 | 		int i; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 199 |  | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 200 | 		for (i = 0; i < PARSE_MAX_VP; i++) { | 
 | 201 | 			vp = &o->posval[i]; | 
 | 202 | 			if (!vp->ival || vp->ival[0] == '\0') | 
 | 203 | 				break; | 
| Jens Axboe | 6612a27 | 2007-03-13 08:54:06 +0100 | [diff] [blame] | 204 | 			ret = 1; | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 205 | 			if (!strncmp(vp->ival, ptr, strlen(vp->ival))) { | 
 | 206 | 				ret = 0; | 
 | 207 | 				if (!o->off1) | 
 | 208 | 					break; | 
 | 209 | 				val_store(ilp, vp->oval, o->off1, data); | 
 | 210 | 				break; | 
 | 211 | 			} | 
 | 212 | 		} | 
 | 213 |  | 
 | 214 | 		if (ret) | 
 | 215 | 			show_option_values(o); | 
 | 216 | 		else if (fn) | 
 | 217 | 			ret = fn(data, ptr); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 218 | 		break; | 
 | 219 | 	} | 
 | 220 | 	case FIO_OPT_STR_VAL_TIME: | 
 | 221 | 		is_time = 1; | 
| Jens Axboe | 75e6f36 | 2006-11-03 08:17:09 +0100 | [diff] [blame] | 222 | 	case FIO_OPT_STR_VAL: | 
 | 223 | 	case FIO_OPT_STR_VAL_INT: { | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 224 | 		fio_opt_str_val_fn *fn = o->cb; | 
 | 225 |  | 
 | 226 | 		if (is_time) | 
 | 227 | 			ret = check_str_time(ptr, &ull); | 
 | 228 | 		else | 
 | 229 | 			ret = check_str_bytes(ptr, &ull); | 
 | 230 |  | 
 | 231 | 		if (ret) | 
 | 232 | 			break; | 
 | 233 |  | 
| Jens Axboe | db8e016 | 2007-01-10 13:41:26 +0100 | [diff] [blame] | 234 | 		if (o->maxval && ull > o->maxval) { | 
 | 235 | 			fprintf(stderr, "max value out of range: %lld (%d max)\n", ull, o->maxval); | 
 | 236 | 			return 1; | 
 | 237 | 		} | 
 | 238 | 		if (o->minval && ull < o->minval) { | 
 | 239 | 			fprintf(stderr, "min value out of range: %lld (%d min)\n", ull, o->minval); | 
 | 240 | 			return 1; | 
 | 241 | 		} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 242 |  | 
 | 243 | 		if (fn) | 
 | 244 | 			ret = fn(data, &ull); | 
 | 245 | 		else { | 
| Jens Axboe | 75e6f36 | 2006-11-03 08:17:09 +0100 | [diff] [blame] | 246 | 			if (o->type == FIO_OPT_STR_VAL_INT) { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 247 | 				if (first) | 
 | 248 | 					val_store(ilp, ull, o->off1, data); | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 249 | 				if (!more && o->off2) | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 250 | 					val_store(ilp, ull, o->off2, data); | 
| Jens Axboe | 75e6f36 | 2006-11-03 08:17:09 +0100 | [diff] [blame] | 251 | 			} else { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 252 | 				if (first) | 
 | 253 | 					val_store(ullp, ull, o->off1, data); | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 254 | 				if (!more && o->off2) | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 255 | 					val_store(ullp, ull, o->off2, data); | 
| Jens Axboe | 75e6f36 | 2006-11-03 08:17:09 +0100 | [diff] [blame] | 256 | 			} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 257 | 		} | 
 | 258 | 		break; | 
 | 259 | 	} | 
| Jens Axboe | af52b34 | 2007-03-13 10:07:47 +0100 | [diff] [blame^] | 260 | 	case FIO_OPT_STR_STORE: { | 
 | 261 | 		fio_opt_str_fn *fn = o->cb; | 
 | 262 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 263 | 		cp = td_var(data, o->off1); | 
 | 264 | 		*cp = strdup(ptr); | 
| Jens Axboe | af52b34 | 2007-03-13 10:07:47 +0100 | [diff] [blame^] | 265 | 		if (fn) { | 
 | 266 | 			ret = fn(data, ptr); | 
 | 267 | 			if (ret) { | 
 | 268 | 				free(*cp); | 
 | 269 | 				*cp = NULL; | 
 | 270 | 			} | 
 | 271 | 		} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 272 | 		break; | 
| Jens Axboe | af52b34 | 2007-03-13 10:07:47 +0100 | [diff] [blame^] | 273 | 	} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 274 | 	case FIO_OPT_RANGE: { | 
| Jens Axboe | b765a37 | 2006-10-27 15:00:16 +0200 | [diff] [blame] | 275 | 		char tmp[128]; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 276 | 		char *p1, *p2; | 
 | 277 |  | 
| Jens Axboe | 0bbab0e | 2006-11-02 09:18:36 +0100 | [diff] [blame] | 278 | 		strncpy(tmp, ptr, sizeof(tmp) - 1); | 
| Jens Axboe | b765a37 | 2006-10-27 15:00:16 +0200 | [diff] [blame] | 279 |  | 
 | 280 | 		p1 = strchr(tmp, '-'); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 281 | 		if (!p1) { | 
| Jens Axboe | 0c9baf9 | 2007-01-11 15:59:26 +0100 | [diff] [blame] | 282 | 			p1 = strchr(tmp, ':'); | 
 | 283 | 			if (!p1) { | 
 | 284 | 				ret = 1; | 
 | 285 | 				break; | 
 | 286 | 			} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 287 | 		} | 
 | 288 |  | 
 | 289 | 		p2 = p1 + 1; | 
 | 290 | 		*p1 = '\0'; | 
| Jens Axboe | b765a37 | 2006-10-27 15:00:16 +0200 | [diff] [blame] | 291 | 		p1 = tmp; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 292 |  | 
 | 293 | 		ret = 1; | 
 | 294 | 		if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) { | 
 | 295 | 			ret = 0; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 296 | 			if (ul1 > ul2) { | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 297 | 				unsigned long foo = ul1; | 
 | 298 |  | 
 | 299 | 				ul1 = ul2; | 
 | 300 | 				ul2 = foo; | 
 | 301 | 			} | 
 | 302 |  | 
 | 303 | 			if (first) { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 304 | 				val_store(ilp, ul1, o->off1, data); | 
 | 305 | 				val_store(ilp, ul2, o->off2, data); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 306 | 			} | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 307 | 			if (!more && o->off3 && o->off4) { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 308 | 				val_store(ilp, ul1, o->off3, data); | 
 | 309 | 				val_store(ilp, ul2, o->off4, data); | 
 | 310 | 			} | 
 | 311 | 		} | 
 | 312 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 313 | 		break; | 
 | 314 | 	} | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 315 | 	case FIO_OPT_INT: | 
 | 316 | 	case FIO_OPT_BOOL: { | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 317 | 		fio_opt_int_fn *fn = o->cb; | 
 | 318 |  | 
 | 319 | 		ret = check_int(ptr, &il); | 
 | 320 | 		if (ret) | 
 | 321 | 			break; | 
 | 322 |  | 
| Jens Axboe | db8e016 | 2007-01-10 13:41:26 +0100 | [diff] [blame] | 323 | 		if (o->maxval && il > (int) o->maxval) { | 
 | 324 | 			fprintf(stderr, "max value out of range: %d (%d max)\n", il, o->maxval); | 
 | 325 | 			return 1; | 
 | 326 | 		} | 
 | 327 | 		if (o->minval && il < o->minval) { | 
 | 328 | 			fprintf(stderr, "min value out of range: %d (%d min)\n", il, o->minval); | 
 | 329 | 			return 1; | 
 | 330 | 		} | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 331 |  | 
| Jens Axboe | 76a43db | 2007-01-11 13:24:44 +0100 | [diff] [blame] | 332 | 		if (o->neg) | 
 | 333 | 			il = !il; | 
 | 334 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 335 | 		if (fn) | 
 | 336 | 			ret = fn(data, &il); | 
 | 337 | 		else { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 338 | 			if (first) | 
 | 339 | 				val_store(ilp, il, o->off1, data); | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 340 | 			if (!more && o->off2) | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 341 | 				val_store(ilp, il, o->off2, data); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 342 | 		} | 
 | 343 | 		break; | 
 | 344 | 	} | 
 | 345 | 	case FIO_OPT_STR_SET: { | 
 | 346 | 		fio_opt_str_set_fn *fn = o->cb; | 
 | 347 |  | 
 | 348 | 		if (fn) | 
 | 349 | 			ret = fn(data); | 
 | 350 | 		else { | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 351 | 			if (first) | 
 | 352 | 				val_store(ilp, 1, o->off1, data); | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 353 | 			if (!more && o->off2) | 
| Jens Axboe | 17abbe8 | 2006-11-06 11:23:10 +0100 | [diff] [blame] | 354 | 				val_store(ilp, 1, o->off2, data); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 355 | 		} | 
 | 356 | 		break; | 
 | 357 | 	} | 
 | 358 | 	default: | 
| Jens Axboe | 1e97cce | 2006-12-05 11:44:16 +0100 | [diff] [blame] | 359 | 		fprintf(stderr, "Bad option type %u\n", o->type); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 360 | 		ret = 1; | 
 | 361 | 	} | 
 | 362 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 363 | 	return ret; | 
 | 364 | } | 
 | 365 |  | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 366 | static int handle_option(struct fio_option *o, const char *ptr, void *data) | 
 | 367 | { | 
| Jens Axboe | 92b586f | 2006-11-07 14:29:17 +0100 | [diff] [blame] | 368 | 	const char *ptr2 = NULL; | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 369 | 	int r1, r2; | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 370 |  | 
 | 371 | 	/* | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 372 | 	 * See if we have a second set of parameters, hidden after a comma. | 
 | 373 | 	 * Do this before parsing the first round, to check if we should | 
 | 374 | 	 * copy set 1 options to set 2. | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 375 | 	 */ | 
| Joel Becker | ad231bc | 2007-03-01 08:22:42 +0100 | [diff] [blame] | 376 | 	if (ptr && | 
 | 377 | 	    (o->type != FIO_OPT_STR_STORE) && | 
 | 378 | 	    (o->type != FIO_OPT_STR)) { | 
| Jens Axboe | 92b586f | 2006-11-07 14:29:17 +0100 | [diff] [blame] | 379 | 		ptr2 = strchr(ptr, ','); | 
| Jens Axboe | 0c9baf9 | 2007-01-11 15:59:26 +0100 | [diff] [blame] | 380 | 		if (!ptr2) | 
 | 381 | 			ptr2 = strchr(ptr, ':'); | 
 | 382 | 	} | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 383 |  | 
 | 384 | 	/* | 
 | 385 | 	 * Don't return early if parsing the first option fails - if | 
 | 386 | 	 * we are doing multiple arguments, we can allow the first one | 
 | 387 | 	 * being empty. | 
 | 388 | 	 */ | 
 | 389 | 	r1 = __handle_option(o, ptr, data, 1, !!ptr2); | 
 | 390 |  | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 391 | 	if (!ptr2) | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 392 | 		return r1; | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 393 |  | 
 | 394 | 	ptr2++; | 
| Jens Axboe | 787f7e9 | 2006-11-06 13:26:29 +0100 | [diff] [blame] | 395 | 	r2 = __handle_option(o, ptr2, data, 0, 0); | 
 | 396 |  | 
 | 397 | 	return r1 && r2; | 
| Jens Axboe | f90eff5 | 2006-11-06 11:08:21 +0100 | [diff] [blame] | 398 | } | 
 | 399 |  | 
| Jens Axboe | b469282 | 2006-10-27 13:43:22 +0200 | [diff] [blame] | 400 | int parse_cmd_option(const char *opt, const char *val, | 
 | 401 | 		     struct fio_option *options, void *data) | 
 | 402 | { | 
 | 403 | 	struct fio_option *o; | 
 | 404 |  | 
 | 405 | 	o = find_option(options, opt); | 
 | 406 | 	if (!o) { | 
 | 407 | 		fprintf(stderr, "Bad option %s\n", opt); | 
 | 408 | 		return 1; | 
 | 409 | 	} | 
 | 410 |  | 
| Jens Axboe | b1508cf | 2006-11-02 09:12:40 +0100 | [diff] [blame] | 411 | 	if (!handle_option(o, val, data)) | 
 | 412 | 		return 0; | 
 | 413 |  | 
 | 414 | 	fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val); | 
 | 415 | 	return 1; | 
| Jens Axboe | b469282 | 2006-10-27 13:43:22 +0200 | [diff] [blame] | 416 | } | 
 | 417 |  | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 418 | int parse_option(const char *opt, struct fio_option *options, void *data) | 
 | 419 | { | 
| Jens Axboe | b469282 | 2006-10-27 13:43:22 +0200 | [diff] [blame] | 420 | 	struct fio_option *o; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 421 | 	char *pre, *post; | 
 | 422 | 	char tmp[64]; | 
 | 423 |  | 
| Jens Axboe | 0bbab0e | 2006-11-02 09:18:36 +0100 | [diff] [blame] | 424 | 	strncpy(tmp, opt, sizeof(tmp) - 1); | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 425 |  | 
 | 426 | 	pre = strchr(tmp, '='); | 
 | 427 | 	if (pre) { | 
 | 428 | 		post = pre; | 
 | 429 | 		*pre = '\0'; | 
 | 430 | 		pre = tmp; | 
 | 431 | 		post++; | 
 | 432 | 		o = find_option(options, pre); | 
 | 433 | 	} else { | 
 | 434 | 		o = find_option(options, tmp); | 
 | 435 | 		post = NULL; | 
 | 436 | 	} | 
 | 437 |  | 
 | 438 | 	if (!o) { | 
 | 439 | 		fprintf(stderr, "Bad option %s\n", tmp); | 
 | 440 | 		return 1; | 
 | 441 | 	} | 
 | 442 |  | 
| Jens Axboe | b1508cf | 2006-11-02 09:12:40 +0100 | [diff] [blame] | 443 | 	if (!handle_option(o, post, data)) | 
 | 444 | 		return 0; | 
 | 445 |  | 
 | 446 | 	fprintf(stderr, "fio: failed parsing %s\n", opt); | 
 | 447 | 	return 1; | 
| Jens Axboe | e1f3650 | 2006-10-27 10:54:08 +0200 | [diff] [blame] | 448 | } | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 449 |  | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 450 | /* | 
 | 451 |  * Option match, levenshtein distance. Handy for not quite remembering what | 
 | 452 |  * the option name is. | 
 | 453 |  */ | 
 | 454 | static int string_distance(const char *s1, const char *s2) | 
 | 455 | { | 
 | 456 | 	unsigned int s1_len = strlen(s1); | 
 | 457 | 	unsigned int s2_len = strlen(s2); | 
 | 458 | 	unsigned int *p, *q, *r; | 
 | 459 | 	unsigned int i, j; | 
 | 460 |  | 
 | 461 | 	p = malloc(sizeof(unsigned int) * (s2_len + 1)); | 
 | 462 | 	q = malloc(sizeof(unsigned int) * (s2_len + 1)); | 
 | 463 |  | 
 | 464 | 	p[0] = 0; | 
 | 465 | 	for (i = 1; i <= s2_len; i++) | 
 | 466 | 		p[i] = p[i - 1] + 1; | 
 | 467 |  | 
 | 468 | 	for (i = 1; i <= s1_len; i++) { | 
 | 469 | 		q[0] = p[0] + 1; | 
 | 470 | 		for (j = 1; j <= s2_len; j++) { | 
 | 471 | 			unsigned int sub = p[j - 1]; | 
 | 472 |  | 
 | 473 | 			if (s1[i - 1] != s2[j - 1]) | 
 | 474 | 				sub++; | 
 | 475 |  | 
 | 476 | 			q[j] = min(p[j] + 1, min(q[j - 1] + 1, sub)); | 
 | 477 | 		} | 
 | 478 | 		r = p; | 
 | 479 | 		p = q; | 
 | 480 | 		q = r; | 
 | 481 | 	} | 
 | 482 |  | 
 | 483 | 	i = p[s2_len]; | 
 | 484 | 	free(p); | 
 | 485 | 	free(q); | 
 | 486 | 	return i; | 
 | 487 | } | 
 | 488 |  | 
 | 489 | static void show_option_help(struct fio_option *o) | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 490 | { | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 491 | 	const char *typehelp[] = { | 
 | 492 | 		"string (opt=bla)", | 
 | 493 | 		"string with possible k/m/g postfix (opt=4k)", | 
 | 494 | 		"string with range and postfix (opt=1k-4k)", | 
 | 495 | 		"string with time postfix (opt=10s)", | 
 | 496 | 		"string (opt=bla)", | 
 | 497 | 		"string with dual range (opt=1k-4k,4k-8k)", | 
 | 498 | 		"integer value (opt=100)", | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 499 | 		"boolean value (opt=1)", | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 500 | 		"no argument (opt)", | 
 | 501 | 	}; | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 502 |  | 
 | 503 | 	printf("%20s: %s\n", "type", typehelp[o->type]); | 
 | 504 | 	printf("%20s: %s\n", "default", o->def ? o->def : "no default"); | 
 | 505 | 	show_option_range(o); | 
 | 506 | 	show_option_values(o); | 
 | 507 | } | 
 | 508 |  | 
 | 509 | int show_cmd_help(struct fio_option *options, const char *name) | 
 | 510 | { | 
 | 511 | 	struct fio_option *o, *closest; | 
 | 512 | 	unsigned int best_dist; | 
| Jens Axboe | 29fc6af | 2007-01-09 21:22:02 +0100 | [diff] [blame] | 513 | 	int found = 0; | 
| Jens Axboe | 320beef | 2007-03-01 10:44:12 +0100 | [diff] [blame] | 514 | 	int show_all = 0; | 
 | 515 |  | 
 | 516 | 	if (!name || !strcmp(name, "all")) | 
 | 517 | 		show_all = 1; | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 518 |  | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 519 | 	closest = NULL; | 
 | 520 | 	best_dist = -1; | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 521 | 	for (o = &options[0]; o->name; o++) { | 
| Jens Axboe | 320beef | 2007-03-01 10:44:12 +0100 | [diff] [blame] | 522 | 		int match = 0; | 
 | 523 |  | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 524 | 		if (name) { | 
 | 525 | 			if (!strcmp(name, o->name)) | 
 | 526 | 				match = 1; | 
 | 527 | 			else { | 
 | 528 | 				unsigned int dist; | 
 | 529 |  | 
 | 530 | 				dist = string_distance(name, o->name); | 
 | 531 | 				if (dist < best_dist) { | 
 | 532 | 					best_dist = dist; | 
 | 533 | 					closest = o; | 
 | 534 | 				} | 
 | 535 | 			} | 
 | 536 | 		} | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 537 |  | 
 | 538 | 		if (show_all || match) { | 
| Jens Axboe | 29fc6af | 2007-01-09 21:22:02 +0100 | [diff] [blame] | 539 | 			found = 1; | 
| Jens Axboe | ec1aee0 | 2007-02-26 13:18:47 +0100 | [diff] [blame] | 540 | 			printf("%20s: %s\n", o->name, o->help); | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 541 | 			if (show_all) | 
 | 542 | 				continue; | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 543 | 		} | 
 | 544 |  | 
| Jens Axboe | 70df2f1 | 2007-01-11 14:04:47 +0100 | [diff] [blame] | 545 | 		if (!match) | 
 | 546 | 			continue; | 
 | 547 |  | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 548 | 		show_option_help(o); | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 549 | 	} | 
 | 550 |  | 
| Jens Axboe | 29fc6af | 2007-01-09 21:22:02 +0100 | [diff] [blame] | 551 | 	if (found) | 
 | 552 | 		return 0; | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 553 |  | 
| Jens Axboe | 0e9f7fa | 2007-03-01 14:05:30 +0100 | [diff] [blame] | 554 | 	printf("No such command: %s", name); | 
 | 555 | 	if (closest) { | 
 | 556 | 		printf(" - showing closest match\n"); | 
 | 557 | 		printf("%20s: %s\n", closest->name, closest->help); | 
 | 558 | 		show_option_help(closest); | 
 | 559 | 	} else | 
 | 560 | 		printf("\n"); | 
 | 561 |  | 
| Jens Axboe | 29fc6af | 2007-01-09 21:22:02 +0100 | [diff] [blame] | 562 | 	return 1; | 
| Jens Axboe | fd28ca4 | 2007-01-09 21:20:13 +0100 | [diff] [blame] | 563 | } | 
| Jens Axboe | ee73849 | 2007-01-10 11:23:16 +0100 | [diff] [blame] | 564 |  | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 565 | /* | 
 | 566 |  * Handle parsing of default parameters. | 
 | 567 |  */ | 
| Jens Axboe | ee73849 | 2007-01-10 11:23:16 +0100 | [diff] [blame] | 568 | void fill_default_options(void *data, struct fio_option *options) | 
 | 569 | { | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 570 | 	struct fio_option *o; | 
| Jens Axboe | ee73849 | 2007-01-10 11:23:16 +0100 | [diff] [blame] | 571 |  | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 572 | 	for (o = &options[0]; o->name; o++) | 
| Jens Axboe | ee73849 | 2007-01-10 11:23:16 +0100 | [diff] [blame] | 573 | 		if (o->def) | 
 | 574 | 			handle_option(o, o->def, data); | 
| Jens Axboe | ee73849 | 2007-01-10 11:23:16 +0100 | [diff] [blame] | 575 | } | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 576 |  | 
 | 577 | /* | 
 | 578 |  * Sanitize the options structure. For now it just sets min/max for bool | 
| Jens Axboe | 5b0a888 | 2007-01-11 14:40:27 +0100 | [diff] [blame] | 579 |  * values and whether both callback and offsets are given. | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 580 |  */ | 
 | 581 | void options_init(struct fio_option *options) | 
 | 582 | { | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 583 | 	struct fio_option *o; | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 584 |  | 
| Jens Axboe | 4945ba1 | 2007-01-11 14:36:56 +0100 | [diff] [blame] | 585 | 	for (o = &options[0]; o->name; o++) { | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 586 | 		if (o->type == FIO_OPT_BOOL) { | 
 | 587 | 			o->minval = 0; | 
 | 588 | 			o->maxval = 1; | 
 | 589 | 		} | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 590 | 		if (!o->cb && !o->off1) | 
 | 591 | 			fprintf(stderr, "Option %s: neither cb nor offset given\n", o->name); | 
| Jens Axboe | af52b34 | 2007-03-13 10:07:47 +0100 | [diff] [blame^] | 592 | 		if (o->type == FIO_OPT_STR || o->type == FIO_OPT_STR_STORE) | 
| Jens Axboe | b1ec1da | 2007-02-23 10:29:16 +0100 | [diff] [blame] | 593 | 			continue; | 
| Jens Axboe | 5b0a888 | 2007-01-11 14:40:27 +0100 | [diff] [blame] | 594 | 		if (o->cb && (o->off1 || o->off2 || o->off3 || o->off4)) | 
 | 595 | 			fprintf(stderr, "Option %s: both cb and offset given\n", o->name); | 
| Jens Axboe | 13335dd | 2007-01-10 13:14:02 +0100 | [diff] [blame] | 596 | 	} | 
 | 597 | } |