diff options
author | Douglas Gilbert <dgilbert@interlog.com> | 2007-09-10 00:54:57 +0000 |
---|---|---|
committer | Douglas Gilbert <dgilbert@interlog.com> | 2007-09-10 00:54:57 +0000 |
commit | 7b165064d3d22cf8e699935bccef0e728857c4eb (patch) | |
tree | ec1fd18a51e9cef40fb333366a13796592bdceda /src/sg_turs.c | |
parent | 6716cee810f1680cefe477e0b8e191c3321cd3b7 (diff) | |
download | sg3_utils-7b165064d3d22cf8e699935bccef0e728857c4eb.tar.gz |
rearrange files into include, src, lib and doc directories
git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@100 6180dd3e-e324-4e3e-922d-17de1ae2f315
Diffstat (limited to 'src/sg_turs.c')
-rw-r--r-- | src/sg_turs.c | 370 |
1 files changed, 370 insertions, 0 deletions
diff --git a/src/sg_turs.c b/src/sg_turs.c new file mode 100644 index 00000000..ee65dc25 --- /dev/null +++ b/src/sg_turs.c @@ -0,0 +1,370 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef SG3_UTILS_MINGW +#include <sys/time.h> +#endif + +#include "sg_lib.h" +#include "sg_cmds_basic.h" + +/* This program sends a user specified number of TEST UNIT READY commands + to the given sg device. Since TUR is a simple command involing no + data transfer (and no REQUEST SENSE command iff the unit is ready) + then this can be used for timing per SCSI command overheads. + + * Copyright (C) 2000-2007 D. Gilbert + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + + */ + +static char * version_str = "3.26 20070714"; + +#if defined(MSC_VER) || defined(__MINGW32__) +#define HAVE_MS_SLEEP +#endif + +#ifdef HAVE_MS_SLEEP +#include <windows.h> +#define sleep_for(seconds) Sleep( (seconds) * 1000) +#else +#define sleep_for(seconds) sleep(seconds) +#endif + +static struct option long_options[] = { + {"help", 0, 0, 'h'}, + {"new", 0, 0, 'N'}, + {"number", 1, 0, 'n'}, + {"old", 0, 0, 'O'}, + {"progress", 0, 0, 'p'}, + {"time", 0, 0, 't'}, + {"verbose", 0, 0, 'v'}, + {"version", 0, 0, 'V'}, + {0, 0, 0, 0}, +}; + +struct opts_t { + int do_help; + int do_number; + int do_progress; + int do_time; + int do_verbose; + int do_version; + const char * device_name; + int opt_new; +}; + + +static void usage() +{ + printf("Usage: sg_turs [--help] [--number=NUM] [--progress] [--time] " + "[--verbose]\n" + " [--version] DEVICE\n" + " where:\n" + " --help|-h print usage message then exit\n" + " --number=NUM|-n NUM number of test_unit_ready commands " + "(def: 1)\n" + " --progress|-p outputs progress indication (percentage) " + "if available\n" + " --time|-t outputs total duration and commands per " + "second\n" + " --verbose|-v increase verbosity\n" + " --version|-V print version string then exit\n\n" + "Performs a SCSI TEST UNIT READY command (or many of them)\n"); +} + +static void usage_old() +{ + printf("Usage: sg_turs [-n=NUM] [-p] [-t] [-v] [-V] " + "DEVICE\n" + " where:\n" + " -n=NUM number of test_unit_ready commands " + "(def: 1)\n" + " -p outputs progress indication (percentage) " + "if available\n" + " -t outputs total duration and commands per " + "second\n" + " -v increase verbosity\n" + " -V print version string then exit\n\n" + "Performs a SCSI TEST UNIT READY command (or many of them)\n"); +} + +static void usage_for(const struct opts_t * optsp) +{ + if (optsp->opt_new) + usage(); + else + usage_old(); +} + +static int process_cl_new(struct opts_t * optsp, int argc, char * argv[]) +{ + int c, n; + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "hn:NOptvV", long_options, + &option_index); + if (c == -1) + break; + + switch (c) { + case 'h': + case '?': + ++optsp->do_help; + break; + case 'n': + n = sg_get_num(optarg); + if (n < 0) { + fprintf(stderr, "bad argument to '--number='\n"); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + optsp->do_number = n; + break; + case 'N': + break; /* ignore */ + case 'O': + optsp->opt_new = 0; + return 0; + case 'p': + ++optsp->do_progress; + break; + case 't': + ++optsp->do_time; + break; + case 'v': + ++optsp->do_verbose; + break; + case 'V': + ++optsp->do_version; + break; + default: + fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); + if (optsp->do_help) + break; + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + if (optind < argc) { + if (NULL == optsp->device_name) { + optsp->device_name = argv[optind]; + ++optind; + } + if (optind < argc) { + for (; optind < argc; ++optind) + fprintf(stderr, "Unexpected extra argument: %s\n", + argv[optind]); + usage(); + return SG_LIB_SYNTAX_ERROR; + } + } + return 0; +} + +static int process_cl_old(struct opts_t * optsp, int argc, char * argv[]) +{ + int k, jmp_out, plen; + const char * cp; + + for (k = 1; k < argc; ++k) { + cp = argv[k]; + plen = strlen(cp); + if (plen <= 0) + continue; + if ('-' == *cp) { + for (--plen, ++cp, jmp_out = 0; plen > 0; --plen, ++cp) { + switch (*cp) { + case 'N': + optsp->opt_new = 1; + return 0; + case 'O': + break; + case 'p': + ++optsp->do_progress; + break; + case 't': + ++optsp->do_time; + break; + case 'v': + ++optsp->do_verbose; + break; + case 'V': + ++optsp->do_verbose; + break; + case '?': + usage_old(); + return 0; + default: + jmp_out = 1; + break; + } + if (jmp_out) + break; + } + if (plen <= 0) + continue; + if (0 == strncmp("n=", cp, 2)) { + optsp->do_number = sg_get_num(cp + 2); + if (optsp->do_number <= 0) { + printf("Couldn't decode number after 'n=' option\n"); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strncmp("-old", cp, 4)) + ; + else if (jmp_out) { + fprintf(stderr, "Unrecognized option: %s\n", cp); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == optsp->device_name) + optsp->device_name = cp; + else { + fprintf(stderr, "too many arguments, got: %s, not expecting: " + "%s\n", optsp->device_name, cp); + usage_old(); + return SG_LIB_SYNTAX_ERROR; + } + } + return 0; +} + +static int process_cl(struct opts_t * optsp, int argc, char * argv[]) +{ + int res; + char * cp; + + cp = getenv("SG3_UTILS_OLD_OPTS"); + if (cp) { + optsp->opt_new = 0; + res = process_cl_old(optsp, argc, argv); + if ((0 == res) && optsp->opt_new) + res = process_cl_new(optsp, argc, argv); + } else { + optsp->opt_new = 1; + res = process_cl_new(optsp, argc, argv); + if ((0 == res) && (0 == optsp->opt_new)) + res = process_cl_old(optsp, argc, argv); + } + return res; +} + +int main(int argc, char * argv[]) +{ + int sg_fd, k, res, progress; + int num_errs = 0; + int reported = 0; + int ret = 0; +#ifndef SG3_UTILS_MINGW + struct timeval start_tm, end_tm; +#endif + struct opts_t opts; + + memset(&opts, 0, sizeof(opts)); + opts.do_number = 1; + res = process_cl(&opts, argc, argv); + if (res) + return SG_LIB_SYNTAX_ERROR; + if (opts.do_help) { + usage_for(&opts); + return 0; + } + if (opts.do_version) { + fprintf(stderr, "Version string: %s\n", version_str); + return 0; + } + + if (NULL == opts.device_name) { + fprintf(stderr, "No DEVICE argument given\n"); + usage_for(&opts); + return SG_LIB_SYNTAX_ERROR; + } + + if ((sg_fd = sg_cmds_open_device(opts.device_name, 1 /* ro */, + opts.do_verbose)) < 0) { + fprintf(stderr, "sg_turs: error opening file: %s: %s\n", + opts.device_name, safe_strerror(-sg_fd)); + return SG_LIB_FILE_ERROR; + } + if (opts.do_progress) { + for (k = 0; k < opts.do_number; ++k) { + if (k > 0) + sleep_for(30); + progress = -1; + res = sg_ll_test_unit_ready_progress(sg_fd, k, &progress, + ((1 == opts.do_number) ? 1 : 0), opts.do_verbose); + if (progress < 0) { + ret = res; + break; + } else + printf("Progress indication: %d%% done\n", + (progress * 100) / 65536); + } + if (opts.do_number > 1) + printf("Completed %d Test Unit Ready commands\n", + ((k < opts.do_number) ? k + 1 : k)); + } else { +#ifndef SG3_UTILS_MINGW + if (opts.do_time) { + start_tm.tv_sec = 0; + start_tm.tv_usec = 0; + gettimeofday(&start_tm, NULL); + } +#endif + for (k = 0; k < opts.do_number; ++k) { + res = sg_ll_test_unit_ready(sg_fd, k, 0, opts.do_verbose); + if (res) { + ++num_errs; + ret = res; + if ((1 == opts.do_number) && (SG_LIB_CAT_NOT_READY == res)) { + printf("device not ready\n"); + reported = 1; + break; + } + } + } +#ifndef SG3_UTILS_MINGW + if ((opts.do_time) && (start_tm.tv_sec || start_tm.tv_usec)) { + struct timeval res_tm; + double a, b; + + gettimeofday(&end_tm, NULL); + res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; + res_tm.tv_usec = end_tm.tv_usec - start_tm.tv_usec; + if (res_tm.tv_usec < 0) { + --res_tm.tv_sec; + res_tm.tv_usec += 1000000; + } + a = res_tm.tv_sec; + a += (0.000001 * res_tm.tv_usec); + b = (double)opts.do_number; + printf("time to perform commands was %d.%06d secs", + (int)res_tm.tv_sec, (int)res_tm.tv_usec); + if (a > 0.00001) + printf("; %.2f operations/sec\n", b / a); + else + printf("\n"); + } +#endif + + if (((opts.do_number > 1) || (num_errs > 0)) && (! reported)) + printf("Completed %d Test Unit Ready commands with %d errors\n", + opts.do_number, num_errs); + } + sg_cmds_close_device(sg_fd); + return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; +} |