options: fix buffer overrun
[fio.git] / options.c
index 852fb05bec44111613907a18bf7433c83b29698a..955bf959e49c3ff2a8c1c9912786f45b833b346c 100644 (file)
--- a/options.c
+++ b/options.c
@@ -22,7 +22,7 @@ char client_sockaddr_str[INET6_ADDRSTRLEN] = { 0 };
 static const struct pattern_fmt_desc fmt_desc[] = {
        {
                .fmt   = "%o",
-               .len   = FIELD_SIZE(struct io_u *, offset),
+               .len   = FIO_FIELD_SIZE(struct io_u *, offset),
                .paste = paste_blockoff
        },
        { }
@@ -44,6 +44,27 @@ static char *get_opt_postfix(const char *str)
        return strdup(p);
 }
 
+static bool split_parse_distr(const char *str, double *val, double *center)
+{
+       char *cp, *p;
+       bool r;
+
+       p = strdup(str);
+       if (!p)
+               return false;
+
+       cp = strstr(p, ":");
+       r = true;
+       if (cp) {
+               *cp = '\0';
+               cp++;
+               r = str_to_float(cp, center, 0);
+       }
+       r = r && str_to_float(p, val, 0);
+       free(p);
+       return r;
+}
+
 static int bs_cmp(const void *p1, const void *p2)
 {
        const struct bssplit *bsp1 = p1;
@@ -787,6 +808,7 @@ static int str_fst_cb(void *data, const char *str)
 {
        struct thread_data *td = cb_data_to_td(data);
        double val;
+       double center = -1;
        bool done = false;
        char *nr;
 
@@ -821,7 +843,7 @@ static int str_fst_cb(void *data, const char *str)
                return 0;
 
        nr = get_opt_postfix(str);
-       if (nr && !str_to_float(nr, &val, 0)) {
+       if (nr && !split_parse_distr(nr, &val, &center)) {
                log_err("fio: file service type random postfix parsing failed\n");
                free(nr);
                return 1;
@@ -829,6 +851,12 @@ static int str_fst_cb(void *data, const char *str)
 
        free(nr);
 
+       if (center != -1 && (center < 0.00 || center > 1.00)) {
+               log_err("fio: distribution center out of range (0 <= center <= 1.0)\n");
+               return 1;
+       }
+       td->random_center = center;
+
        switch (td->o.file_service_type) {
        case FIO_FSERVICE_ZIPF:
                if (val == 1.00) {
@@ -1030,6 +1058,7 @@ static int str_random_distribution_cb(void *data, const char *str)
 {
        struct thread_data *td = cb_data_to_td(data);
        double val;
+       double center = -1;
        char *nr;
 
        if (td->o.random_distribution == FIO_RAND_DIST_ZIPF)
@@ -1046,7 +1075,7 @@ static int str_random_distribution_cb(void *data, const char *str)
                return 0;
 
        nr = get_opt_postfix(str);
-       if (nr && !str_to_float(nr, &val, 0)) {
+       if (nr && !split_parse_distr(nr, &val, &center)) {
                log_err("fio: random postfix parsing failed\n");
                free(nr);
                return 1;
@@ -1054,6 +1083,12 @@ static int str_random_distribution_cb(void *data, const char *str)
 
        free(nr);
 
+       if (center != -1 && (center < 0.00 || center > 1.00)) {
+               log_err("fio: distribution center out of range (0 <= center <= 1.0)\n");
+               return 1;
+       }
+       td->o.random_center.u.f = center;
+
        if (td->o.random_distribution == FIO_RAND_DIST_ZIPF) {
                if (val == 1.00) {
                        log_err("fio: zipf theta must different than 1.0\n");
@@ -1387,7 +1422,7 @@ static int str_verify_pattern_cb(void *data, const char *input)
        struct thread_data *td = cb_data_to_td(data);
        int ret;
 
-       td->o.verify_fmt_sz = ARRAY_SIZE(td->o.verify_fmt);
+       td->o.verify_fmt_sz = FIO_ARRAY_SIZE(td->o.verify_fmt);
        ret = parse_and_fill_pattern(input, strlen(input), td->o.verify_pattern,
                                     MAX_PATTERN_SIZE, fmt_desc,
                                     td->o.verify_fmt, &td->o.verify_fmt_sz);
@@ -1637,6 +1672,7 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                .lname  = "Filename(s)",
                .type   = FIO_OPT_STR_STORE,
                .off1   = offsetof(struct thread_options, filename),
+               .maxlen = PATH_MAX,
                .cb     = str_filename_cb,
                .prio   = -1, /* must come after "directory" */
                .help   = "File(s) to use for the workload",
@@ -1872,11 +1908,6 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
                          { .ival = "cpuio",
                            .help = "CPU cycle burner engine",
                          },
-#ifdef CONFIG_GUASI
-                         { .ival = "guasi",
-                           .help = "GUASI IO engine",
-                         },
-#endif
 #ifdef CONFIG_RDMA
                          { .ival = "rdma",
                            .help = "RDMA IO engine",
@@ -3738,14 +3769,32 @@ struct fio_option fio_options[FIO_MAX_OPTS] = {
        {
                .name   = "sync",
                .lname  = "Synchronous I/O",
-               .type   = FIO_OPT_BOOL,
+               .type   = FIO_OPT_STR,
                .off1   = offsetof(struct thread_options, sync_io),
-               .help   = "Use O_SYNC for buffered writes",
-               .def    = "0",
-               .parent = "buffered",
+               .help   = "Use synchronous write IO",
+               .def    = "none",
                .hide   = 1,
                .category = FIO_OPT_C_IO,
                .group  = FIO_OPT_G_IO_TYPE,
+               .posval = {
+                         { .ival = "none",
+                           .oval = 0,
+                         },
+                         { .ival = "0",
+                           .oval = 0,
+                         },
+                         { .ival = "sync",
+                           .oval = O_SYNC,
+                         },
+                         { .ival = "1",
+                           .oval = O_SYNC,
+                         },
+#ifdef O_DSYNC
+                         { .ival = "dsync",
+                           .oval = O_DSYNC,
+                         },
+#endif
+               },
        },
 #ifdef FIO_HAVE_WRITE_HINT
        {
@@ -5051,7 +5100,7 @@ static char *fio_keyword_replace(char *opt)
                struct fio_keyword *kw = &fio_keywords[i];
 
                while ((s = strstr(opt, kw->word)) != NULL) {
-                       char *new = malloc(strlen(opt) + 1);
+                       char *new = calloc(strlen(opt) + 1, 1);
                        char *o_org = opt;
                        int olen = s - opt;
                        int len;
@@ -5067,9 +5116,10 @@ static char *fio_keyword_replace(char *opt)
                         * If there's more in the original string, copy that
                         * in too
                         */
-                       opt += strlen(kw->word) + olen;
+                       opt += olen + strlen(kw->word);
+                       /* keeps final zero thanks to calloc */
                        if (strlen(opt))
-                               memcpy(new + olen + len, opt, opt - o_org - 1);
+                               memcpy(new + olen + len, opt, strlen(opt));
 
                        /*
                         * replace opt and free the old opt