Fix crash on loading unknown IO engine with --ioengine
[fio.git] / init.c
diff --git a/init.c b/init.c
index 35fbdf15365b3661b4dea465b2ae978be096cb59..74a02e07422f37477f8b3a883c0f02ffa6a22bd1 100644 (file)
--- a/init.c
+++ b/init.c
@@ -364,7 +364,7 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
 
        td->thread_number = thread_number;
 
-       if (!parent || !parent->o.group_reporting)
+       if (!parent->o.group_reporting)
                stat_number++;
 
        set_cmd_options(td);
@@ -937,11 +937,12 @@ static struct fpre_keyword {
        { .keyword = NULL, },
        };
 
-static char *make_filename(char *buf, struct thread_options *o,
+static char *make_filename(char *buf, size_t buf_size,struct thread_options *o,
                           const char *jobname, int jobnum, int filenum)
 {
        struct fpre_keyword *f;
        char copy[PATH_MAX];
+       size_t dst_left = PATH_MAX - 1;
 
        if (!o->filename_format || !strlen(o->filename_format)) {
                sprintf(buf, "%s.%d.%d", jobname, jobnum, filenum);
@@ -951,7 +952,9 @@ static char *make_filename(char *buf, struct thread_options *o,
        for (f = &fpre_keywords[0]; f->keyword; f++)
                f->strlen = strlen(f->keyword);
 
-       strcpy(buf, o->filename_format);
+       buf[buf_size - 1] = '\0';
+       strncpy(buf, o->filename_format, buf_size - 1);
+
        memset(copy, 0, sizeof(copy));
        for (f = &fpre_keywords[0]; f->keyword; f++) {
                do {
@@ -969,27 +972,49 @@ static char *make_filename(char *buf, struct thread_options *o,
                        if (pre_len) {
                                strncpy(dst, buf, pre_len);
                                dst += pre_len;
+                               dst_left -= pre_len;
                        }
 
                        switch (f->key) {
-                       case FPRE_JOBNAME:
-                               dst += sprintf(dst, "%s", jobname);
+                       case FPRE_JOBNAME: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%s", jobname);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
-                       case FPRE_JOBNUM:
-                               dst += sprintf(dst, "%d", jobnum);
+                               }
+                       case FPRE_JOBNUM: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%d", jobnum);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
-                       case FPRE_FILENUM:
-                               dst += sprintf(dst, "%d", filenum);
+                               }
+                       case FPRE_FILENUM: {
+                               int ret;
+
+                               ret = snprintf(dst, dst_left, "%d", filenum);
+                               if (ret < 0)
+                                       break;
+                               dst += ret;
+                               dst_left -= ret;
                                break;
+                               }
                        default:
                                assert(0);
                                break;
                        }
 
                        if (post_start)
-                               strcpy(dst, buf + post_start);
+                               strncpy(dst, buf + post_start, dst_left);
 
-                       strcpy(buf, copy);
+                       strncpy(buf, copy, buf_size - 1);
                } while (1);
        }
 
@@ -1049,7 +1074,7 @@ static int add_job(struct thread_data *td, const char *jobname, int job_add_num,
                        add_file(td, jobname, job_add_num, 0);
                else {
                        for (i = 0; i < o->nr_files; i++)
-                               add_file(td, make_filename(fname, o, jobname, job_add_num, i), job_add_num, 0);
+                               add_file(td, make_filename(fname, sizeof(fname), o, jobname, job_add_num, i), job_add_num, 0);
                }
        }
 
@@ -1435,9 +1460,6 @@ int parse_jobs_ini(char *file, int is_buf, int stonewall_flag, int type)
                i++;
        }
 
-       for (i = 0; i < num_opts; i++)
-               free(opts[i]);
-
        free(string);
        free(name);
        free(opts);
@@ -1694,8 +1716,6 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
        optind = 1;
 
        while ((c = getopt_long_only(argc, argv, ostr, l_opts, &lidx)) != -1) {
-               did_arg = 1;
-
                if ((c & FIO_CLIENT_FLAG) || client_flag_set(c)) {
                        parse_cmd_client(cur_client, argv[optind - 1]);
                        c &= ~FIO_CLIENT_FLAG;
@@ -1719,7 +1739,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        write_bw_log = 1;
                        break;
                case 'o':
-                       if (f_out)
+                       if (f_out && f_out != stdout)
                                fclose(f_out);
 
                        f_out = fopen(optarg, "w+");
@@ -1752,30 +1772,35 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        append_terse_output = 1;
                        break;
                case 'h':
+                       did_arg = 1;
                        if (!cur_client) {
                                usage(argv[0]);
                                do_exit++;
                        }
                        break;
                case 'c':
+                       did_arg = 1;
                        if (!cur_client) {
                                fio_show_option_help(optarg);
                                do_exit++;
                        }
                        break;
                case 'i':
+                       did_arg = 1;
                        if (!cur_client) {
                                fio_show_ioengine_help(optarg);
                                do_exit++;
                        }
                        break;
                case 's':
+                       did_arg = 1;
                        dump_cmdline = 1;
                        break;
                case 'r':
                        read_only = 1;
                        break;
                case 'v':
+                       did_arg = 1;
                        if (!cur_client) {
                                log_info("%s\n", fio_version_string);
                                do_exit++;
@@ -1812,6 +1837,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                                do_exit++;
                        break;
                case 'P':
+                       did_arg = 1;
                        parse_only = 1;
                        break;
                case 'x': {
@@ -1831,6 +1857,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        break;
                        }
                case 'p':
+                       did_arg = 1;
                        if (exec_profile)
                                free(exec_profile);
                        exec_profile = strdup(optarg);
@@ -1842,8 +1869,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        if (!strncmp(opt, "name", 4) && td) {
                                ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
                                if (ret)
-                                       return 0;
+                                       goto out_free;
                                td = NULL;
+                               did_arg = 1;
                        }
                        if (!td) {
                                int is_section = !strncmp(opt, "name", 4);
@@ -1856,8 +1884,14 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                                        continue;
 
                                td = get_new_job(global, &def_thread, 1);
-                               if (!td || ioengine_load(td))
-                                       return 0;
+                               if (!td || ioengine_load(td)) {
+                                       if (td) {
+                                               put_job(td);
+                                               td = NULL;
+                                       }
+                                       do_exit++;
+                                       break;
+                               }
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
 
@@ -1878,8 +1912,14 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
 
                        if (!ret && !strcmp(opt, "ioengine")) {
                                free_ioengine(td);
-                               if (ioengine_load(td))
-                                       return 0;
+                               if (ioengine_load(td)) {
+                                       if (td) {
+                                               put_job(td);
+                                               td = NULL;
+                                       }
+                                       do_exit++;
+                                       break;
+                               }
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
                        break;
@@ -1887,6 +1927,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                case FIO_GETOPT_IOENGINE: {
                        const char *opt = l_opts[lidx].name;
                        char *val = optarg;
+
+                       if (!td)
+                               break;
+
                        ret = fio_cmd_ioengine_option_parse(td, opt, val);
                        break;
                }
@@ -1902,6 +1946,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        }
                        break;
                case 'S':
+                       did_arg = 1;
                        if (nr_clients) {
                                log_err("fio: can't be both client and server\n");
                                do_exit++;
@@ -1914,17 +1959,21 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        backend = 1;
                        break;
                case 'D':
+                       if (pid_file)
+                               free(pid_file);
                        pid_file = strdup(optarg);
                        break;
                case 'I':
                        if ((ret = fio_idle_prof_parse_opt(optarg))) {
                                /* exit on error and calibration only */
+                               did_arg = 1;
                                do_exit++;
-                               if (ret == -1) 
+                               if (ret == -1)
                                        exit_val = 1;
                        }
                        break;
                case 'C':
+                       did_arg = 1;
                        if (is_backend) {
                                log_err("fio: can't be both client and server\n");
                                do_exit++;
@@ -1951,10 +2000,12 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        }
                        break;
                case 'T':
+                       did_arg = 1;
                        do_exit++;
                        exit_val = fio_monotonic_clocktest();
                        break;
                case 'G':
+                       did_arg = 1;
                        do_exit++;
                        exit_val = fio_crctest(optarg);
                        break;
@@ -1994,8 +2045,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                free(pid_file);
 
        if (td) {
-               if (!ret)
+               if (!ret) {
                        ret = add_job(td, td->o.name ?: "fio", 0, 0, client_type);
+                       if (ret)
+                               did_arg = 1;
+               }
        }
 
        while (!ret && optind < argc) {
@@ -2005,6 +2059,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                optind++;
        }
 
+out_free:
+       if (pid_file)
+               free(pid_file);
+
        return ini_idx;
 }