From 84c586f1f1d8bd102928f3ae95d1d1185a59de8f Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Wed, 19 Jan 2022 19:12:36 +0000 Subject: [PATCH] round of coverity identified issue fixes (and non-issues) git-svn-id: https://svn.bingwo.ca/repos/sg3_utils/trunk@931 6180dd3e-e324-4e3e-922d-17de1ae2f315 diff --git a/lib/sg_cmds_basic.c b/lib/sg_cmds_basic.c index e177354..92dd102 100644 --- a/lib/sg_cmds_basic.c +++ b/lib/sg_cmds_basic.c @@ -192,7 +192,6 @@ int sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin, int pt_res, bool noisy, int verbose, int * o_sense_cat) { - bool favour_sense; int cat, slen, sstat, req_din_x, req_dout_x; int act_din_x, act_dout_x; const uint8_t * sbp; @@ -323,19 +322,23 @@ sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin, get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); pr2ws("%s: transport: %s\n", leadin, b); } - /* Shall we favour sense data over a transport error (given both) */ #ifdef SG_LIB_LINUX - favour_sense = false; /* DRIVER_SENSE is not passed through */ + return -1; /* DRIVER_SENSE is not passed through */ #else - favour_sense = ((SAM_STAT_CHECK_CONDITION == - get_scsi_pt_status_response(ptvp)) && (slen > 0)); + /* Shall we favour sense data over a transport error (given both) */ + { + bool favour_sense = ((SAM_STAT_CHECK_CONDITION == + get_scsi_pt_status_response(ptvp)) && (slen > 0)); + + if (favour_sense) + return sg_cmds_process_helper(leadin, req_din_x, act_din_x, + req_dout_x, act_dout_x, sbp, + slen, noisy, verbose, + o_sense_cat); + else + return -1; + } #endif - if (favour_sense) - return sg_cmds_process_helper(leadin, req_din_x, act_din_x, - req_dout_x, act_dout_x, sbp, slen, - noisy, verbose, o_sense_cat); - else - return -1; case SCSI_PT_RESULT_OS_ERR: if (verbose || noisy) { get_scsi_pt_os_err_str(ptvp, sizeof(b), b); diff --git a/lib/sg_cmds_extra.c b/lib/sg_cmds_extra.c index 7d4f453..bacb033 100644 --- a/lib/sg_cmds_extra.c +++ b/lib/sg_cmds_extra.c @@ -1807,6 +1807,7 @@ sg_ll_ata_pt(int sg_fd, const uint8_t * cdbp, int cdb_len, int k, res, slen, duration; int ret = -1; uint8_t apt_cdb[ATA_PT_32_CMDLEN]; + uint8_t incoming_apt_cdb[ATA_PT_32_CMDLEN]; uint8_t sense_b[SENSE_BUFF_LEN] = {0}; uint8_t * sp; const uint8_t * bp; @@ -1815,18 +1816,25 @@ sg_ll_ata_pt(int sg_fd, const uint8_t * cdbp, int cdb_len, char b[256]; memset(apt_cdb, 0, sizeof(apt_cdb)); + memset(incoming_apt_cdb, 0, sizeof(incoming_apt_cdb)); + if (NULL == cdbp) { + if (vb) + pr2ws("NULL cdb pointer\n"); + return -1; + } + memcpy(incoming_apt_cdb, cdbp, cdb_len); b[0] = '\0'; switch (cdb_len) { case 12: cnamep = "ATA pass-through(12)"; apt_cdb[0] = ATA_PT_12_CMD; - memcpy(apt_cdb + 1, cdbp + 1, 10); + memcpy(apt_cdb + 1, incoming_apt_cdb + 1, 10); /* control byte at cdb[11] left at zero */ break; case 16: cnamep = "ATA pass-through(16)"; apt_cdb[0] = ATA_PT_16_CMD; - memcpy(apt_cdb + 1, cdbp + 1, 14); + memcpy(apt_cdb + 1, incoming_apt_cdb + 1, 14); /* control byte at cdb[15] left at zero */ break; case 32: @@ -1835,17 +1843,12 @@ sg_ll_ata_pt(int sg_fd, const uint8_t * cdbp, int cdb_len, /* control byte at cdb[1] left at zero */ apt_cdb[7] = 0x18; /* length starting at next byte */ sg_put_unaligned_be16(ATA_PT_32_SA, apt_cdb + 8); - memcpy(apt_cdb + 10, cdbp + 10, 32 - 10); + memcpy(apt_cdb + 10, incoming_apt_cdb + 10, 32 - 10); break; default: pr2ws("cdb_len must be 12, 16 or 32\n"); return -1; } - if (NULL == cdbp) { - if (vb) - pr2ws("%s NULL cdb pointer\n", cnamep); - return -1; - } if (sensep && (max_sense_len >= (int)sizeof(sense_b))) { sp = sensep; slen = max_sense_len; diff --git a/lib/sg_lib.c b/lib/sg_lib.c index 35f0fbd..1b267e4 100644 --- a/lib/sg_lib.c +++ b/lib/sg_lib.c @@ -3556,16 +3556,15 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, k = read(fd, mp_arr, max_arr_len); if (k <= 0) { if (0 == k) { - ret = SG_LIB_SYNTAX_ERROR; + ret = SG_LIB_FILE_ERROR; pr2ws("read 0 bytes from binary file %s\n", fname); } else { ret = sg_convert_errno(errno); pr2ws("read from binary file %s: %s\n", fname, safe_strerror(errno)); } - goto bin_fini; - } - if ((0 == fstat(fd, &a_stat)) && S_ISFIFO(a_stat.st_mode)) { + } else if ((k < max_arr_len) && (0 == fstat(fd, &a_stat)) && + S_ISFIFO(a_stat.st_mode)) { /* pipe; keep reading till error or 0 read */ while (k < max_arr_len) { m = read(fd, mp_arr + k, max_arr_len - k); @@ -3576,13 +3575,13 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, pr2ws("read from binary pipe %s: %s\n", fname, safe_strerror(err)); ret = sg_convert_errno(err); - goto bin_fini; + break; } k += m; } } - *mp_arr_len = k; -bin_fini: + if (k >= 0) + *mp_arr_len = k; if ((fd >= 0) && (! has_stdin)) close(fd); return ret; @@ -3623,9 +3622,17 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; - if (1 == sscanf(carry_over, "%4x", &h)) - mp_arr[off - 1] = h; /* back up and overwrite */ - else { + if (1 == sscanf(carry_over, "%4x", &h)) { + if (off > 0) { + if (off > max_arr_len) { + pr2ws("%s: array length exceeded\n", __func__); + ret = SG_LIB_LBA_OUT_OF_RANGE; + *mp_arr_len = max_arr_len; + goto fini; + } else + mp_arr[off - 1] = h; /* back up and overwrite */ + } + } else { pr2ws("%s: carry_over error ['%s'] around line %d\n", __func__, carry_over, j + 1); ret = SG_LIB_SYNTAX_ERROR; @@ -3667,8 +3674,8 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, *mp_arr_len = max_arr_len; ret = SG_LIB_LBA_OUT_OF_RANGE; goto fini; - } - mp_arr[off + k] = h; + } else + mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; @@ -3692,8 +3699,8 @@ sg_f2hex_arr(const char * fname, bool as_binary, bool no_space, ret = SG_LIB_LBA_OUT_OF_RANGE; *mp_arr_len = max_arr_len; goto fini; - } - mp_arr[off + k] = h; + } else + mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; @@ -3766,7 +3773,11 @@ uint32_t sg_get_page_size(void) { #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) - return (uint32_t)sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ + { + long res = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ + + return (res <= 0) ? 4096 : res; + } #elif defined(SG_LIB_WIN32) static bool got_page_size = false; static uint32_t win_page_size; diff --git a/src/sg_dd.c b/src/sg_dd.c index 2fa3750..65f7698 100644 --- a/src/sg_dd.c +++ b/src/sg_dd.c @@ -85,6 +85,8 @@ static const char * version_str = "6.31 20211114"; #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define DEF_MODE_CDB_SZ 10 #define DEF_MODE_RESP_LEN 252 @@ -1848,15 +1850,16 @@ main(int argc, char * argv[]) bpt_given = true; } else if (0 == strcmp(key, "bs")) { blk_sz = sg_get_num(buf); - bpt_given = true; - } else if (0 == strcmp(key, "bs")) { - blk_sz = sg_get_num(buf); - if (-1 == blk_sz) { + if ((blk_sz < 0) || (blk_sz > MAX_BPT_VALUE)) { pr2serr(ME "bad argument to 'bs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "cdbsz")) { iflag.cdbsz = sg_get_num(buf); + if ((iflag.cdbsz < 6) || (iflag.cdbsz > 32)) { + pr2serr(ME "'cdbsz' expects 6, 10, 12, 16 or 32\n"); + return SG_LIB_SYNTAX_ERROR; + } oflag.cdbsz = iflag.cdbsz; cdbsz_given = true; } else if (0 == strcmp(key, "cdl")) { @@ -1894,7 +1897,7 @@ main(int argc, char * argv[]) } else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); - if (-1LL == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'count='\n"); return SG_LIB_SYNTAX_ERROR; } @@ -1906,9 +1909,13 @@ main(int argc, char * argv[]) t = sg_get_num(buf); oflag.fua = !! (t & 1); iflag.fua = !! (t & 2); - } else if (0 == strcmp(key, "ibs")) + } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); - else if (strcmp(key, "if") == 0) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { + pr2serr(ME "bad argument to 'ibs='\n"); + return SG_LIB_SYNTAX_ERROR; + } + } else if (strcmp(key, "if") == 0) { if ('\0' != inf[0]) { pr2serr("Second IFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; @@ -1921,9 +1928,13 @@ main(int argc, char * argv[]) pr2serr(ME "bad argument to 'iflag='\n"); return SG_LIB_SYNTAX_ERROR; } - } else if (0 == strcmp(key, "obs")) + } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); - else if (0 == strcmp(key, "odir")) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { + pr2serr(ME "bad argument to 'obs='\n"); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key, "odir")) { iflag.direct = !! sg_get_num(buf); oflag.direct = iflag.direct; } else if (strcmp(key, "of") == 0) { @@ -1956,13 +1967,13 @@ main(int argc, char * argv[]) } } else if (0 == strcmp(key, "seek")) { seek = sg_get_llnum(buf); - if (-1LL == seek) { + if ((seek < 0) || (seek > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'seek='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "skip")) { skip = sg_get_llnum(buf); - if (-1LL == skip) { + if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'skip='\n"); return SG_LIB_SYNTAX_ERROR; } @@ -2080,8 +2091,8 @@ main(int argc, char * argv[]) pr2serr("Can't use both append and seek switches\n"); return SG_LIB_CONTRADICT; } - if (bpt < 1) { - pr2serr("bpt must be greater than 0\n"); + if ((bpt < 1) || (bpt > MAX_BPT_VALUE)) { + pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } if (iflag.sparse) diff --git a/src/sg_logs.c b/src/sg_logs.c index 694ee6e..de5d339 100644 --- a/src/sg_logs.c +++ b/src/sg_logs.c @@ -669,8 +673,8 @@ get_vp_mask(int vpn) if (vpn < 0) return 0; else - return (vpn > (32 - MVP_OFFSET)) ? OVP_ALL : - (1 << (vpn + MVP_OFFSET)); + return (vpn >= (32 - MVP_OFFSET)) ? OVP_ALL : + (1 << (vpn + MVP_OFFSET)); } static int diff --git a/src/sg_map26.c b/src/sg_map26.c index 3fca019..2ea8d69 100644 --- a/src/sg_map26.c +++ b/src/sg_map26.c @@ -396,7 +396,7 @@ list_matching_nodes(const char * dir_name, int file_type, int majj, int minn, } struct sg_item_t { - char name[NAME_LEN_MAX]; + char name[NAME_LEN_MAX + 2]; int ft; int nt; int d_type; diff --git a/src/sg_modes.c b/src/sg_modes.c index 47062b1..c0fc87f 100644 --- a/src/sg_modes.c +++ b/src/sg_modes.c @@ -790,6 +790,9 @@ dStrRaw(const uint8_t * str, int len) printf("%c", str[k]); } +/* Note to coverity: this function is safe as long as the page_code_desc + * objects pointed to by pcdp have a sentinel object at the end of each + * array. And they do by design.*/ static int count_desc_elems(const struct page_code_desc * pcdp) { diff --git a/src/sg_persist.c b/src/sg_persist.c index e779fe4..872f16e 100644 --- a/src/sg_persist.c +++ b/src/sg_persist.c @@ -1279,7 +1279,9 @@ main(int argc, char * argv[]) flagged = true; goto fini; } - sg_cmds_close_device(sg_fd); + res = sg_cmds_close_device(sg_fd); + if (res < 0) + pr2serr("%s: sg_cmds_close_device() failed res=%d\n", ME, res); } if (! op->readwrite_force) { diff --git a/src/sg_raw.c b/src/sg_raw.c index 9cfa19c..453a85a 100644 --- a/src/sg_raw.c +++ b/src/sg_raw.c @@ -323,7 +323,7 @@ parse_cmd_line(struct opts_t * op, int argc, char *argv[]) return SG_LIB_SYNTAX_ERROR; } - if (op->cdb_length > MAX_SCSI_CDBSZ) { + if (op->cdb_length >= MAX_SCSI_CDBSZ) { pr2serr("CDB too long (max. %d bytes)\n", MAX_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } diff --git a/src/sg_read.c b/src/sg_read.c index 628e0d8..a4f7cee 100644 --- a/src/sg_read.c +++ b/src/sg_read.c @@ -58,12 +58,14 @@ #include "sg_pr2serr.h" -static const char * version_str = "1.36 20191220"; +static const char * version_str = "1.38 20220118"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define ME "sg_read: " @@ -456,30 +458,35 @@ main(int argc, char * argv[]) do_blk_sgio = !! sg_get_num(buf); else if (0 == strcmp(key,"bpt")) { bpt = sg_get_num(buf); - if (-1 == bpt) { + if ((bpt < 0) || (bpt > MAX_BPT_VALUE)) { pr2serr( ME "bad argument to 'bpt'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"bs")) { bs = sg_get_num(buf); - if (-1 == bs) { + if ((bs < 0) || (bs > MAX_BPT_VALUE)) { pr2serr( ME "bad argument to 'bs'\n"); return SG_LIB_SYNTAX_ERROR; } - } else if (0 == strcmp(key,"cdbsz")) + } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz = sg_get_num(buf); - else if (0 == strcmp(key,"count")) { + if ((scsi_cdbsz < 0) || (scsi_cdbsz > 32)) { + pr2serr( ME "bad argument to 'cdbsz', expect 6, 10, 12, 16 " + "or 32\n"); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"count")) { count_given = true; if ('-' == *buf) { dd_count = sg_get_llnum(buf + 1); - if (-1 == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr( ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } dd_count = - dd_count; } else { dd_count = sg_get_llnum(buf); - if (-1 == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr( ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } @@ -504,7 +511,7 @@ main(int argc, char * argv[]) outf[INF_SZ - 1] = '\0'; } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); - if (-1 == skip) { + if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr( ME "bad argument to 'skip'\n"); return SG_LIB_SYNTAX_ERROR; } diff --git a/src/sg_read_buffer.c b/src/sg_read_buffer.c index 93c32a5..01a79c3 100644 --- a/src/sg_read_buffer.c +++ b/src/sg_read_buffer.c @@ -483,7 +483,10 @@ main(int argc, char * argv[]) do_long = true; break; case 'm': - if (isdigit((uint8_t)*optarg)) { + if (NULL == optarg) { + pr2serr("bad argument to '--mode'\n"); + return SG_LIB_SYNTAX_ERROR; + } else if (isdigit((uint8_t)*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { pr2serr("argument to '--mode' should be in the range 0 " diff --git a/src/sg_sat_phy_event.c b/src/sg_sat_phy_event.c index 9b1f588..090ecf7 100644 --- a/src/sg_sat_phy_event.c +++ b/src/sg_sat_phy_event.c @@ -154,15 +154,17 @@ dStrRaw(const uint8_t * str, int len) } /* ATA READ LOG EXT command [2Fh, PIO data-in] */ -/* N.B. "log_addr" is the log page number, "page_in_log" is usually false */ +/* N.B. "log_addr" is the log page number, "page_in_log" is usually 0 */ static int -do_read_log_ext(int sg_fd, int log_addr, bool page_in_log, int feature, +do_read_log_ext(int sg_fd, int log_addr, int page_in_log, int feature, int blk_count, void * resp, int mx_resp_len, int cdb_len, bool ck_cond, bool extend, int do_hex, bool do_raw, int verbose) { /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ +#if 0 bool t_type = false;/* false -> 512 byte LBs, true -> device's LB size */ +#endif bool t_dir = true; /* false -> to device, 1 -> from device */ bool byte_block = true; /* false -> bytes, true -> 512 byte blocks (if t_type=false) */ @@ -205,8 +207,10 @@ do_read_log_ext(int sg_fd, int log_addr, bool page_in_log, int feature, apt_cdb[2] = t_length; if (ck_cond) apt_cdb[2] |= 0x20; +#if 0 if (t_type) apt_cdb[2] |= 0x10; +#endif if (t_dir) apt_cdb[2] |= 0x8; if (byte_block) @@ -226,8 +230,10 @@ do_read_log_ext(int sg_fd, int log_addr, bool page_in_log, int feature, apt12_cdb[2] = t_length; if (ck_cond) apt12_cdb[2] |= 0x20; +#if 0 if (t_type) apt12_cdb[2] |= 0x10; +#endif if (t_dir) apt12_cdb[2] |= 0x8; if (byte_block) @@ -487,7 +493,7 @@ int main(int argc, char * argv[]) return sg_convert_errno(err); } ret = do_read_log_ext(sg_fd, SATA_PHY_EVENT_LPAGE, - false /* page_in_log */, + 0 /* page_in_log */, (reset ? 1 : 0) /* feature */, 1 /* blk_count */, inBuff, READ_LOG_EXT_RESPONSE_LEN, cdb_len, ck_cond, diff --git a/src/sg_scan_linux.c b/src/sg_scan_linux.c index 7354ad4..c04206a 100644 --- a/src/sg_scan_linux.c +++ b/src/sg_scan_linux.c @@ -203,6 +203,7 @@ int main(int argc, char * argv[]) printf(ME "Out of memory\n"); return SG_LIB_CAT_OTHER; } + strcpy(fname, ""); for (k = 1, j = 0; k < argc; ++k) { cp = argv[k]; diff --git a/src/sg_stpg.c b/src/sg_stpg.c index e57b13c..a12b5ca 100644 --- a/src/sg_stpg.c +++ b/src/sg_stpg.c @@ -142,15 +142,14 @@ dStrRaw(const uint8_t * str, int len) static int decode_target_port(uint8_t * buff, int len, int *d_id, int *d_tpg) { - int c_set, assoc, desig_type, i_len; - int off, u; + int c_set, assoc, desig_type, i_len, off; const uint8_t * bp; const uint8_t * ip; *d_id = -1; *d_tpg = -1; off = -1; - while ((u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0) { + while (sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1) == 0) { bp = buff + off; i_len = bp[3]; if ((off + i_len + 4) > len) { diff --git a/src/sg_vpd.c b/src/sg_vpd.c index 0ca6303..1a74af5 100644 --- a/src/sg_vpd.c +++ b/src/sg_vpd.c @@ -755,6 +755,7 @@ decode_dev_ids_quiet(uint8_t * buff, int len, int m_assoc, uint8_t sas_tport_addr[8]; rtp = 0; + u = 0; memset(sas_tport_addr, 0, sizeof(sas_tport_addr)); for (k = 0, off = -1; true; ++k) { if ((0 == k) && (0 != buff[2])) { diff --git a/src/sg_xcopy.c b/src/sg_xcopy.c index 4307668..39ad83c 100644 --- a/src/sg_xcopy.c +++ b/src/sg_xcopy.c @@ -306,7 +306,7 @@ open_sg(struct xcopy_fp_t * fp, int vb) int devmajor, devminor, offset; struct sg_simple_inquiry_resp sir; char ebuff[EBUFF_SZ]; - int len; + int len, res; devmajor = major(fp->devno); devminor = minor(fp->devno); @@ -344,7 +344,9 @@ open_sg(struct xcopy_fp_t * fp, int vb) } if (sg_simple_inquiry(fp->sg_fd, &sir, false, vb)) { pr2serr("INQUIRY failed on %s\n", ebuff); - sg_cmds_close_device(fp->sg_fd); + res = sg_cmds_close_device(fp->sg_fd); + if (res < 0) + pr2serr("sg_cmds_close_device() failed as well\n"); fp->sg_fd = -1; return -1; } @@ -1024,7 +1026,7 @@ desc_from_vpd_id(int sg_fd, uint8_t *desc, int desc_len, int res, verb; uint8_t rcBuff[256], *bp, *best = NULL; unsigned int len = 254; - int off = -1, u, i_len, best_len = 0, assoc, desig, f_desig = 0; + int off = -1, i_len, best_len = 0, assoc, desig, f_desig = 0; char b[80]; verb = (verbose ? verbose - 1: 0); @@ -1060,8 +1062,7 @@ desc_from_vpd_id(int sg_fd, uint8_t *desc, int desc_len, hex2stderr(rcBuff, len, 1); } - while ((u = sg_vpd_dev_id_iter(rcBuff + 4, len - 4, &off, 0, -1, -1)) == - 0) { + while (sg_vpd_dev_id_iter(rcBuff + 4, len - 4, &off, 0, -1, -1) == 0) { bp = rcBuff + 4 + off; i_len = bp[3]; if (((unsigned int)off + i_len + 4) > len) { diff --git a/src/sgm_dd.c b/src/sgm_dd.c index e95fca9..aa656b3 100644 --- a/src/sgm_dd.c +++ b/src/sgm_dd.c @@ -69,13 +69,15 @@ #include "sg_pr2serr.h" -static const char * version_str = "1.17 20211024"; +static const char * version_str = "1.19 20220118"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define ME "sgm_dd: " @@ -795,6 +797,10 @@ main(int argc, char * argv[]) } } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz_in = sg_get_num(buf); + if ((scsi_cdbsz_in < 6) || (scsi_cdbsz_in > 32)) { + pr2serr(ME "'cdbsz' expects 6, 10, 12, 16 or 32\n"); + return SG_LIB_SYNTAX_ERROR; + } scsi_cdbsz_out = scsi_cdbsz_in; cdbsz_given = true; } else if (0 == strcmp(key,"coe")) { @@ -803,7 +809,7 @@ main(int argc, char * argv[]) } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); - if (-1LL == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } @@ -818,7 +824,7 @@ main(int argc, char * argv[]) in_flags.fua = true; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); - if (-1 == ibs) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr(ME "bad argument to 'ibs'\n"); return SG_LIB_SYNTAX_ERROR; } @@ -850,19 +856,19 @@ main(int argc, char * argv[]) } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); - if (-1 == obs) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr(ME "bad argument to 'obs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); - if (-1LL == seek) { + if ((seek < 0) || (seek > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'seek'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); - if (-1LL == skip) { + if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr(ME "bad argument to 'skip'\n"); return SG_LIB_SYNTAX_ERROR; } @@ -955,8 +961,8 @@ main(int argc, char * argv[]) pr2serr("Can't use both append and seek switches\n"); return SG_LIB_CONTRADICT; } - if (bpt < 1) { - pr2serr("bpt must be greater than 0\n"); + if ((bpt < 1) || (bpt > MAX_BPT_VALUE)) { + pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } /* defaulting transfer size to 128*2048 for CD/DVDs is too large diff --git a/src/sgp_dd.c b/src/sgp_dd.c index b71bf7b..a36d9d0 100644 --- a/src/sgp_dd.c +++ b/src/sgp_dd.c @@ -85,13 +85,15 @@ #include "sg_pr2serr.h" -static const char * version_str = "5.83 20211105"; +static const char * version_str = "5.84 20220118"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_BLOCKS_PER_2048TRANSFER 32 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ @@ -370,13 +372,15 @@ thread_exit_handler(int sig) static char * tsafe_strerror(int code, char * ebp) { + int status; char * cp; - pthread_mutex_lock(&strerr_mut); + status = pthread_mutex_lock(&strerr_mut); + if (0 != status) pr2serr("lock strerr_mut"); cp = safe_strerror(code); strncpy(ebp, cp, STRERR_BUFF_LEN); - pthread_mutex_unlock(&strerr_mut); - + status = pthread_mutex_unlock(&strerr_mut); + if (0 != status) pr2serr("unlock strerr_mut"); ebp[STRERR_BUFF_LEN - 1] = '\0'; return ebp; } @@ -649,8 +653,10 @@ sg_in_open(const char * fnp, struct flags_t * flagp, int bs, int bpt) perror(ebuff); return -sg_convert_errno(err); } - if (sg_prepare(fd, bs, bpt)) + if (sg_prepare(fd, bs, bpt)) { + close(fd); return -SG_LIB_FILE_ERROR; + } return fd; } @@ -675,8 +681,10 @@ sg_out_open(const char * fnp, struct flags_t * flagp, int bs, int bpt) perror(ebuff); return -sg_convert_errno(err); } - if (sg_prepare(fd, bs, bpt)) + if (sg_prepare(fd, bs, bpt)) { + close(fd); return -SG_LIB_FILE_ERROR; + } return fd; } @@ -1424,19 +1432,23 @@ main(int argc, char * argv[]) keylen = strlen(key); if (0 == strcmp(key,"bpt")) { clp->bpt = sg_get_num(buf); - if (-1 == clp->bpt) { + if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key,"bs")) { clp->bs = sg_get_num(buf); - if (-1 == clp->bs) { + if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { clp->cdbsz_in = sg_get_num(buf); + if ((clp->cdbsz_in < 6) || (clp->cdbsz_in > 32)) { + pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } clp->cdbsz_out = clp->cdbsz_in; cdbsz_given = 1; } else if (0 == strcmp(key,"coe")) { @@ -1445,7 +1457,7 @@ main(int argc, char * argv[]) } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); - if (-1LL == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -1464,7 +1476,7 @@ main(int argc, char * argv[]) clp->in_flags.fua = true; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); - if (-1 == ibs) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -1483,7 +1495,7 @@ main(int argc, char * argv[]) } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); - if (-1 == obs) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -1502,13 +1514,13 @@ main(int argc, char * argv[]) } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); - if (-1LL == seek) { + if ((seek < 0) || (seek > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); - if (-1LL == skip) { + if ((skip < 0) || (skip > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -1611,8 +1623,8 @@ main(int argc, char * argv[]) pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } - if (clp->bpt < 1) { - pr2serr("bpt must be greater than 0\n"); + if ((clp->bpt < 1) || (clp->bpt > MAX_BPT_VALUE)) { + pr2serr("bpt must be > 0 and <= %d\n", MAX_BPT_VALUE); return SG_LIB_SYNTAX_ERROR; } if (clp->in_flags.mmap && clp->out_flags.mmap) { @@ -1851,9 +1863,14 @@ main(int argc, char * argv[]) clp->out_count = dd_count; clp->out_rem_count = dd_count; clp->seek = seek; - clp->out_blk = seek; status = pthread_mutex_init(&clp->inout_mutex, NULL); if (0 != status) err_exit(status, "init inout_mutex"); + status = pthread_mutex_lock(&clp->inout_mutex); + if (0 != status) err_exit(status, "lock inout_mutex"); + clp->out_blk = seek; + status = pthread_mutex_unlock(&clp->inout_mutex); + if (0 != status) err_exit(status, "unlock inout_mutex"); + status = pthread_cond_init(&clp->out_sync_cv, NULL); if (0 != status) err_exit(status, "init out_sync_cv"); diff --git a/testing/sg_mrq_dd.cpp b/testing/sg_mrq_dd.cpp index a97aa9b..7b81a63 100644 --- a/testing/sg_mrq_dd.cpp +++ b/testing/sg_mrq_dd.cpp @@ -141,6 +141,8 @@ using namespace std; #define MAX_SCSI_CDB_SZ 16 /* could be 32 */ #define PACK_ID_TID_MULTIPLIER (0x1000000) /* 16,777,216 */ #define MAX_SLICES 16 /* number of IFILE,OFILE pairs */ +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 @@ -3361,7 +3363,7 @@ skip_seek(struct global_collection *clp, const char * key, const char * buf, } } else { /* single number on command line (e.g. skip=1234) */ ll = sg_get_llnum(buf); - if (-1LL == ll) { + if ((ll < 0) || (ll > MAX_COUNT_SKIP_SEEK)) { pr2serr("bad argument to '%s='\n", key); return SG_LIB_SYNTAX_ERROR; } @@ -3544,14 +3546,14 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, keylen = strlen(key); if (0 == strcmp(key, "bpt")) { clp->bpt = sg_get_num(buf); - if (-1 == clp->bpt) { + if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); goto syn_err; } bpt_given = true; } else if (0 == strcmp(key, "bs")) { clp->bs = sg_get_num(buf); - if (-1 == clp->bs) { + if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); goto syn_err; } @@ -3611,7 +3613,8 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, } if (0 != strcmp("-1", buf)) { clp->dd_count = sg_get_llnum(buf); - if (-1LL == clp->dd_count) { + if ((clp->dd_count < 0) || + (clp->dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); goto syn_err; } @@ -3622,7 +3625,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->out_flags.dio = clp->in_flags.dio; } else if (0 == strcmp(key, "elemsz_kb")) { n = sg_get_num(buf); - if (n < 1) { + if ((n < 1) || (n > (MAX_BPT_VALUE / 1024))) { pr2serr("elemsz_kb=EKB wants an integer > 0\n"); goto syn_err; } @@ -3646,7 +3649,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->in_flags.fua = true; } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); - if (-1 == ibs) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); goto syn_err; } @@ -3700,7 +3703,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->out_flags.no_waitq = true; } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); - if (-1 == obs) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); goto syn_err; } @@ -3769,9 +3772,13 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, memcpy(skip_buf, buf, n + 1); } else if (0 == strcmp(key, "sync")) do_sync = !! sg_get_num(buf); - else if (0 == strcmp(key, "thr")) + else if (0 == strcmp(key, "thr")) { num_threads = sg_get_num(buf); - else if (0 == strcmp(key, "time")) { + if ((num_threads < 0) || (num_threads > MAX_BPT_VALUE)) { + pr2serr("%sneed argument to 'skip='\n", my_name); + goto syn_err; + } + } else if (0 == strcmp(key, "time")) { ccp = strchr(buf, ','); do_time = sg_get_num(buf); if (do_time < 0) { @@ -3780,7 +3787,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, } if (ccp) { n = sg_get_num(ccp + 1); - if (n < 0) { + if ((n < 0) || (n > (MAX_BPT_VALUE / 1000))) { pr2serr("%sbad argument to 'time=0|1|2,TO'\n", my_name); goto syn_err; } diff --git a/testing/sgh_dd.cpp b/testing/sgh_dd.cpp index 38ee1d5..2c1f243 100644 --- a/testing/sgh_dd.cpp +++ b/testing/sgh_dd.cpp @@ -134,6 +134,8 @@ using namespace std; #define DEF_SDT_CRT_SEC 3 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 @@ -4043,19 +4045,23 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->aen_given = true; } else if (0 == strcmp(key, "bpt")) { clp->bpt = sg_get_num(buf); - if (-1 == clp->bpt) { + if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bpt='\n", my_name); return SG_LIB_SYNTAX_ERROR; } bpt_given = true; } else if (0 == strcmp(key, "bs")) { clp->bs = sg_get_num(buf); - if (-1 == clp->bs) { + if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'bs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "cdbsz")) { clp->cdbsz_in = sg_get_num(buf); + if ((clp->cdbsz_in < 6) || (clp->cdbsz_in > 32)) { + pr2serr("%s'cdbsz' expects 6, 10, 12, 16 or 32\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } clp->cdbsz_out = clp->cdbsz_in; clp->cdbsz_given = true; } else if (0 == strcmp(key, "coe")) { @@ -4069,7 +4075,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, } else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); - if (-1LL == dd_count) { + if ((dd_count < 0) || (dd_count > MAX_COUNT_SKIP_SEEK)) { pr2serr("%sbad argument to 'count='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -4103,7 +4109,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->in_flags.fua = true; } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); - if (-1 == ibs) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'ibs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -4148,7 +4154,7 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, clp->noshare = !! sg_get_num(buf); } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); - if (-1 == obs) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { pr2serr("%sbad argument to 'obs='\n", my_name); return SG_LIB_SYNTAX_ERROR; } @@ -4206,13 +4212,13 @@ parse_cmdline_sanity(int argc, char * argv[], struct global_collection * clp, } } else if (0 == strcmp(key, "seek")) { clp->seek = sg_get_llnum(buf); - if (-1LL == clp->seek) { + if (clp->seek < 0) { pr2serr("%sbad argument to 'seek='\n", my_name); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "skip")) { clp->skip = sg_get_llnum(buf); - if (-1LL == clp->skip) { + if (clp->skip < 0) { pr2serr("%sbad argument to 'skip='\n", my_name); return SG_LIB_SYNTAX_ERROR; } diff --git a/testing/sgs_dd.c b/testing/sgs_dd.c index 65b2c06..60d25aa 100644 --- a/testing/sgs_dd.c +++ b/testing/sgs_dd.c @@ -100,6 +100,8 @@ static const char * my_name = "sgs_dd"; #define SGQ_MAX_RD_AHEAD 32 #define SGQ_MAX_WR_AHEAD 32 #define SGQ_NUM_ELEMS (SGQ_MAX_RD_AHEAD + SGQ_MAX_WR_AHEAD + 1) +#define MAX_BPT_VALUE (1 << 24) /* used for maximum bs as well */ +#define MAX_COUNT_SKIP_SEEK (1LL << 48) /* coverity wants upper bound */ #define SGQ_FREE 0 #define SGQ_IO_STARTED 1 @@ -1274,17 +1276,33 @@ main(int argc, char * argv[]) buf++; if (*buf) *buf++ = '\0'; - if (0 == strcmp(key,"bpt")) + if (0 == strcmp(key,"bpt")) { clp->bpt = sg_get_num(buf); - else if (0 == strcmp(key,"bs")) + if ((clp->bpt < 0) || (clp->bpt > MAX_BPT_VALUE)) { + pr2serr("%s: bad argument to 'bpt='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"bs")) { clp->bs = sg_get_num(buf); - else if (0 == strcmp(key,"count")) + if ((clp->bs < 0) || (clp->bs > MAX_BPT_VALUE)) { + pr2serr("%s: bad argument to 'bs='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"count")) { count = sg_get_num(buf); - else if (0 == strcmp(key,"deb")) + if (count < 0) { + pr2serr("%s: bad argument to 'count='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"deb")) clp->debug += sg_get_num(buf); - else if (0 == strcmp(key,"ibs")) + else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); - else if (strcmp(key,"if") == 0) { + if ((ibs < 0) || (ibs > MAX_BPT_VALUE)) { + pr2serr("%s: bad argument to 'ibs='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (strcmp(key,"if") == 0) { memcpy(inf, buf, INOUTF_SZ); inf[INOUTF_SZ - 1] = '\0'; } else if (0 == strcmp(key, "iflag")) { @@ -1297,9 +1315,13 @@ main(int argc, char * argv[]) else if (0 == strcmp(key,"no_sig")) { /* default changes */ clp->no_sig = !!sg_get_num(buf); no_sig_given = true; - } else if (0 == strcmp(key,"obs")) + } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); - else if (strcmp(key,"of") == 0) { + if ((obs < 0) || (obs > MAX_BPT_VALUE)) { + pr2serr("%s: bad argument to 'obs='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (strcmp(key,"of") == 0) { memcpy(outf, buf, INOUTF_SZ); outf[INOUTF_SZ - 1] = '\0'; } else if (0 == strcmp(key, "oflag")) { @@ -1311,11 +1333,19 @@ main(int argc, char * argv[]) clp->poll_ms = sg_get_num(buf); else if (0 == strcmp(key,"rt_sig")) clp->use_rt_sig = !!sg_get_num(buf); - else if (0 == strcmp(key,"seek")) + else if (0 == strcmp(key,"seek")) { seek = sg_get_num(buf); - else if (0 == strcmp(key,"skip")) + if (seek < 0) { + pr2serr("%s: bad argument to 'seek='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"skip")) { skip = sg_get_num(buf); - else if (0 == strcmp(key,"time")) + if (skip < 0) { + pr2serr("%s: bad argument to 'skip='\n", my_name); + return SG_LIB_SYNTAX_ERROR; + } + } else if (0 == strcmp(key,"time")) ; /* do nothing */ else if ((0 == strcmp(key,"-V")) || (0 == strcmp(key,"--version"))) { pr2serr("%s: version: %s\n", my_name, version_str);