init: improve command line check for when to print usage/help
[fio.git] / init.c
diff --git a/init.c b/init.c
index 910f2badbcfda054d8a6f300575093eabb572924..7630978cc3ca805839dbbf280f8681b83925295d 100644 (file)
--- a/init.c
+++ b/init.c
@@ -38,7 +38,7 @@ const char fio_version_string[] = FIO_VERSION;
 static char **ini_file;
 static int max_jobs = FIO_MAX_JOBS;
 static int dump_cmdline;
-static int def_timeout;
+static long long def_timeout;
 static int parse_only;
 
 static struct thread_data def_thread;
@@ -318,6 +318,14 @@ static int setup_thread_area(void)
        return 0;
 }
 
+static void set_cmd_options(struct thread_data *td)
+{
+       struct thread_options *o = &td->o;
+
+       if (!o->timeout)
+               o->timeout = def_timeout;
+}
+
 /*
  * Return a free job structure.
  */
@@ -326,8 +334,10 @@ static struct thread_data *get_new_job(int global, struct thread_data *parent,
 {
        struct thread_data *td;
 
-       if (global)
+       if (global) {
+               set_cmd_options(&def_thread);
                return &def_thread;
+       }
        if (setup_thread_area()) {
                log_err("error: failed to setup shm segment\n");
                return NULL;
@@ -354,9 +364,10 @@ 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);
        return td;
 }
 
@@ -931,6 +942,7 @@ static char *make_filename(char *buf, struct thread_options *o,
 {
        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);
@@ -958,25 +970,47 @@ 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);
                } while (1);
@@ -1424,9 +1458,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);
@@ -1440,8 +1471,8 @@ static int fill_def_thread(void)
        memset(&def_thread, 0, sizeof(def_thread));
 
        fio_getaffinity(getpid(), &def_thread.o.cpumask);
-       def_thread.o.timeout = def_timeout;
        def_thread.o.error_dump = 1;
+
        /*
         * fill default options
         */
@@ -1683,8 +1714,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;
@@ -1695,7 +1724,11 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        smalloc_pool_size = atoi(optarg);
                        break;
                case 't':
-                       def_timeout = atoi(optarg);
+                       if (check_str_time(optarg, &def_timeout, 1)) {
+                               log_err("fio: failed parsing time %s\n", optarg);
+                               do_exit++;
+                               exit_val = 1;
+                       }
                        break;
                case 'l':
                        write_lat_log = 1;
@@ -1704,6 +1737,9 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                        write_bw_log = 1;
                        break;
                case 'o':
+                       if (f_out)
+                               fclose(f_out);
+
                        f_out = fopen(optarg, "w+");
                        if (!f_out) {
                                perror("fopen output");
@@ -1734,30 +1770,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++;
@@ -1794,6 +1835,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': {
@@ -1813,6 +1855,9 @@ 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);
                        break;
                case FIO_GETOPT_JOB: {
@@ -1822,8 +1867,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);
@@ -1837,7 +1883,7 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
 
                                td = get_new_job(global, &def_thread, 1);
                                if (!td || ioengine_load(td))
-                                       return 0;
+                                       goto out_free;
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
 
@@ -1859,7 +1905,7 @@ 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;
+                                       goto out_free;
                                fio_options_set_ioengine_opts(l_opts, td);
                        }
                        break;
@@ -1867,7 +1913,12 @@ 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);
+                       did_arg = 1;
                        break;
                }
                case 'w':
@@ -1882,6 +1933,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++;
@@ -1894,17 +1946,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++;
@@ -1931,10 +1987,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;
@@ -1970,10 +2028,15 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
 
        if (is_backend && backend)
                return fio_start_server(pid_file);
+       else if (pid_file)
+               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) {
@@ -1983,6 +2046,10 @@ int parse_cmd_line(int argc, char *argv[], int client_type)
                optind++;
        }
 
+out_free:
+       if (pid_file)
+               free(pid_file);
+
        return ini_idx;
 }
 
@@ -2018,7 +2085,7 @@ int parse_options(int argc, char *argv[])
 
        if (job_files > 0) {
                for (i = 0; i < job_files; i++) {
-                       if (fill_def_thread())
+                       if (i && fill_def_thread())
                                return 1;
                        if (nr_clients) {
                                if (fio_clients_send_ini(ini_file[i]))