parse.c revision 08e26e3579fdae51cc9aafc71a80c638563bf2cd
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 14static unsigned long get_mult_time(char c) 15{ 16 switch (c) { 17 case 'm': 18 case 'M': 19 return 60; 20 case 'h': 21 case 'H': 22 return 60 * 60; 23 case 'd': 24 case 'D': 25 return 24 * 60 * 60; 26 default: 27 return 1; 28 } 29} 30 31static unsigned long get_mult_bytes(char c) 32{ 33 switch (c) { 34 case 'k': 35 case 'K': 36 return 1024; 37 case 'm': 38 case 'M': 39 return 1024 * 1024; 40 case 'g': 41 case 'G': 42 return 1024 * 1024 * 1024; 43 default: 44 return 1; 45 } 46} 47 48/* 49 * convert string into decimal value, noting any size suffix 50 */ 51static int str_to_decimal(const char *str, unsigned long long *val, int kilo) 52{ 53 int len; 54 55 len = strlen(str); 56 if (!len) 57 return 1; 58 59 *val = strtoul(str, NULL, 10); 60 if (*val == ULONG_MAX && errno == ERANGE) 61 return 1; 62 63 if (kilo) 64 *val *= get_mult_bytes(str[len - 1]); 65 else 66 *val *= get_mult_time(str[len - 1]); 67 68 return 0; 69} 70 71static int check_str_bytes(const char *p, unsigned long long *val) 72{ 73 return str_to_decimal(p, val, 1); 74} 75 76static int check_str_time(const char *p, unsigned long long *val) 77{ 78 return str_to_decimal(p, val, 0); 79} 80 81void strip_blank_front(char **p) 82{ 83 char *s = *p; 84 85 while (isspace(*s)) 86 s++; 87} 88 89void strip_blank_end(char *p) 90{ 91 char *s = p + strlen(p) - 1; 92 93 while (isspace(*s) || iscntrl(*s)) 94 s--; 95 96 *(s + 1) = '\0'; 97} 98 99static int check_range_bytes(const char *str, unsigned long *val) 100{ 101 char suffix; 102 103 if (!strlen(str)) 104 return 1; 105 106 if (sscanf(str, "%lu%c", val, &suffix) == 2) { 107 *val *= get_mult_bytes(suffix); 108 return 0; 109 } 110 111 if (sscanf(str, "%lu", val) == 1) 112 return 0; 113 114 return 1; 115} 116 117static int check_int(const char *p, unsigned int *val) 118{ 119 if (!strlen(p)) 120 return 1; 121 if (sscanf(p, "%u", val) == 1) 122 return 0; 123 124 return 1; 125} 126 127static struct fio_option *find_option(struct fio_option *options, 128 const char *opt) 129{ 130 struct fio_option *o = &options[0]; 131 132 while (o->name) { 133 if (!strcmp(o->name, opt)) 134 return o; 135 136 o++; 137 } 138 139 return NULL; 140} 141 142#define val_store(ptr, val, off, data) \ 143 do { \ 144 ptr = td_var((data), (off)); \ 145 *ptr = (val); \ 146 } while (0) 147 148static int __handle_option(struct fio_option *o, const char *ptr, void *data, 149 int first, int more) 150{ 151 unsigned int il, *ilp; 152 unsigned long long ull, *ullp; 153 unsigned long ul1, ul2; 154 char **cp; 155 int ret = 0, is_time = 0; 156 157 if (!ptr && o->type != FIO_OPT_STR_SET) { 158 fprintf(stderr, "Option %s requires an argument\n", o->name); 159 return 1; 160 } 161 162 switch (o->type) { 163 case FIO_OPT_STR: { 164 fio_opt_str_fn *fn = o->cb; 165 166 ret = fn(data, ptr); 167 break; 168 } 169 case FIO_OPT_STR_VAL_TIME: 170 is_time = 1; 171 case FIO_OPT_STR_VAL: 172 case FIO_OPT_STR_VAL_INT: { 173 fio_opt_str_val_fn *fn = o->cb; 174 175 if (is_time) 176 ret = check_str_time(ptr, &ull); 177 else 178 ret = check_str_bytes(ptr, &ull); 179 180 if (ret) 181 break; 182 183 if (o->max_val && ull > o->max_val) 184 ull = o->max_val; 185 186 if (fn) 187 ret = fn(data, &ull); 188 else { 189 if (o->type == FIO_OPT_STR_VAL_INT) { 190 if (first) 191 val_store(ilp, ull, o->off1, data); 192 if (!more && o->off2) 193 val_store(ilp, ull, o->off2, data); 194 } else { 195 if (first) 196 val_store(ullp, ull, o->off1, data); 197 if (!more && o->off2) 198 val_store(ullp, ull, o->off2, data); 199 } 200 } 201 break; 202 } 203 case FIO_OPT_STR_STORE: 204 cp = td_var(data, o->off1); 205 *cp = strdup(ptr); 206 break; 207 case FIO_OPT_RANGE: { 208 char tmp[128]; 209 char *p1, *p2; 210 211 strncpy(tmp, ptr, sizeof(tmp) - 1); 212 213 p1 = strchr(tmp, '-'); 214 if (!p1) { 215 ret = 1; 216 break; 217 } 218 219 p2 = p1 + 1; 220 *p1 = '\0'; 221 p1 = tmp; 222 223 ret = 1; 224 if (!check_range_bytes(p1, &ul1) && !check_range_bytes(p2, &ul2)) { 225 ret = 0; 226 if (ul1 > ul2) { 227 unsigned long foo = ul1; 228 229 ul1 = ul2; 230 ul2 = foo; 231 } 232 233 if (first) { 234 val_store(ilp, ul1, o->off1, data); 235 val_store(ilp, ul2, o->off2, data); 236 } 237 if (!more && o->off3 && o->off4) { 238 val_store(ilp, ul1, o->off3, data); 239 val_store(ilp, ul2, o->off4, data); 240 } 241 } 242 243 break; 244 } 245 case FIO_OPT_INT: { 246 fio_opt_int_fn *fn = o->cb; 247 248 ret = check_int(ptr, &il); 249 if (ret) 250 break; 251 252 if (o->max_val && il > o->max_val) 253 il = o->max_val; 254 255 if (fn) 256 ret = fn(data, &il); 257 else { 258 if (first) 259 val_store(ilp, il, o->off1, data); 260 if (!more && o->off2) 261 val_store(ilp, il, o->off2, data); 262 } 263 break; 264 } 265 case FIO_OPT_STR_SET: { 266 fio_opt_str_set_fn *fn = o->cb; 267 268 if (fn) 269 ret = fn(data); 270 else { 271 if (first) 272 val_store(ilp, 1, o->off1, data); 273 if (!more && o->off2) 274 val_store(ilp, 1, o->off2, data); 275 } 276 break; 277 } 278 default: 279 fprintf(stderr, "Bad option type %d\n", o->type); 280 ret = 1; 281 } 282 283 return ret; 284} 285 286static int handle_option(struct fio_option *o, const char *ptr, void *data) 287{ 288 const char *ptr2 = NULL; 289 int r1, r2; 290 291 /* 292 * See if we have a second set of parameters, hidden after a comma. 293 * Do this before parsing the first round, to check if we should 294 * copy set 1 options to set 2. 295 */ 296 if (ptr) 297 ptr2 = strchr(ptr, ','); 298 299 /* 300 * Don't return early if parsing the first option fails - if 301 * we are doing multiple arguments, we can allow the first one 302 * being empty. 303 */ 304 r1 = __handle_option(o, ptr, data, 1, !!ptr2); 305 306 if (!ptr2) 307 return r1; 308 309 ptr2++; 310 r2 = __handle_option(o, ptr2, data, 0, 0); 311 312 return r1 && r2; 313} 314 315int parse_cmd_option(const char *opt, const char *val, 316 struct fio_option *options, void *data) 317{ 318 struct fio_option *o; 319 320 o = find_option(options, opt); 321 if (!o) { 322 fprintf(stderr, "Bad option %s\n", opt); 323 return 1; 324 } 325 326 if (!handle_option(o, val, data)) 327 return 0; 328 329 fprintf(stderr, "fio: failed parsing %s=%s\n", opt, val); 330 return 1; 331} 332 333int parse_option(const char *opt, struct fio_option *options, void *data) 334{ 335 struct fio_option *o; 336 char *pre, *post; 337 char tmp[64]; 338 339 strncpy(tmp, opt, sizeof(tmp) - 1); 340 341 pre = strchr(tmp, '='); 342 if (pre) { 343 post = pre; 344 *pre = '\0'; 345 pre = tmp; 346 post++; 347 o = find_option(options, pre); 348 } else { 349 o = find_option(options, tmp); 350 post = NULL; 351 } 352 353 if (!o) { 354 fprintf(stderr, "Bad option %s\n", tmp); 355 return 1; 356 } 357 358 if (!handle_option(o, post, data)) 359 return 0; 360 361 fprintf(stderr, "fio: failed parsing %s\n", opt); 362 return 1; 363} 364