Avoid potential buffer overflow in make_filename()
[fio.git] / init.c
diff --git a/init.c b/init.c
index a2377dc95e33c1499340037cae86b3b436ad2db6..a0d4f8c797f092378ec80a067c0aa1afed15e416 100644 (file)
--- a/init.c
+++ b/init.c
@@ -64,6 +64,11 @@ int write_bw_log = 0;
 int read_only = 0;
 int status_interval = 0;
 
+char *trigger_file = NULL;
+long long trigger_timeout = 0;
+char *trigger_cmd = NULL;
+char *trigger_remote_cmd = NULL;
+
 static int prev_group_jobs;
 
 unsigned long fio_debug = 0;
@@ -241,6 +246,26 @@ static struct option l_opts[FIO_NR_OPTIONS] = {
                .has_arg        = required_argument,
                .val            = 'L',
        },
+       {
+               .name           = (char *) "trigger-file",
+               .has_arg        = required_argument,
+               .val            = 'W',
+       },
+       {
+               .name           = (char *) "trigger-timeout",
+               .has_arg        = required_argument,
+               .val            = 'B',
+       },
+       {
+               .name           = (char *) "trigger",
+               .has_arg        = required_argument,
+               .val            = 'H',
+       },
+       {
+               .name           = (char *) "trigger-remote",
+               .has_arg        = required_argument,
+               .val            = 'J',
+       },
        {
                .name           = NULL,
        },
@@ -273,6 +298,11 @@ static void free_shm(void)
                free_threads_shm();
        }
 
+       free(trigger_file);
+       free(trigger_cmd);
+       free(trigger_remote_cmd);
+       trigger_file = trigger_cmd = trigger_remote_cmd = NULL;
+
        options_free(fio_options, &def_thread);
        fio_filelock_exit();
        scleanup();
@@ -470,13 +500,8 @@ static unsigned long long get_rand_start_delay(struct thread_data *td)
 
        delayrange = td->o.start_delay_high - td->o.start_delay;
 
-       if (td->o.use_os_rand) {
-               r = os_random_long(&td->delay_state);
-               delayrange = (unsigned long long) ((double) delayrange * (r / (OS_RAND_MAX + 1.0)));
-       } else {
-               r = __rand(&td->__delay_state);
-               delayrange = (unsigned long long) ((double) delayrange * (r / (FRAND_MAX + 1.0)));
-       }
+       r = __rand(&td->delay_state);
+       delayrange = (unsigned long long) ((double) delayrange * (r / (FRAND_MAX + 1.0)));
 
        delayrange += td->o.start_delay;
        return delayrange;
@@ -540,7 +565,6 @@ static int fixup_options(struct thread_data *td)
        if (!o->max_bs[DDIR_TRIM])
                o->max_bs[DDIR_TRIM] = o->bs[DDIR_TRIM];
 
-
        o->rw_min_bs = min(o->min_bs[DDIR_READ], o->min_bs[DDIR_WRITE]);
        o->rw_min_bs = min(o->min_bs[DDIR_TRIM], o->rw_min_bs);
 
@@ -734,6 +758,12 @@ static int fixup_options(struct thread_data *td)
                ret = 1;
        }
 
+       if (fio_option_is_set(o, gtod_cpu)) {
+               fio_gtod_init();
+               fio_gtod_set_cpu(o->gtod_cpu);
+               fio_gtod_offload = 1;
+       }
+
        return ret;
 }
 
@@ -787,44 +817,18 @@ static int exists_and_not_file(const char *filename)
        return 1;
 }
 
-static void td_fill_rand_seeds_os(struct thread_data *td)
-{
-       os_random_seed(td->rand_seeds[FIO_RAND_BS_OFF], &td->bsrange_state);
-       os_random_seed(td->rand_seeds[FIO_RAND_VER_OFF], &td->verify_state);
-       os_random_seed(td->rand_seeds[FIO_RAND_MIX_OFF], &td->rwmix_state);
-
-       if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
-               os_random_seed(td->rand_seeds[FIO_RAND_FILE_OFF], &td->next_file_state);
-
-       os_random_seed(td->rand_seeds[FIO_RAND_FILE_SIZE_OFF], &td->file_size_state);
-       os_random_seed(td->rand_seeds[FIO_RAND_TRIM_OFF], &td->trim_state);
-       os_random_seed(td->rand_seeds[FIO_RAND_START_DELAY], &td->delay_state);
-
-       if (!td_random(td))
-               return;
-
-       if (td->o.rand_repeatable)
-               td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number;
-
-       os_random_seed(td->rand_seeds[FIO_RAND_BLOCK_OFF], &td->random_state);
-
-       os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF], &td->seq_rand_state[DDIR_READ]);
-       os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF], &td->seq_rand_state[DDIR_WRITE]);
-       os_random_seed(td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF], &td->seq_rand_state[DDIR_TRIM]);
-}
-
 static void td_fill_rand_seeds_internal(struct thread_data *td)
 {
-       init_rand_seed(&td->__bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF]);
-       init_rand_seed(&td->__verify_state, td->rand_seeds[FIO_RAND_VER_OFF]);
-       init_rand_seed(&td->__rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF]);
+       init_rand_seed(&td->bsrange_state, td->rand_seeds[FIO_RAND_BS_OFF]);
+       init_rand_seed(&td->verify_state, td->rand_seeds[FIO_RAND_VER_OFF]);
+       init_rand_seed(&td->rwmix_state, td->rand_seeds[FIO_RAND_MIX_OFF]);
 
        if (td->o.file_service_type == FIO_FSERVICE_RANDOM)
-               init_rand_seed(&td->__next_file_state, td->rand_seeds[FIO_RAND_FILE_OFF]);
+               init_rand_seed(&td->next_file_state, td->rand_seeds[FIO_RAND_FILE_OFF]);
 
-       init_rand_seed(&td->__file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]);
-       init_rand_seed(&td->__trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]);
-       init_rand_seed(&td->__delay_state, td->rand_seeds[FIO_RAND_START_DELAY]);
+       init_rand_seed(&td->file_size_state, td->rand_seeds[FIO_RAND_FILE_SIZE_OFF]);
+       init_rand_seed(&td->trim_state, td->rand_seeds[FIO_RAND_TRIM_OFF]);
+       init_rand_seed(&td->delay_state, td->rand_seeds[FIO_RAND_START_DELAY]);
 
        if (!td_random(td))
                return;
@@ -832,10 +836,10 @@ static void td_fill_rand_seeds_internal(struct thread_data *td)
        if (td->o.rand_repeatable)
                td->rand_seeds[FIO_RAND_BLOCK_OFF] = FIO_RANDSEED * td->thread_number;
 
-       init_rand_seed(&td->__random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]);
-       init_rand_seed(&td->__seq_rand_state[DDIR_READ], td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF]);
-       init_rand_seed(&td->__seq_rand_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF]);
-       init_rand_seed(&td->__seq_rand_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF]);
+       init_rand_seed(&td->random_state, td->rand_seeds[FIO_RAND_BLOCK_OFF]);
+       init_rand_seed(&td->seq_rand_state[DDIR_READ], td->rand_seeds[FIO_RAND_SEQ_RAND_READ_OFF]);
+       init_rand_seed(&td->seq_rand_state[DDIR_WRITE], td->rand_seeds[FIO_RAND_SEQ_RAND_WRITE_OFF]);
+       init_rand_seed(&td->seq_rand_state[DDIR_TRIM], td->rand_seeds[FIO_RAND_SEQ_RAND_TRIM_OFF]);
 }
 
 void td_fill_rand_seeds(struct thread_data *td)
@@ -848,10 +852,7 @@ void td_fill_rand_seeds(struct thread_data *td)
                                + i;
        }
 
-       if (td->o.use_os_rand)
-               td_fill_rand_seeds_os(td);
-       else
-               td_fill_rand_seeds_internal(td);
+       td_fill_rand_seeds_internal(td);
 
        init_rand_seed(&td->buf_state, td->rand_seeds[FIO_RAND_BUF_OFF]);
        frand_copy(&td->buf_state_prev, &td->buf_state);
@@ -931,7 +932,17 @@ static void init_flags(struct thread_data *td)
                td->flags |= TD_F_READ_IOLOG;
        if (o->refill_buffers)
                td->flags |= TD_F_REFILL_BUFFERS;
-       if (o->scramble_buffers)
+       /*
+        * Always scramble buffers if asked to
+        */
+       if (o->scramble_buffers && fio_option_is_set(o, scramble_buffers))
+               td->flags |= TD_F_SCRAMBLE_BUFFERS;
+       /*
+        * But also scramble buffers, unless we were explicitly asked
+        * to zero them.
+        */
+       if (o->scramble_buffers && !(o->zero_buffers &&
+           fio_option_is_set(o, zero_buffers)))
                td->flags |= TD_F_SCRAMBLE_BUFFERS;
        if (o->verify != VERIFY_NONE)
                td->flags |= TD_F_VER_NONE;
@@ -1025,8 +1036,14 @@ static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
                                ret = snprintf(dst, dst_left, "%s", jobname);
                                if (ret < 0)
                                        break;
-                               dst += ret;
-                               dst_left -= ret;
+                               else if (ret > dst_left) {
+                                       log_err("fio: truncated filename\n");
+                                       dst += dst_left;
+                                       dst_left = 0;
+                               } else {
+                                       dst += ret;
+                                       dst_left -= ret;
+                               }
                                break;
                                }
                        case FPRE_JOBNUM: {
@@ -1035,8 +1052,14 @@ static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
                                ret = snprintf(dst, dst_left, "%d", jobnum);
                                if (ret < 0)
                                        break;
-                               dst += ret;
-                               dst_left -= ret;
+                               else if (ret > dst_left) {
+                                       log_err("fio: truncated filename\n");
+                                       dst += dst_left;
+                                       dst_left = 0;
+                               } else {
+                                       dst += ret;
+                                       dst_left -= ret;
+                               }
                                break;
                                }
                        case FPRE_FILENUM: {
@@ -1045,8 +1068,14 @@ static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
                                ret = snprintf(dst, dst_left, "%d", filenum);
                                if (ret < 0)
                                        break;
-                               dst += ret;
-                               dst_left -= ret;
+                               else if (ret > dst_left) {
+                                       log_err("fio: truncated filename\n");
+                                       dst += dst_left;
+                                       dst_left = 0;
+                               } else {
+                                       dst += ret;
+                                       dst_left -= ret;
+                               }
                                break;
                                }
                        default:
@@ -1432,7 +1461,8 @@ int __parse_jobs_ini(struct thread_data *td,
                        int __err = errno;
 
                        log_err("fio: unable to open '%s' job file\n", file);
-                       td_verror(td, __err, "job file open");
+                       if (td)
+                               td_verror(td, __err, "job file open");
                        return 1;
                }
        }
@@ -1698,6 +1728,10 @@ static void usage(const char *name)
 #ifdef CONFIG_ZLIB
        printf("  --inflate-log=log\tInflate and output compressed log\n");
 #endif
+       printf("  --trigger-file=file\tExecute trigger cmd when file exists\n");
+       printf("  --trigger-timeout=t\tExecute trigger af this time\n");
+       printf("  --trigger=cmd\t\tSet this command as local trigger\n");
+       printf("  --trigger-remote=cmd\tSet this command as remote trigger\n");
        printf("\nFio was written by Jens Axboe <jens.axboe@oracle.com>");
        printf("\n                   Jens Axboe <jaxboe@fusionio.com>");
        printf("\n                   Jens Axboe <axboe@fb.com>\n");
@@ -1875,6 +1909,30 @@ static void parse_cmd_client(void *client, char *opt)
        fio_client_add_cmd_option(client, opt);
 }
 
+static void show_closest_option(const char *name)
+{
+       int best_option, best_distance;
+       int i, distance;
+
+       while (*name == '-')
+               name++;
+
+       best_option = -1;
+       best_distance = INT_MAX;
+       i = 0;
+       while (l_opts[i].name) {
+               distance = string_distance(name, l_opts[i].name);
+               if (distance < best_distance) {
+                       best_distance = distance;
+                       best_option = i;
+               }
+               i++;
+       }
+
+       if (best_option != -1)
+               log_err("Did you mean %s?\n", l_opts[best_option].name);
+}
+
 int parse_cmd_line(int argc, char *argv[], int client_type)
 {
        struct thread_data *td = NULL;
@@ -2001,12 +2059,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'E': {
                        long long t = 0;
 
-                       if (str_to_decimal(optarg, &t, 0, NULL, 1)) {
+                       if (check_str_time(optarg, &t, 1)) {
                                log_err("fio: failed parsing eta time %s\n", optarg);
                                exit_val = 1;
                                do_exit++;
                        }
-                       eta_new_line = t;
+                       eta_new_line = t / 1000;
                        break;
                        }
                case 'd':
@@ -2198,7 +2256,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'T':
                        did_arg = 1;
                        do_exit++;
-                       exit_val = fio_monotonic_clocktest();
+                       exit_val = fio_monotonic_clocktest(1);
                        break;
                case 'G':
                        did_arg = 1;
@@ -2208,18 +2266,36 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case 'L': {
                        long long val;
 
-                       if (check_str_time(optarg, &val, 0)) {
+                       if (check_str_time(optarg, &val, 1)) {
                                log_err("fio: failed parsing time %s\n", optarg);
                                do_exit++;
                                exit_val = 1;
                                break;
                        }
-                       status_interval = val * 1000;
+                       status_interval = val / 1000;
+                       break;
+                       }
+               case 'W':
+                       trigger_file = strdup(optarg);
+                       break;
+               case 'H':
+                       trigger_cmd = strdup(optarg);
+                       break;
+               case 'J':
+                       trigger_remote_cmd = strdup(optarg);
                        break;
+               case 'B':
+                       if (check_str_time(optarg, &trigger_timeout, 1)) {
+                               log_err("fio: failed parsing time %s\n", optarg);
+                               do_exit++;
+                               exit_val = 1;
                        }
+                       trigger_timeout /= 1000000;
+                       break;
                case '?':
                        log_err("%s: unrecognized option '%s'\n", argv[0],
                                                        argv[optind - 1]);
+                       show_closest_option(argv[optind - 1]);
                default:
                        do_exit++;
                        exit_val = 1;
@@ -2337,12 +2413,6 @@ int parse_options(int argc, char *argv[])
                return 0;
        }
 
-       if (def_thread.o.gtod_offload) {
-               fio_gtod_init();
-               fio_gtod_offload = 1;
-               fio_gtod_cpu = def_thread.o.gtod_cpu;
-       }
-
        if (output_format == FIO_OUTPUT_NORMAL)
                log_info("%s\n", fio_version_string);