sg3_utils-1.40/0000755000175000017500000000000012431015530012340 5ustar douggdouggsg3_utils-1.40/Makefile.am0000664000175000017500000000026012144707462014411 0ustar douggdougg SUBDIRS = include \ lib \ src \ doc \ scripts EXTRA_DIST=autogen.sh COVERAGE CREDITS distclean-local: rm -rf autom4te.cache rm -f build-stamp configure-stamp sg3_utils-1.40/lib/0000755000175000017500000000000012431015530013106 5ustar douggdouggsg3_utils-1.40/lib/sg_pt_common.c0000664000175000017500000000062212344371176015756 0ustar douggdougg/* * Copyright (c) 2009-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include "sg_pt.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif static const char * scsi_pt_version_str = "2.12 20140606"; const char * scsi_pt_version() { return scsi_pt_version_str; } sg3_utils-1.40/lib/Makefile.am0000664000175000017500000000234712420601524015154 0ustar douggdougglibsgutils2_la_SOURCES = \ sg_lib.c \ sg_lib_data.c \ sg_cmds_basic.c \ sg_cmds_basic2.c \ sg_cmds_extra.c \ sg_cmds_mmc.c \ sg_pt_common.c if OS_LINUX libsgutils2_la_SOURCES += \ sg_pt_linux.c \ sg_io_linux.c endif if OS_WIN32_MINGW libsgutils2_la_SOURCES += sg_pt_win32.c endif if OS_WIN32_CYGWIN libsgutils2_la_SOURCES += sg_pt_win32.c endif if OS_FREEBSD libsgutils2_la_SOURCES += sg_pt_freebsd.c endif if OS_SOLARIS libsgutils2_la_SOURCES += sg_pt_solaris.c endif if OS_OSF libsgutils2_la_SOURCES += sg_pt_osf1.c endif # For C++/clang testing ## CC = g++ ## CC = g++ ## CC = clang ## CC = clang++ # -std= can be c99, c11, gnu11, etc. Default is gnu89 (gnu90 is the same) # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W -pedantic -std=c11 # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W -pedantic -std=c++11 lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ sg3_utils-1.40/lib/sg_cmds_basic2.c0000664000175000017500000010252212414667052016135 0ustar douggdougg/* * Copyright (c) 1999-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * CONTENTS * Some SCSI commands are executed in many contexts and hence began * to appear in several sg3_utils utilities. This files centralizes * some of the low level command execution code. In most cases the * interpretation of the command response is left to the each * utility. */ #include #include #include #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define EBUFF_SZ 256 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */ #define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */ #define SYNCHRONIZE_CACHE_CMD 0x35 #define SYNCHRONIZE_CACHE_CMDLEN 10 #define SERVICE_ACTION_IN_16_CMD 0x9e #define SERVICE_ACTION_IN_16_CMDLEN 16 #define READ_CAPACITY_16_SA 0x10 #define READ_CAPACITY_10_CMD 0x25 #define READ_CAPACITY_10_CMDLEN 10 #define MODE_SENSE6_CMD 0x1a #define MODE_SENSE6_CMDLEN 6 #define MODE_SENSE10_CMD 0x5a #define MODE_SENSE10_CMDLEN 10 #define MODE_SELECT6_CMD 0x15 #define MODE_SELECT6_CMDLEN 6 #define MODE_SELECT10_CMD 0x55 #define MODE_SELECT10_CMDLEN 10 #define LOG_SENSE_CMD 0x4d #define LOG_SENSE_CMDLEN 10 #define LOG_SELECT_CMD 0x4c #define LOG_SELECT_CMDLEN 10 #define START_STOP_CMD 0x1b #define START_STOP_CMDLEN 6 #define PREVENT_ALLOW_CMD 0x1e #define PREVENT_ALLOW_CMDLEN 6 #define MODE6_RESP_HDR_LEN 4 #define MODE10_RESP_HDR_LEN 8 #define MODE_RESP_ARB_LEN 1024 #define INQUIRY_RESP_INITIAL_LEN 36 /* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_sync_cache_10(int sg_fd, int sync_nv, int immed, int group, unsigned int lba, unsigned int count, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char scCmdBlk[SYNCHRONIZE_CACHE_CMDLEN] = {SYNCHRONIZE_CACHE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (sync_nv) scCmdBlk[1] |= 4; if (immed) scCmdBlk[1] |= 2; scCmdBlk[2] = (lba >> 24) & 0xff; scCmdBlk[3] = (lba >> 16) & 0xff; scCmdBlk[4] = (lba >> 8) & 0xff; scCmdBlk[5] = lba & 0xff; scCmdBlk[6] = group & 0x1f; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (count > 0xffff) { fprintf(sg_warnings_strm, "count too big\n"); return -1; } scCmdBlk[7] = (count >> 8) & 0xff; scCmdBlk[8] = count & 0xff; if (verbose) { fprintf(sg_warnings_strm, " synchronize cache(10) cdb: "); for (k = 0; k < SYNCHRONIZE_CACHE_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", scCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "synchronize cache(10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, scCmdBlk, sizeof(scCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "synchronize cache(10)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_readcap_16(int sg_fd, int pmi, uint64_t llba, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rcCmdBlk[SERVICE_ACTION_IN_16_CMDLEN] = {SERVICE_ACTION_IN_16_CMD, READ_CAPACITY_16_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (pmi) { /* lbs only valid when pmi set */ rcCmdBlk[14] |= 1; rcCmdBlk[2] = (llba >> 56) & 0xff; rcCmdBlk[3] = (llba >> 48) & 0xff; rcCmdBlk[4] = (llba >> 40) & 0xff; rcCmdBlk[5] = (llba >> 32) & 0xff; rcCmdBlk[6] = (llba >> 24) & 0xff; rcCmdBlk[7] = (llba >> 16) & 0xff; rcCmdBlk[8] = (llba >> 8) & 0xff; rcCmdBlk[9] = llba & 0xff; } /* Allocation length, no guidance in SBC-2 rev 15b */ rcCmdBlk[10] = (mx_resp_len >> 24) & 0xff; rcCmdBlk[11] = (mx_resp_len >> 16) & 0xff; rcCmdBlk[12] = (mx_resp_len >> 8) & 0xff; rcCmdBlk[13] = mx_resp_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " read capacity (16) cdb: "); for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rcCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read capacity (16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rcCmdBlk, sizeof(rcCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read capacity (16)", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ CAPACITY (10) command. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rcCmdBlk[READ_CAPACITY_10_CMDLEN] = {READ_CAPACITY_10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (pmi) { /* lbs only valid when pmi set */ rcCmdBlk[8] |= 1; rcCmdBlk[2] = (lba >> 24) & 0xff; rcCmdBlk[3] = (lba >> 16) & 0xff; rcCmdBlk[4] = (lba >> 8) & 0xff; rcCmdBlk[5] = lba & 0xff; } if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " read capacity (10) cdb: "); for (k = 0; k < READ_CAPACITY_10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rcCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read capacity (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rcCmdBlk, sizeof(rcCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read capacity (10)", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char modesCmdBlk[MODE_SENSE6_CMDLEN] = {MODE_SENSE6_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; modesCmdBlk[1] = (unsigned char)(dbd ? 0x8 : 0); modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff); modesCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (mx_resp_len > 0xff) { fprintf(sg_warnings_strm, "mx_resp_len too big\n"); return -1; } if (verbose) { fprintf(sg_warnings_strm, " mode sense (6) cdb: "); for (k = 0; k < MODE_SENSE6_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", modesCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "mode sense (6): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "mode sense (6)", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " mode sense (6): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } if (resid > 0) { if (resid > mx_resp_len) { fprintf(sg_warnings_strm, "mode sense(6): resid (%d) should " "never exceed requested len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char modesCmdBlk[MODE_SENSE10_CMDLEN] = {MODE_SENSE10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; modesCmdBlk[1] = (unsigned char)((dbd ? 0x8 : 0) | (llbaa ? 0x10 : 0)); modesCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); modesCmdBlk[3] = (unsigned char)(sub_pg_code & 0xff); modesCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); modesCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (mx_resp_len > 0xffff) { fprintf(sg_warnings_strm, "mx_resp_len too big\n"); return -1; } if (verbose) { fprintf(sg_warnings_strm, " mode sense (10) cdb: "); for (k = 0; k < MODE_SENSE10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", modesCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "mode sense (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "mode sense (10)", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " mode sense (10): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } if (resid > 0) { if (resid > mx_resp_len) { fprintf(sg_warnings_strm, "mode sense(10): resid (%d) should " "never exceed requested len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } /* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp, int param_len, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char modesCmdBlk[MODE_SELECT6_CMDLEN] = {MODE_SELECT6_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; modesCmdBlk[1] = (unsigned char)(((pf << 4) & 0x10) | (sp & 0x1)); modesCmdBlk[4] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (param_len > 0xff) { fprintf(sg_warnings_strm, "mode select (6): param_len too big\n"); return -1; } if (verbose) { fprintf(sg_warnings_strm, " mode select (6) cdb: "); for (k = 0; k < MODE_SELECT6_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", modesCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if (verbose > 1) { fprintf(sg_warnings_strm, " mode select (6) parameter list\n"); dStrHexErr((const char *)paramp, param_len, -1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "mode select (6): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "mode select (6)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp, int param_len, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char modesCmdBlk[MODE_SELECT10_CMDLEN] = {MODE_SELECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; modesCmdBlk[1] = (unsigned char)(((pf << 4) & 0x10) | (sp & 0x1)); modesCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); modesCmdBlk[8] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (param_len > 0xffff) { fprintf(sg_warnings_strm, "mode select (10): param_len too big\n"); return -1; } if (verbose) { fprintf(sg_warnings_strm, " mode select (10) cdb: "); for (k = 0; k < MODE_SELECT10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", modesCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if (verbose > 1) { fprintf(sg_warnings_strm, " mode select (10) parameter list\n"); dStrHexErr((const char *)paramp, param_len, -1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "mode select (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, modesCmdBlk, sizeof(modesCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "mode select (10)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* MODE SENSE commands yield a response that has block descriptors followed * by mode pages. In most cases users are interested in the first mode page. * This function returns the (byte) offset of the start of the first mode * page. Set mode_sense_6 to 1 for MODE SENSE (6) and 0 for MODE SENSE (10). * Returns >= 0 is successful or -1 if failure. If there is a failure * a message is written to err_buff. */ int sg_mode_page_offset(const unsigned char * resp, int resp_len, int mode_sense_6, char * err_buff, int err_buff_len) { int bd_len; int calc_len; int offset; if ((NULL == resp) || (resp_len < 4) || ((! mode_sense_6) && (resp_len < 8))) { if (err_buff_len > 0) snprintf(err_buff, err_buff_len, "given response length too " "short: %d\n", resp_len); return -1; } if (mode_sense_6) { calc_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + MODE6_RESP_HDR_LEN; } else { calc_len = (resp[0] << 8) + resp[1] + 2; bd_len = (resp[6] << 8) + resp[7]; /* LongLBA doesn't change this calculation */ offset = bd_len + MODE10_RESP_HDR_LEN; } if ((offset + 2) > resp_len) { if (err_buff_len > 0) snprintf(err_buff, err_buff_len, "given response length " "too small, offset=%d given_len=%d bd_len=%d\n", offset, resp_len, bd_len); offset = -1; } else if ((offset + 2) > calc_len) { if (err_buff_len > 0) snprintf(err_buff, err_buff_len, "calculated response " "length too small, offset=%d calc_len=%d bd_len=%d\n", offset, calc_len, bd_len); offset = -1; } return offset; } /* Fetches current, changeable, default and/or saveable modes pages as * indicated by pcontrol_arr for given pg_code and sub_pg_code. If * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If * flexible set and mode data length seems wrong then try and * fix (compensating hack for bad device or driver). pcontrol_arr * should have 4 elements for output of current, changeable, default * and saved values respectively. Each element should be NULL or * at least mx_mpage_len bytes long. * Return of 0 -> overall success, various SG_LIB_CAT_* positive values or * -1 -> other errors. * If success_mask pointer is not NULL then first zeros it. Then set bits * 0, 1, 2 and/or 3 if the current, changeable, default and saved values * respectively have been fetched. If error on current page * then stops and returns that error; otherwise continues if an error is * detected but returns the first error encountered. */ int sg_get_mode_page_controls(int sg_fd, int mode6, int pg_code, int sub_pg_code, int dbd, int flexible, int mx_mpage_len, int * success_mask, void * pcontrol_arr[], int * reported_len, int verbose) { int k, n, res, offset, calc_len, xfer_len, resp_mode6; unsigned char buff[MODE_RESP_ARB_LEN]; char ebuff[EBUFF_SZ]; int first_err = 0; if (success_mask) *success_mask = 0; if (reported_len) *reported_len = 0; if (mx_mpage_len < 4) return 0; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; memset(ebuff, 0, sizeof(ebuff)); /* first try to find length of current page response */ memset(buff, 0, MODE10_RESP_HDR_LEN); if (mode6) /* want first 8 bytes just in case */ res = sg_ll_mode_sense6(sg_fd, dbd, 0 /* pc */, pg_code, sub_pg_code, buff, MODE10_RESP_HDR_LEN, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, 0 /* pc */, pg_code, sub_pg_code, buff, MODE10_RESP_HDR_LEN, 1, verbose); if (0 != res) return res; n = buff[0]; if (reported_len) *reported_len = mode6 ? (n + 1) : ((n << 8) + buff[1] + 2); resp_mode6 = mode6; if (flexible) { if (mode6 && (n < 3)) { resp_mode6 = 0; if (verbose) fprintf(sg_warnings_strm, ">>> msense(6) but resp[0]=%d so " "try msense(10) response processing\n", n); } if ((0 == mode6) && (n > 5)) { if ((n > 11) && (0 == (n % 2)) && (0 == buff[4]) && (0 == buff[5]) && (0 == buff[6])) { buff[1] = n; buff[0] = 0; if (verbose) fprintf(sg_warnings_strm, ">>> msense(10) but resp[0]=%d " "and not msense(6) response so fix length\n", n); } else resp_mode6 = 1; } } if (verbose && (resp_mode6 != mode6)) fprintf(sg_warnings_strm, ">>> msense(%d) but resp[0]=%d " "so switch response processing\n", (mode6 ? 6 : 10), buff[0]); calc_len = resp_mode6 ? (buff[0] + 1) : ((buff[0] << 8) + buff[1] + 2); if (calc_len > MODE_RESP_ARB_LEN) calc_len = MODE_RESP_ARB_LEN; offset = sg_mode_page_offset(buff, calc_len, resp_mode6, ebuff, EBUFF_SZ); if (offset < 0) { if (('\0' != ebuff[0]) && (verbose > 0)) fprintf(sg_warnings_strm, "sg_get_mode_page_controls: %s\n", ebuff); return SG_LIB_CAT_MALFORMED; } xfer_len = calc_len - offset; if (xfer_len > mx_mpage_len) xfer_len = mx_mpage_len; for (k = 0; k < 4; ++k) { if (NULL == pcontrol_arr[k]) continue; memset(pcontrol_arr[k], 0, mx_mpage_len); if (mode6) res = sg_ll_mode_sense6(sg_fd, dbd, k /* pc */, pg_code, sub_pg_code, buff, calc_len, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, k /* pc */, pg_code, sub_pg_code, buff, calc_len, 1, verbose); if (0 != res) { if (0 == first_err) first_err = res; if (0 == k) break; /* if problem on current page, it won't improve */ else continue; } if (xfer_len > 0) memcpy(pcontrol_arr[k], buff + offset, xfer_len); if (success_mask) *success_mask |= (1 << k); } return first_err; } /* Invokes a SCSI LOG SENSE command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code, int subpg_code, int paramp, unsigned char * resp, int mx_resp_len, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char logsCmdBlk[LOG_SENSE_CMDLEN] = {LOG_SENSE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (mx_resp_len > 0xffff) { fprintf(sg_warnings_strm, "mx_resp_len too big\n"); return -1; } logsCmdBlk[1] = (unsigned char)((ppc ? 2 : 0) | (sp ? 1 : 0)); logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); logsCmdBlk[3] = (unsigned char)(subpg_code & 0xff); logsCmdBlk[5] = (unsigned char)((paramp >> 8) & 0xff); logsCmdBlk[6] = (unsigned char)(paramp & 0xff); logsCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); logsCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { fprintf(sg_warnings_strm, " log sense cdb: "); for (k = 0; k < LOG_SENSE_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", logsCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "log sense: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, logsCmdBlk, sizeof(logsCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "log sense", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((mx_resp_len > 3) && (ret < 4)) { /* resid indicates LOG SENSE response length bad, so zero it */ resp[2] = 0; resp[3] = 0; } ret = 0; } if (resid > 0) { if (resid > mx_resp_len) { fprintf(sg_warnings_strm, "log sense: resid (%d) should " "never exceed requested len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } /* Invokes a SCSI LOG SELECT command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc, int pg_code, int subpg_code, unsigned char * paramp, int param_len, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char logsCmdBlk[LOG_SELECT_CMDLEN] = {LOG_SELECT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (param_len > 0xffff) { fprintf(sg_warnings_strm, "log select: param_len too big\n"); return -1; } logsCmdBlk[1] = (unsigned char)((pcr ? 2 : 0) | (sp ? 1 : 0)); logsCmdBlk[2] = (unsigned char)(((pc << 6) & 0xc0) | (pg_code & 0x3f)); logsCmdBlk[3] = (unsigned char)(subpg_code & 0xff); logsCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); logsCmdBlk[8] = (unsigned char)(param_len & 0xff); if (verbose) { fprintf(sg_warnings_strm, " log select cdb: "); for (k = 0; k < LOG_SELECT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", logsCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if ((verbose > 1) && (param_len > 0)) { fprintf(sg_warnings_strm, " log select parameter list\n"); dStrHexErr((const char *)paramp, param_len, -1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "log select: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, logsCmdBlk, sizeof(logsCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "log select", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI START STOP UNIT command (SBC + MMC). * Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors. * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and * format_layer_number(mmc) fields. They also overlap on the noflush(sbc) * and fl(mmc) one bit field. This is the cause of the awkardly named * pc_mod__fl_num and noflush__fl arguments to this function. * */ int sg_ll_start_stop_unit(int sg_fd, int immed, int pc_mod__fl_num, int power_cond, int noflush__fl, int loej, int start, int noisy, int verbose) { unsigned char ssuBlk[START_STOP_CMDLEN] = {START_STOP_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; int k, res, ret, sense_cat; struct sg_pt_base * ptvp; ssuBlk[1] = immed & 1; ssuBlk[3] = pc_mod__fl_num & 0xf; /* bits 2 and 3 are reserved in MMC */ ssuBlk[4] = ((power_cond & 0xf) << 4) | (noflush__fl ? 0x4 : 0) | (loej ? 0x2 : 0) | (start ? 0x1 : 0); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Start stop unit command:"); for (k = 0; k < (int)sizeof(ssuBlk); ++k) fprintf (sg_warnings_strm, " %02x", ssuBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "start stop unit: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, ssuBlk, sizeof(ssuBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, START_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "start stop unit", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command * [was in SPC-3 but displaced from SPC-4 into SBC-3, MMC-5, SSC-3] * prevent==0 allows removal, prevent==1 prevents removal ... * Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char pCmdBlk[PREVENT_ALLOW_CMDLEN] = {PREVENT_ALLOW_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if ((prevent < 0) || (prevent > 3)) { fprintf(sg_warnings_strm, "prevent argument should be 0, 1, 2 or 3\n"); return -1; } pCmdBlk[4] |= (prevent & 0x3); if (verbose) { fprintf(sg_warnings_strm, " Prevent allow medium removal cdb: "); for (k = 0; k < PREVENT_ALLOW_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", pCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "prevent allow medium removal: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, pCmdBlk, sizeof(pCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "prevent allow medium removal", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.40/lib/Makefile.in0000664000175000017500000005407612420601524015173 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @OS_LINUX_TRUE@am__append_1 = \ @OS_LINUX_TRUE@ sg_pt_linux.c \ @OS_LINUX_TRUE@ sg_io_linux.c @OS_WIN32_MINGW_TRUE@am__append_2 = sg_pt_win32.c @OS_WIN32_CYGWIN_TRUE@am__append_3 = sg_pt_win32.c @OS_FREEBSD_TRUE@am__append_4 = sg_pt_freebsd.c @OS_SOLARIS_TRUE@am__append_5 = sg_pt_solaris.c @OS_OSF_TRUE@am__append_6 = sg_pt_osf1.c subdir = lib DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(libdir)" LTLIBRARIES = $(lib_LTLIBRARIES) am__libsgutils2_la_SOURCES_DIST = sg_lib.c sg_lib_data.c \ sg_cmds_basic.c sg_cmds_basic2.c sg_cmds_extra.c sg_cmds_mmc.c \ sg_pt_common.c sg_pt_linux.c sg_io_linux.c sg_pt_win32.c \ sg_pt_freebsd.c sg_pt_solaris.c sg_pt_osf1.c @OS_LINUX_TRUE@am__objects_1 = sg_pt_linux.lo sg_io_linux.lo @OS_WIN32_MINGW_TRUE@am__objects_2 = sg_pt_win32.lo @OS_WIN32_CYGWIN_TRUE@am__objects_3 = sg_pt_win32.lo @OS_FREEBSD_TRUE@am__objects_4 = sg_pt_freebsd.lo @OS_SOLARIS_TRUE@am__objects_5 = sg_pt_solaris.lo @OS_OSF_TRUE@am__objects_6 = sg_pt_osf1.lo am_libsgutils2_la_OBJECTS = sg_lib.lo sg_lib_data.lo sg_cmds_basic.lo \ sg_cmds_basic2.lo sg_cmds_extra.lo sg_cmds_mmc.lo \ sg_pt_common.lo $(am__objects_1) $(am__objects_2) \ $(am__objects_3) $(am__objects_4) $(am__objects_5) \ $(am__objects_6) libsgutils2_la_OBJECTS = $(am_libsgutils2_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = libsgutils2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(libsgutils2_la_LDFLAGS) $(LDFLAGS) -o \ $@ AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(libsgutils2_la_SOURCES) DIST_SOURCES = $(am__libsgutils2_la_SOURCES_DIST) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ libsgutils2_la_SOURCES = sg_lib.c sg_lib_data.c sg_cmds_basic.c \ sg_cmds_basic2.c sg_cmds_extra.c sg_cmds_mmc.c sg_pt_common.c \ $(am__append_1) $(am__append_2) $(am__append_3) \ $(am__append_4) $(am__append_5) $(am__append_6) # For C++/clang testing # -std= can be c99, c11, gnu11, etc. Default is gnu89 (gnu90 is the same) # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W -pedantic -std=c11 # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W -pedantic -std=c++11 lib_LTLIBRARIES = libsgutils2.la libsgutils2_la_LDFLAGS = -version-info 2:0:0 libsgutils2_la_LIBADD = @GETOPT_O_FILES@ @os_libs@ libsgutils2_la_DEPENDENCIES = @GETOPT_O_FILES@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; \ locs=`for p in $$list; do echo $$p; done | \ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ sort -u`; \ test -z "$$locs" || { \ echo rm -f $${locs}; \ rm -f $${locs}; \ } libsgutils2.la: $(libsgutils2_la_OBJECTS) $(libsgutils2_la_DEPENDENCIES) $(EXTRA_libsgutils2_la_DEPENDENCIES) $(AM_V_CCLD)$(libsgutils2_la_LINK) -rpath $(libdir) $(libsgutils2_la_OBJECTS) $(libsgutils2_la_LIBADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_basic.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_basic2.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_extra.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_cmds_mmc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_io_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_lib.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_lib_data.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_common.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_freebsd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_linux.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_osf1.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_solaris.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_pt_win32.Plo@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(LTLIBRARIES) installdirs: for dir in "$(DESTDIR)$(libdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-libLTLIBRARIES install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-libLTLIBRARIES .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libLTLIBRARIES clean-libtool cscopelist-am ctags \ ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-tags distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-libLTLIBRARIES install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/lib/sg_pt_solaris.c0000664000175000017500000002146511351460102016133 0ustar douggdougg/* * Copyright (c) 2007-2010 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* sg_pt_solaris version 1.03 20100321 */ #include #include #include #include #include #include #include #include /* Solaris headers */ #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #define DEF_TIMEOUT 60 /* 60 seconds */ struct sg_pt_solaris_scsi { struct uscsi_cmd uscsi; int max_sense_len; int in_err; int os_err; }; struct sg_pt_base { struct sg_pt_solaris_scsi impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. The 'flags' argument is ignored in Solaris. * Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int flags_arg, int verbose) { int oflags = O_NONBLOCK | O_RDWR; int fd; flags_arg = flags_arg; /* ignore flags argument, suppress warning */ if (verbose > 1) { fprintf(stderr, "open %s with flags=0x%x\n", device_name, oflags); } fd = open(device_name, oflags); if (fd < 0) fd = -errno; return fd; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { int res; res = close(device_fd); if (res < 0) res = -errno; return res; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_solaris_scsi * ptp; ptp = (struct sg_pt_solaris_scsi *) calloc(1, sizeof(struct sg_pt_solaris_scsi)); if (ptp) { ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; } return (struct sg_pt_base *)ptp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_solaris_scsi)); ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; ptp->uscsi.uscsi_timeout = DEF_TIMEOUT; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp->uscsi.uscsi_cdb) ++ptp->in_err; ptp->uscsi.uscsi_cdb = (char *)cdb; ptp->uscsi.uscsi_cdblen = cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp->uscsi.uscsi_rqbuf) ++ptp->in_err; memset(sense, 0, max_sense_len); ptp->uscsi.uscsi_rqbuf = (char *)sense; ptp->uscsi.uscsi_rqlen = max_sense_len; ptp->max_sense_len = max_sense_len; } /* from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp->uscsi.uscsi_bufaddr) ++ptp->in_err; if (dxfer_len > 0) { ptp->uscsi.uscsi_bufaddr = (char *)dxferp; ptp->uscsi.uscsi_buflen = dxfer_len; ptp->uscsi.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_RQENABLE; } } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_solaris_scsi * ptp = &vp->impl; if (ptp->uscsi.uscsi_bufaddr) ++ptp->in_err; if (dxfer_len > 0) { ptp->uscsi.uscsi_bufaddr = (char *)dxferp; ptp->uscsi.uscsi_buflen = dxfer_len; ptp->uscsi.uscsi_flags = USCSI_WRITE | USCSI_ISOLATE | USCSI_RQENABLE; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { // struct sg_pt_solaris_scsi * ptp = &vp->impl; vp = vp; /* ignore and suppress warning */ pack_id = pack_id; /* ignore and suppress warning */ } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { // struct sg_pt_solaris_scsi * ptp = &vp->impl; vp = vp; /* ignore and suppress warning */ tag = tag; /* ignore and suppress warning */ } /* Note that task management function codes are transport specific */ void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_solaris_scsi * ptp = &vp->impl; ++ptp->in_err; tmf_code = tmf_code; /* dummy to silence compiler */ } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_solaris_scsi * ptp = &vp->impl; ++ptp->in_err; attribute = attribute; /* dummy to silence compiler */ priority = priority; /* dummy to silence compiler */ } void set_scsi_pt_flags(struct sg_pt_base * objp, int flags) { /* do nothing, suppress warnings */ objp = objp; flags = flags; } /* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_solaris_scsi * ptp = &vp->impl; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(stderr, "Replicated or unused set_scsi_pt... " "functions\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->uscsi.uscsi_cdb) { if (verbose) fprintf(stderr, "No SCSI command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } if (time_secs > 0) ptp->uscsi.uscsi_timeout = time_secs; if (ioctl(fd, USCSICMD, &ptp->uscsi)) { ptp->os_err = errno; if ((EIO == ptp->os_err) && ptp->uscsi.uscsi_status) { ptp->os_err = 0; return 0; } if (verbose) fprintf(stderr, "ioctl(USCSICMD) failed with os_err " "(errno) = %d\n", ptp->os_err); return -ptp->os_err; } return 0; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; int scsi_st = ptp->uscsi.uscsi_status; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if ((SAM_STAT_CHECK_CONDITION == scsi_st) || (SAM_STAT_COMMAND_TERMINATED == scsi_st)) return SCSI_PT_RESULT_SENSE; else if (scsi_st) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp->uscsi.uscsi_resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp->uscsi.uscsi_status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; int res; if (ptp->max_sense_len > 0) { res = ptp->max_sense_len - ptp->uscsi.uscsi_rqresid; return (res > 0) ? res : 0; } return 0; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { // const struct sg_pt_solaris_scsi * ptp = &vp->impl; vp = vp; /* ignore and suppress warning */ return -1; /* not available */ } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { // const struct sg_pt_solaris_scsi * ptp = &vp->impl; vp = vp; /* ignore and suppress warning */ return 0; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; return ptp->os_err; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { // const struct sg_pt_solaris_scsi * ptp = &vp->impl; vp = vp; /* ignore and suppress warning */ if (max_b_len > 0) b[0] = '\0'; return b; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_solaris_scsi * ptp = &vp->impl; const char * cp; cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } sg3_utils-1.40/lib/sg_lib.c0000664000175000017500000022133712400160337014525 0ustar douggdougg/* * Copyright (c) 1999-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* NOTICE: * On 5th October 2004 (v1.00) this file name was changed from sg_err.c * to sg_lib.c and the previous GPL was changed to a FreeBSD license. * The intention is to maintain this file and the related sg_lib.h file * as open source and encourage their unencumbered use. * * CONTRIBUTIONS: * This file started out as a copy of SCSI opcodes, sense keys and * additional sense codes (ASC/ASCQ) kept in the Linux SCSI subsystem * in the kernel source file: drivers/scsi/constant.c . That file * bore this notice: "Copyright (C) 1993, 1994, 1995 Eric Youngdale" * and a GPL notice. * * Much of the data in this file is derived from SCSI draft standards * found at http://www.t10.org with the "SCSI Primary Commands-4" (SPC-4) * being the central point of reference. * * Contributions: * sense key specific field decoding [Trent Piepho 20031116] * */ #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include "sg_lib.h" #include "sg_lib_data.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif /* sg_lib_version_str (and datestamp) defined in sg_lib_data.c file */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d /* corresponding ASC is 0 */ /* The following two opcodes were renamed to 'Third party copy out/in' in * spc4r34 */ #define SG_THIRD_PARTY_COPY_OUT SG_EXTENDED_COPY #define SG_THIRD_PARTY_COPY_IN SG_RECEIVE_COPY FILE * sg_warnings_strm = NULL; /* would like to default to stderr */ #ifdef __GNUC__ static int my_snprintf(char * cp, int cp_max_len, const char * fmt, ...) __attribute__ ((format (printf, 3, 4))); #else static int my_snprintf(char * cp, int cp_max_len, const char * fmt, ...); #endif /* Want safe, 'n += snprintf(b + n, blen - n, ...)' style sequence of * functions. Returns number number of chars placed in cp excluding the * trailing null char. So for cp_max_len > 0 the return value is always * < cp_max_len; for cp_max_len <= 1 the return value is 0 and no chars * are written to cp. Note this means that when cp_max_len = 1, this * function assumes that cp[0] is the null character and does nothing * (and returns 0). */ static int my_snprintf(char * cp, int cp_max_len, const char * fmt, ...) { va_list args; int n; if (cp_max_len < 2) return 0; va_start(args, fmt); n = vsnprintf(cp, cp_max_len, fmt, args); va_end(args); return (n < cp_max_len) ? n : (cp_max_len - 1); } /* Searches 'arr' for match on 'value' then 'peri_type'. If matches 'value' but not 'peri_type' then yields first 'value' match entry. Last element of 'arr' has NULL 'name'. If no match returns NULL. */ static const struct sg_lib_value_name_t * get_value_name(const struct sg_lib_value_name_t * arr, int value, int peri_type) { const struct sg_lib_value_name_t * vp = arr; const struct sg_lib_value_name_t * holdp; for (; vp->name; ++vp) { if (value == vp->value) { if (peri_type == vp->peri_dev_type) return vp; holdp = vp; while ((vp + 1)->name && (value == (vp + 1)->value)) { ++vp; if (peri_type == vp->peri_dev_type) return vp; } return holdp; } } return NULL; } void sg_set_warnings_strm(FILE * warnings_strm) { sg_warnings_strm = warnings_strm; } #define CMD_NAME_LEN 128 void sg_print_command(const unsigned char * command) { int k, sz; char buff[CMD_NAME_LEN]; sg_get_command_name(command, 0, CMD_NAME_LEN, buff); buff[CMD_NAME_LEN - 1] = '\0'; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "%s [", buff); if (SG_VARIABLE_LENGTH_CMD == command[0]) sz = command[7] + 8; else sz = sg_get_command_size(command[0]); for (k = 0; k < sz; ++k) fprintf(sg_warnings_strm, "%02x ", command[k]); fprintf(sg_warnings_strm, "]\n"); } void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff) { const char * ccp = NULL; int unknown = 0; if ((NULL == buff) || (buff_len < 1)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } scsi_status &= 0x7e; /* sanitize as much as possible */ switch (scsi_status) { case 0: ccp = "Good"; break; case 0x2: ccp = "Check Condition"; break; case 0x4: ccp = "Condition Met"; break; case 0x8: ccp = "Busy"; break; case 0x10: ccp = "Intermediate (obsolete)"; break; case 0x14: ccp = "Intermediate-Condition Met (obsolete)"; break; case 0x18: ccp = "Reservation Conflict"; break; case 0x22: ccp = "Command Terminated (obsolete)"; break; case 0x28: ccp = "Task set Full"; break; case 0x30: ccp = "ACA Active"; break; case 0x40: ccp = "Task Aborted"; break; default: unknown = 1; break; } if (unknown) my_snprintf(buff, buff_len, "Unknown status [0x%x]", scsi_status); else my_snprintf(buff, buff_len, "%s", ccp); } void sg_print_scsi_status(int scsi_status) { char buff[128]; sg_get_scsi_status_str(scsi_status, sizeof(buff) - 1, buff); buff[sizeof(buff) - 1] = '\0'; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "%s ", buff); } /* Get sense key from sense buffer. If successful returns a sense key value * between 0 and 15. If sense buffer cannot be decode, returns -1 . */ int sg_get_sense_key(const unsigned char * sensep, int sense_len) { if ((NULL == sensep) || (sense_len < 2)) return -1; switch (sensep[0] & 0x7f) { case 0x70: case 0x71: return (sense_len < 3) ? -1 : (sensep[2] & 0xf); case 0x72: case 0x73: return sensep[1] & 0xf; default: return -1; } } /* Yield string associated with sense_key value. Returns 'buff'. */ char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff) { if (1 == buff_len) { buff[0] = '\0'; return buff; } if ((sense_key >= 0) && (sense_key < 16)) my_snprintf(buff, buff_len, "%s", sg_lib_sense_key_desc[sense_key]); else my_snprintf(buff, buff_len, "invalid value: 0x%x", sense_key); return buff; } /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */ char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff) { int k, num, rlen; int found = 0; struct sg_lib_asc_ascq_t * eip; struct sg_lib_asc_ascq_range_t * ei2p; if (1 == buff_len) { buff[0] = '\0'; return buff; } for (k = 0; sg_lib_asc_ascq_range[k].text; ++k) { ei2p = &sg_lib_asc_ascq_range[k]; if ((ei2p->asc == asc) && (ascq >= ei2p->ascq_min) && (ascq <= ei2p->ascq_max)) { found = 1; num = my_snprintf(buff, buff_len, "Additional sense: "); rlen = buff_len - num; num += my_snprintf(buff + num, ((rlen > 0) ? rlen : 0), ei2p->text, ascq); } } if (found) return buff; for (k = 0; sg_lib_asc_ascq[k].text; ++k) { eip = &sg_lib_asc_ascq[k]; if (eip->asc == asc && eip->ascq == ascq) { found = 1; my_snprintf(buff, buff_len, "Additional sense: %s", eip->text); } } if (! found) { if (asc >= 0x80) my_snprintf(buff, buff_len, "vendor specific ASC=%02x, " "ASCQ=%02x (hex)", asc, ascq); else if (ascq >= 0x80) my_snprintf(buff, buff_len, "ASC=%02x, vendor specific " "qualification ASCQ=%02x (hex)", asc, ascq); else my_snprintf(buff, buff_len, "ASC=%02x, ASCQ=%02x (hex)", asc, ascq); } return buff; } /* Attempt to find the first SCSI sense data descriptor that matches the * given 'desc_type'. If found return pointer to start of sense data * descriptor; otherwise (including fixed format sense data) returns NULL. */ const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, int desc_type) { int add_sb_len, add_d_len, desc_len, k; const unsigned char * descp; if ((sense_len < 8) || (0 == (add_sb_len = sensep[7]))) return NULL; if ((sensep[0] < 0x72) || (sensep[0] > 0x73)) return NULL; add_sb_len = (add_sb_len < (sense_len - 8)) ? add_sb_len : (sense_len - 8); descp = &sensep[8]; for (desc_len = 0, k = 0; k < add_sb_len; k += desc_len) { descp += desc_len; add_d_len = (k < (add_sb_len - 1)) ? descp[1]: -1; desc_len = add_d_len + 2; if (descp[0] == desc_type) return descp; if (add_d_len < 0) /* short descriptor ?? */ break; } return NULL; } /* Returns 1 if valid bit set, 0 if valid bit clear. Irrespective the * information field is written out via 'info_outp' (except when it is * NULL). Handles both fixed and descriptor sense formats. */ int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len, uint64_t * info_outp) { int j; const unsigned char * ucp; uint64_t ull; if (info_outp) *info_outp = 0; if (sb_len < 7) return 0; switch (sensep[0] & 0x7f) { case 0x70: case 0x71: if (info_outp) *info_outp = ((unsigned int)sensep[3] << 24) + (sensep[4] << 16) + (sensep[5] << 8) + sensep[6]; return (sensep[0] & 0x80) ? 1 : 0; case 0x72: case 0x73: ucp = sg_scsi_sense_desc_find(sensep, sb_len, 0 /* info desc */); if (ucp && (0xa == ucp[1])) { ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[4 + j]; } if (info_outp) *info_outp = ull; return !!(ucp[2] & 0x80); /* since spc3r23 should be set */ } else return 0; default: return 0; } } /* Returns 1 if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set. * In descriptor format if the stream commands descriptor not found * then returns 0. Writes 1 or 0 corresponding to these bits to the * last three arguments if they are non-NULL. */ int sg_get_sense_filemark_eom_ili(const unsigned char * sensep, int sb_len, int * filemark_p, int * eom_p, int * ili_p) { const unsigned char * ucp; if (sb_len < 7) return 0; switch (sensep[0] & 0x7f) { case 0x70: case 0x71: if (sensep[2] & 0xe0) { if (filemark_p) *filemark_p = !!(sensep[2] & 0x80); if (eom_p) *eom_p = !!(sensep[2] & 0x40); if (ili_p) *ili_p = !!(sensep[2] & 0x20); return 1; } else return 0; case 0x72: case 0x73: /* Look for stream commands sense data descriptor */ ucp = sg_scsi_sense_desc_find(sensep, sb_len, 4); if (ucp && (ucp[1] >= 2)) { if (ucp[3] & 0xe0) { if (filemark_p) *filemark_p = !!(ucp[3] & 0x80); if (eom_p) *eom_p = !!(ucp[3] & 0x40); if (ili_p) *ili_p = !!(ucp[3] & 0x20); return 1; } } return 0; default: return 0; } } /* Returns 1 if SKSV is set and sense key is NO_SENSE or NOT_READY. Also * returns 1 if progress indication sense data descriptor found. Places * progress field from sense data where progress_outp points. If progress * field is not available returns 0 and *progress_outp is unaltered. Handles * both fixed and descriptor sense formats. * Hint: if 1 is returned *progress_outp may be multiplied by 100 then * divided by 65536 to get the percentage completion. */ int sg_get_sense_progress_fld(const unsigned char * sensep, int sb_len, int * progress_outp) { const unsigned char * ucp; int sk, sk_pr; if (sb_len < 7) return 0; switch (sensep[0] & 0x7f) { case 0x70: case 0x71: sk = (sensep[2] & 0xf); if ((sb_len < 18) || ((SPC_SK_NO_SENSE != sk) && (SPC_SK_NOT_READY != sk))) return 0; if (sensep[15] & 0x80) { /* SKSV bit set */ if (progress_outp) *progress_outp = (sensep[16] << 8) + sensep[17]; return 1; } else return 0; case 0x72: case 0x73: /* sense key specific progress (0x2) or progress descriptor (0xa) */ sk = (sensep[1] & 0xf); sk_pr = (SPC_SK_NO_SENSE == sk) || (SPC_SK_NOT_READY == sk); if (sk_pr && ((ucp = sg_scsi_sense_desc_find(sensep, sb_len, 2))) && (0x6 == ucp[1]) && (0x80 & ucp[4])) { if (progress_outp) *progress_outp = (ucp[5] << 8) + ucp[6]; return 1; } else if (((ucp = sg_scsi_sense_desc_find(sensep, sb_len, 0xa))) && ((0x6 == ucp[1]))) { if (progress_outp) *progress_outp = (ucp[6] << 8) + ucp[7]; return 1; } else return 0; default: return 0; } } char * sg_get_pdt_str(int pdt, int buff_len, char * buff) { if ((pdt < 0) || (pdt > 31)) my_snprintf(buff, buff_len, "bad pdt"); else my_snprintf(buff, buff_len, "%s", sg_lib_pdt_strs[pdt]); return buff; } char * sg_get_trans_proto_str(int tpi, int buff_len, char * buff) { if ((tpi < 0) || (tpi > 15)) my_snprintf(buff, buff_len, "bad tpi"); else my_snprintf(buff, buff_len, "%s", sg_lib_transport_proto_strs[tpi]); return buff; } #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_OFFLINE 0xe #define TPGS_STATE_TRANSITIONING 0xf static int decode_tpgs_state(int st, char * b, int blen) { switch (st) { case TPGS_STATE_OPTIMIZED: return my_snprintf(b, blen, "active/optimized"); case TPGS_STATE_NONOPTIMIZED: return my_snprintf(b, blen, "active/non optimized"); case TPGS_STATE_STANDBY: return my_snprintf(b, blen, "standby"); case TPGS_STATE_UNAVAILABLE: return my_snprintf(b, blen, "unavailable"); case TPGS_STATE_OFFLINE: return my_snprintf(b, blen, "offline"); case TPGS_STATE_TRANSITIONING: return my_snprintf(b, blen, "transitioning between states"); default: return my_snprintf(b, blen, "unknown: 0x%x", st); } } static int uds_referral_descriptor_str(char * b, int blen, const unsigned char * dp, int alen) { int n = 0; int dlen = alen - 2; int k, j, g, f, tpgd; const unsigned char * tp; uint64_t ull; char c[40]; n += my_snprintf(b + n, blen - n, " Not all referrals: %d\n", !!(dp[2] & 0x1)); dp += 4; for (k = 0, f = 1; (k + 4) < dlen; k += g, dp += g, ++f) { tpgd = dp[3]; g = (tpgd * 4) + 20; n += my_snprintf(b + n, blen - n, " Descriptor %d\n", f); if ((k + g) > dlen) { n += my_snprintf(b + n, blen - n, " truncated descriptor, " "stop\n"); return n; } ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= dp[4 + j]; } n += my_snprintf(b + n, blen - n, " first uds LBA: 0x%" PRIx64 "\n", ull); ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= dp[12 + j]; } n += my_snprintf(b + n, blen - n, " last uds LBA: 0x%" PRIx64 "\n", ull); for (j = 0; j < tpgd; ++j) { tp = dp + 20 + (j * 4); decode_tpgs_state(tp[0] & 0xf, c, sizeof(c)); n += my_snprintf(b + n, blen - n, " tpg: %d state: %s\n", (tp[2] << 8) + tp[3], c); } } return n; } static const char * sdata_src[] = { "unknown", "Extended Copy command source device", "Extended Copy command destination device", }; /* Decode descriptor format sense descriptors (assumes sense buffer is * in descriptor format) */ static void sg_get_sense_descriptors_str(const unsigned char * sense_buffer, int sb_len, int blen, char * b) { int add_sb_len, add_d_len, desc_len, k, j, sense_key, processed; int n, progress, pr, rem; const unsigned char * descp; const char * dtsp = " >> descriptor too short"; if ((NULL == b) || (blen <= 0)) return; b[0] = '\0'; if ((sb_len < 8) || (0 == (add_sb_len = sense_buffer[7]))) return; add_sb_len = (add_sb_len < (sb_len - 8)) ? add_sb_len : (sb_len - 8); sense_key = (sense_buffer[1] & 0xf); for (descp = (sense_buffer + 8), k = 0, n = 0; (k < add_sb_len) && (n < blen); k += desc_len, descp += desc_len) { add_d_len = (k < (add_sb_len - 1)) ? descp[1] : -1; if ((k + add_d_len + 2) > add_sb_len) add_d_len = add_sb_len - k - 2; desc_len = add_d_len + 2; n += my_snprintf(b + n, blen - n, " Descriptor type: "); processed = 1; switch (descp[0]) { case 0: n += my_snprintf(b + n, blen - n, "Information\n"); if ((add_d_len >= 10) && (0x80 & descp[2])) { n += my_snprintf(b + n, blen - n, " 0x"); for (j = 0; j < 8; ++j) n += my_snprintf(b + n, blen - n, "%02x", descp[4 + j]); n += my_snprintf(b + n, blen - n, "\n"); } else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 1: n += my_snprintf(b + n, blen - n, "Command specific\n"); if (add_d_len >= 10) { n += my_snprintf(b + n, blen - n, " 0x"); for (j = 0; j < 8; ++j) n += my_snprintf(b + n, blen - n, "%02x", descp[4 + j]); n += my_snprintf(b + n, blen - n, "\n"); } else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 2: n += my_snprintf(b + n, blen - n, "Sense key specific:"); switch (sense_key) { case SPC_SK_ILLEGAL_REQUEST: n += my_snprintf(b + n, blen - n, " Field pointer\n"); if (add_d_len < 6) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } n += my_snprintf(b + n, blen - n, " Error in %s: byte %d", (descp[4] & 0x40) ? "Command" : "Data parameters", (descp[5] << 8) | descp[6]); if (descp[4] & 0x08) { n += my_snprintf(b + n, blen - n, " bit %d\n", descp[4] & 0x07); } else n += my_snprintf(b + n, blen - n, "\n"); break; case SPC_SK_HARDWARE_ERROR: case SPC_SK_MEDIUM_ERROR: case SPC_SK_RECOVERED_ERROR: n += my_snprintf(b + n, blen - n, " Actual retry count\n"); if (add_d_len < 6) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } n += my_snprintf(b + n, blen - n," 0x%02x%02x\n", descp[5], descp[6]); break; case SPC_SK_NO_SENSE: case SPC_SK_NOT_READY: n += my_snprintf(b + n, blen - n, " Progress indication: "); if (add_d_len < 6) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } progress = (descp[5] << 8) + descp[6]; pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; n += my_snprintf(b + n, blen - n, "%d.%02d%%\n", pr, rem); break; case SPC_SK_COPY_ABORTED: n += my_snprintf(b + n, blen - n, " Segment pointer\n"); if (add_d_len < 6) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } n += my_snprintf(b + n, blen - n, " Relative to start of %s, " "byte %d", (descp[4] & 0x20) ? "segment descriptor" : "parameter list", (descp[5] << 8) | descp[6]); if (descp[4] & 0x08) n += my_snprintf(b + n, blen - n, " bit %d\n", descp[4] & 0x07); else n += my_snprintf(b + n, blen - n, "\n"); break; case SPC_SK_UNIT_ATTENTION: n += my_snprintf(b + n, blen - n, " Unit attention condition " "queue: "); n += my_snprintf(b + n, blen - n, "overflow flag is %d\n", !!(descp[4] & 0x1)); break; default: n += my_snprintf(b + n, blen - n, " Sense_key: 0x%x " "unexpected\n", sense_key); processed = 0; break; } break; case 3: n += my_snprintf(b + n, blen - n, "Field replaceable unit\n"); if (add_d_len >= 2) n += my_snprintf(b + n, blen - n, " code=0x%x\n", descp[3]); else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 4: n += my_snprintf(b + n, blen - n, "Stream commands\n"); if (add_d_len >= 2) { if (descp[3] & 0x80) n += my_snprintf(b + n, blen - n, " FILEMARK"); if (descp[3] & 0x40) n += my_snprintf(b + n, blen - n, " End Of Medium " "(EOM)"); if (descp[3] & 0x20) n += my_snprintf(b + n, blen - n, " Incorrect Length " "Indicator (ILI)"); n += my_snprintf(b + n, blen - n, "\n"); } else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 5: n += my_snprintf(b + n, blen - n, "Block commands\n"); if (add_d_len >= 2) n += my_snprintf(b + n, blen - n, " Incorrect Length " "Indicator (ILI) %s\n", (descp[3] & 0x20) ? "set" : "clear"); else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 6: n += my_snprintf(b + n, blen - n, "OSD object identification\n"); processed = 0; break; case 7: n += my_snprintf(b + n, blen - n, "OSD response integrity check " "value\n"); processed = 0; break; case 8: n += my_snprintf(b + n, blen - n, "OSD attribute " "identification\n"); processed = 0; break; case 9: /* this is defined in SAT (and SAT-2) */ n += my_snprintf(b + n, blen - n, "ATA Status Return\n"); if (add_d_len >= 12) { int extend, sector_count; extend = descp[2] & 1; sector_count = descp[5] + (extend ? (descp[4] << 8) : 0); n += my_snprintf(b + n, blen - n, " extend=%d error=0x%x " " sector_count=0x%x\n", extend, descp[3], sector_count); if (extend) n += my_snprintf(b + n, blen - n, " " "lba=0x%02x%02x%02x%02x%02x%02x\n", descp[10], descp[8], descp[6], descp[11], descp[9], descp[7]); else n += my_snprintf(b + n, blen - n, " " "lba=0x%02x%02x%02x\n", descp[11], descp[9], descp[7]); n += my_snprintf(b + n, blen - n, " device=0x%x " "status=0x%x\n", descp[12], descp[13]); } else { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; } break; case 0xa: /* Added in SPC-4 rev 17, became 'Another ...' in rev 34 */ n += my_snprintf(b + n, blen - n, "Another progress " "indication\n"); if (add_d_len < 6) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } progress = (descp[6] << 8) + descp[7]; pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; n += my_snprintf(b + n, blen - n, " %d.02%d%%", pr, rem); n += my_snprintf(b + n, blen - n, " [sense_key=0x%x " "asc,ascq=0x%x,0x%x]\n", descp[2], descp[3], descp[4]); break; case 0xb: /* Added in SPC-4 rev 23, defined in SBC-3 rev 22 */ n += my_snprintf(b + n, blen - n, "User data segment referral\n"); if (add_d_len < 2) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } n += uds_referral_descriptor_str(b + n, blen - n, descp, add_d_len); break; case 0xc: /* Added in SPC-4 rev 28 */ n += my_snprintf(b + n, blen - n, "Forwarded sense data\n"); if (add_d_len < 2) { n += my_snprintf(b + n, blen - n, "%s\n", dtsp); processed = 0; break; } n += my_snprintf(b + n, blen - n, " FSDT: %s\n", (descp[2] & 0x80) ? "set" : "clear"); j = descp[2] & 0xf; if (j < 3) n += my_snprintf(b + n, blen - n, " Sense data source: " "%s\n", sdata_src[j]); else n += my_snprintf(b + n, blen - n, " Sense data source: " "reserved [%d]\n", j); { char c[200]; sg_get_scsi_status_str(descp[3], sizeof(c) - 1, c); c[sizeof(c) - 1] = '\0'; n += my_snprintf(b + n, blen - n, " Forwarded status: " "%s\n", c); if (add_d_len > 2) { /* recursing; hope not to get carried away */ n += my_snprintf(b + n, blen - n, " vvvvvvvvvvvvvvvv\n"); sg_get_sense_str(NULL, descp + 4, add_d_len - 2, 0, sizeof(c), c); n += my_snprintf(b + n, blen - n, "%s", c); n += my_snprintf(b + n, blen - n, " ^^^^^^^^^^^^^^^^\n"); } } break; default: if (descp[0] >= 0x80) n += my_snprintf(b + n, blen - n, "Vendor specific [0x%x]\n", descp[0]); else n += my_snprintf(b + n, blen - n, "Unknown [0x%x]\n", descp[0]); processed = 0; break; } if (! processed) { if (add_d_len > 0) { n += my_snprintf(b + n, blen - n, " "); for (j = 0; j < add_d_len; ++j) { if ((j > 0) && (0 == (j % 24))) n += my_snprintf(b + n, blen - n, "\n "); n += my_snprintf(b + n, blen - n, "%02x ", descp[j + 2]); } n += my_snprintf(b + n, blen - n, "\n"); } } if (add_d_len < 0) n += my_snprintf(b + n, blen - n, " short descriptor\n"); } } /* Decode SAT ATA PASS-THROUGH fixed format sense */ static void sg_get_sense_sat_pt_fixed_str(const unsigned char * sp, int slen, int blen, char * b) { int n = 0; if ((blen < 1) || (slen < 12)) return; if (SPC_SK_RECOVERED_ERROR != (0xf & sp[2])) n += my_snprintf(b + n, blen - n, " >> expected Sense key: " "Recovered Error ??\n"); n += my_snprintf(b + n, blen - n, " error=0x%x, status=0x%x, " "device=0x%x, sector_count(7:0)=0x%x%c\n", sp[3], sp[4], sp[5], sp[6], ((0x40 & sp[8]) ? '+' : ' ')); n += my_snprintf(b + n, blen - n, " extend=%d, log_index=0x%x, " "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", (!!(0x80 & sp[8])), (0xf & sp[8]), sp[9], sp[10], sp[11], ((0x20 & sp[8]) ? '+' : ' ')); } /* Fetch sense information */ void sg_get_sense_str(const char * leadin, const unsigned char * sense_buffer, int sb_len, int raw_sinfo, int buff_len, char * buff) { int len, valid, progress, n, r, pr, rem, blen; unsigned int info; int descriptor_format = 0; int sdat_ovfl = 0; const char * ebp = NULL; char error_buff[64]; char b[256]; struct sg_scsi_sense_hdr ssh; if ((NULL == buff) || (buff_len <= 0)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } blen = sizeof(b); n = 0; if (sb_len < 1) { my_snprintf(buff, buff_len, "sense buffer empty\n"); return; } if (leadin) n += my_snprintf(buff + n, buff_len - n, "%s: ", leadin); len = sb_len; if (sg_scsi_normalize_sense(sense_buffer, sb_len, &ssh)) { switch (ssh.response_code) { case 0x70: /* fixed, current */ ebp = "Fixed format, current"; len = (sb_len > 7) ? (sense_buffer[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sense_buffer[2] & 0x10) : 0; break; case 0x71: /* fixed, deferred */ /* error related to a previous command */ ebp = "Fixed format, <<>>"; len = (sb_len > 7) ? (sense_buffer[7] + 8) : sb_len; len = (len > sb_len) ? sb_len : len; sdat_ovfl = (len > 2) ? !!(sense_buffer[2] & 0x10) : 0; break; case 0x72: /* descriptor, current */ descriptor_format = 1; ebp = "Descriptor format, current"; sdat_ovfl = (sb_len > 4) ? !!(sense_buffer[4] & 0x80) : 0; break; case 0x73: /* descriptor, deferred */ descriptor_format = 1; ebp = "Descriptor format, <<>>"; sdat_ovfl = (sb_len > 4) ? !!(sense_buffer[4] & 0x80) : 0; break; case 0x0: ebp = "Response code: 0x0 (?)"; break; default: my_snprintf(error_buff, sizeof(error_buff), "Unknown response code: 0x%x", ssh.response_code); ebp = error_buff; break; } n += my_snprintf(buff + n, buff_len - n, " %s; Sense key: %s\n ", ebp, sg_lib_sense_key_desc[ssh.sense_key]); if (sdat_ovfl) n += my_snprintf(buff + n, buff_len - n, "<<>>\n"); if (descriptor_format) { n += my_snprintf(buff + n, buff_len - n, "%s\n", sg_get_asc_ascq_str(ssh.asc, ssh.ascq, sizeof(b), b)); sg_get_sense_descriptors_str(sense_buffer, len, buff_len - n, buff + n); n = strlen(buff); } else if ((len > 12) && (0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { /* SAT ATA PASS-THROUGH fixed format */ n += my_snprintf(buff + n, buff_len - n, "%s\n", sg_get_asc_ascq_str(ssh.asc, ssh.ascq, sizeof(b), b)); sg_get_sense_sat_pt_fixed_str(sense_buffer, len, buff_len - n, buff + n); n = strlen(buff); } else if (len > 2) { /* fixed format */ if (len > 12) n += my_snprintf(buff + n, buff_len - n, "%s\n", sg_get_asc_ascq_str(ssh.asc, ssh.ascq, sizeof(b), b)); r = 0; valid = sense_buffer[0] & 0x80; if (len > 6) { info = (unsigned int)((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | (sense_buffer[5] << 8) | sense_buffer[6]); if (valid) r += my_snprintf(b + r, blen - r, " Info fld=0x%x [%u] ", info, info); else if (info > 0) r += my_snprintf(b + r, blen - r, " Valid=0, Info " "fld=0x%x [%u] ", info, info); } else info = 0; if (sense_buffer[2] & 0xe0) { if (sense_buffer[2] & 0x80) r += my_snprintf(b + r, blen - r, " FMK"); /* current command has read a filemark */ if (sense_buffer[2] & 0x40) r += my_snprintf(b + r, blen - r, " EOM"); /* end-of-medium condition exists */ if (sense_buffer[2] & 0x20) r += my_snprintf(b + r, blen - r, " ILI"); /* incorrect block length requested */ r += my_snprintf(b + r, blen - r, "\n"); } else if (valid || (info > 0)) r += my_snprintf(b + r, blen - r, "\n"); if ((len >= 14) && sense_buffer[14]) r += my_snprintf(b + r, blen - r, " Field replaceable unit " "code: %d\n", sense_buffer[14]); if ((len >= 18) && (sense_buffer[15] & 0x80)) { /* sense key specific decoding */ switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: r += my_snprintf(b + r, blen - r, " Sense Key Specific: " "Error in %s: byte %d", ((sense_buffer[15] & 0x40) ? "Command" : "Data parameters"), (sense_buffer[16] << 8) | sense_buffer[17]); if (sense_buffer[15] & 0x08) r += my_snprintf(b + r, blen - r, " bit %d\n", sense_buffer[15] & 0x07); else r += my_snprintf(b + r, blen - r, "\n"); break; case SPC_SK_NO_SENSE: case SPC_SK_NOT_READY: progress = (sense_buffer[16] << 8) + sense_buffer[17]; pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; r += my_snprintf(b + r, blen - r, " Progress " "indication: %d.%02d%%\n", pr, rem); break; case SPC_SK_HARDWARE_ERROR: case SPC_SK_MEDIUM_ERROR: case SPC_SK_RECOVERED_ERROR: r += my_snprintf(b + r, blen - r, " Actual retry count: " "0x%02x%02x\n", sense_buffer[16], sense_buffer[17]); break; case SPC_SK_COPY_ABORTED: r += my_snprintf(b + r, blen - r, " Segment pointer: "); r += my_snprintf(b + r, blen - r, "Relative to start of " "%s, byte %d", ((sense_buffer[15] & 0x20) ? "segment descriptor" : "parameter list"), ((sense_buffer[16] << 8) + sense_buffer[17])); if (sense_buffer[15] & 0x08) r += my_snprintf(b + r, blen - r, " bit %d\n", sense_buffer[15] & 0x07); else r += my_snprintf(b + r, blen - r, "\n"); break; case SPC_SK_UNIT_ATTENTION: r += my_snprintf(b + r, blen - r, " Unit attention " "condition queue: "); r += my_snprintf(b + r, blen - r, "overflow flag is %d\n", !!(sense_buffer[15] & 0x1)); break; default: r += my_snprintf(b + r, blen - r, " Sense_key: 0x%x " "unexpected\n", ssh.sense_key); break; } } if (r > 0) n += my_snprintf(buff + n, buff_len - n, "%s", b); } else n += my_snprintf(buff + n, buff_len - n, " fixed descriptor " "length too short, len=%d\n", len); } else { /* non-extended SCSI-1 sense data ?? */ if (sb_len < 4) { n += my_snprintf(buff + n, buff_len - n, "sense buffer too short " "(4 byte minimum)\n"); return; } r = 0; r += my_snprintf(b + r, blen - r, "Probably uninitialized data.\n " "Try to view as SCSI-1 non-extended sense:\n"); r += my_snprintf(b + r, blen - r, " AdValid=%d Error class=%d " "Error code=%d\n", !!(sense_buffer[0] & 0x80), ((sense_buffer[0] >> 4) & 0x7), (sense_buffer[0] & 0xf)); if (sense_buffer[0] & 0x80) r += my_snprintf(b + r, blen - r, " lba=0x%x\n", ((sense_buffer[1] & 0x1f) << 16) + (sense_buffer[2] << 8) + sense_buffer[3]); n += my_snprintf(buff + n, buff_len - n, "%s\n", b); len = sb_len; if (len > 32) len = 32; /* trim in case there is a lot of rubbish */ } if (raw_sinfo) { n += my_snprintf(buff + n, buff_len - n, " Raw sense data (in hex):" "\n"); if (n >= (buff_len - 1)) return; dStrHexStr((const char *)sense_buffer, len, " ", 0, buff_len - n, buff + n); } } /* Print sense information */ void sg_print_sense(const char * leadin, const unsigned char * sense_buffer, int sb_len, int raw_sinfo) { char b[2048]; sg_get_sense_str(leadin, sense_buffer, sb_len, raw_sinfo, sizeof(b), b); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "%s", b); } /* See description in sg_lib.h header file */ int sg_scsi_normalize_sense(const unsigned char * sensep, int sb_len, struct sg_scsi_sense_hdr * sshp) { if (sshp) memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); if ((NULL == sensep) || (0 == sb_len) || (0x70 != (0x70 & sensep[0]))) return 0; if (sshp) { sshp->response_code = (0x7f & sensep[0]); if (sshp->response_code >= 0x72) { /* descriptor format */ if (sb_len > 1) sshp->sense_key = (0xf & sensep[1]); if (sb_len > 2) sshp->asc = sensep[2]; if (sb_len > 3) sshp->ascq = sensep[3]; if (sb_len > 7) sshp->additional_length = sensep[7]; } else { /* fixed format */ if (sb_len > 2) sshp->sense_key = (0xf & sensep[2]); if (sb_len > 7) { sb_len = (sb_len < (sensep[7] + 8)) ? sb_len : (sensep[7] + 8); if (sb_len > 12) sshp->asc = sensep[12]; if (sb_len > 13) sshp->ascq = sensep[13]; } } } return 1; } /* Returns a SG_LIB_CAT_* value. If cannot decode sense_buffer or a less * common sense key then return SG_LIB_CAT_SENSE .*/ int sg_err_category_sense(const unsigned char * sense_buffer, int sb_len) { struct sg_scsi_sense_hdr ssh; if ((sense_buffer && (sb_len > 2)) && (sg_scsi_normalize_sense(sense_buffer, sb_len, &ssh))) { switch (ssh.sense_key) { /* 0 to 0x1f */ case SPC_SK_NO_SENSE: return SG_LIB_CAT_NO_SENSE; case SPC_SK_RECOVERED_ERROR: return SG_LIB_CAT_RECOVERED; case SPC_SK_NOT_READY: return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: case SPC_SK_BLANK_CHECK: return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_UNIT_ATTENTION: return SG_LIB_CAT_UNIT_ATTENTION; /* used to return SG_LIB_CAT_MEDIA_CHANGED when ssh.asc==0x28 */ case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) return SG_LIB_CAT_INVALID_OP; else return SG_LIB_CAT_ILLEGAL_REQ; break; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) return SG_LIB_CAT_PROTECTION; else return SG_LIB_CAT_ABORTED_COMMAND; case SPC_SK_MISCOMPARE: return SG_LIB_CAT_MISCOMPARE; case SPC_SK_DATA_PROTECT: return SG_LIB_CAT_DATA_PROTECT; case SPC_SK_COPY_ABORTED: return SG_LIB_CAT_COPY_ABORTED; case SPC_SK_COMPLETED: case SPC_SK_VOLUME_OVERFLOW: return SG_LIB_CAT_SENSE; default: ; /* reserved and vendor specific sense keys fall through */ } } return SG_LIB_CAT_SENSE; } /* Beware: gives wrong answer for variable length command (opcode=0x7f) */ int sg_get_command_size(unsigned char opcode) { switch ((opcode >> 5) & 0x7) { case 0: return 6; case 1: case 2: case 6: case 7: return 10; case 3: case 5: return 12; break; case 4: return 16; default: return 10; } } void sg_get_command_name(const unsigned char * cmdp, int peri_type, int buff_len, char * buff) { int service_action; if ((NULL == buff) || (buff_len < 1)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } if (NULL == cmdp) { my_snprintf(buff, buff_len, "%s", " command pointer"); return; } service_action = (SG_VARIABLE_LENGTH_CMD == cmdp[0]) ? ((cmdp[8] << 8) | cmdp[9]) : (cmdp[1] & 0x1f); sg_get_opcode_sa_name(cmdp[0], service_action, peri_type, buff_len, buff); } struct op_code2sa_t { int op_code; struct sg_lib_value_name_t * arr; const char * prefix; }; static struct op_code2sa_t op_code2sa_arr[] = { {SG_VARIABLE_LENGTH_CMD, sg_lib_variable_length_arr, NULL}, {SG_MAINTENANCE_IN, sg_lib_maint_in_arr, NULL}, {SG_MAINTENANCE_OUT, sg_lib_maint_out_arr, NULL}, {SG_SERVICE_ACTION_IN_12, sg_lib_serv_in12_arr, NULL}, {SG_SERVICE_ACTION_OUT_12, sg_lib_serv_out12_arr, NULL}, {SG_SERVICE_ACTION_IN_16, sg_lib_serv_in16_arr, NULL}, {SG_SERVICE_ACTION_OUT_16, sg_lib_serv_out16_arr, NULL}, {SG_SERVICE_ACTION_BIDI, sg_lib_serv_bidi_arr, NULL}, {SG_PERSISTENT_RESERVE_IN, sg_lib_pr_in_arr, "Persistent reserve in"}, {SG_PERSISTENT_RESERVE_OUT, sg_lib_pr_out_arr, "Persistent reserve out"}, {SG_THIRD_PARTY_COPY_OUT, sg_lib_xcopy_sa_arr, NULL}, {SG_THIRD_PARTY_COPY_IN, sg_lib_rec_copy_sa_arr, NULL}, {SG_READ_BUFFER, sg_lib_read_buff_arr, "Read buffer"}, {SG_WRITE_BUFFER, sg_lib_write_buff_arr, "Write buffer"}, {SG_SANITIZE, sg_lib_sanitize_sa_arr, "Sanitize"}, {0xffff, NULL, NULL}, }; void sg_get_opcode_sa_name(unsigned char cmd_byte0, int service_action, int peri_type, int buff_len, char * buff) { const struct sg_lib_value_name_t * vnp; const struct op_code2sa_t * osp; char b[80]; if ((NULL == buff) || (buff_len < 1)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } for (osp = op_code2sa_arr; osp->arr; ++osp) { if ((int)cmd_byte0 == osp->op_code) { vnp = get_value_name(osp->arr, service_action, peri_type); if (vnp) { if (osp->prefix) my_snprintf(buff, buff_len, "%s, %s", osp->prefix, vnp->name); else my_snprintf(buff, buff_len, "%s", vnp->name); } else { sg_get_opcode_name(cmd_byte0, peri_type, sizeof(b), b); my_snprintf(buff, buff_len, "%s service action=0x%x", b, service_action); } return; } } sg_get_opcode_name(cmd_byte0, peri_type, buff_len, buff); } void sg_get_opcode_name(unsigned char cmd_byte0, int peri_type, int buff_len, char * buff) { const struct sg_lib_value_name_t * vnp; int grp; if ((NULL == buff) || (buff_len < 1)) return; else if (1 == buff_len) { buff[0] = '\0'; return; } if (SG_VARIABLE_LENGTH_CMD == cmd_byte0) { my_snprintf(buff, buff_len, "%s", "Variable length"); return; } grp = (cmd_byte0 >> 5) & 0x7; switch (grp) { case 0: case 1: case 2: case 4: case 5: vnp = get_value_name(sg_lib_normal_opcodes, cmd_byte0, peri_type); if (vnp) my_snprintf(buff, buff_len, "%s", vnp->name); else my_snprintf(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0); break; case 3: my_snprintf(buff, buff_len, "Reserved [0x%x]", (int)cmd_byte0); break; case 6: case 7: my_snprintf(buff, buff_len, "Vendor specific [0x%x]", (int)cmd_byte0); break; default: my_snprintf(buff, buff_len, "Opcode=0x%x", (int)cmd_byte0); break; } } /* Iterates to next designation descriptor in the device identification * VPD page. The 'initial_desig_desc' should point to start of first * descriptor with 'page_len' being the number of valid bytes in that * and following descriptors. To start, 'off' should point to a negative * value, thereafter it should point to the value yielded by the previous * call. If 0 returned then 'initial_desig_desc + *off' should be a valid * descriptor; returns -1 if normal end condition and -2 for an abnormal * termination. Matches association, designator_type and/or code_set when * any of those values are greater than or equal to zero. */ int sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, int * off, int m_assoc, int m_desig_type, int m_code_set) { const unsigned char * ucp; int k, c_set, assoc, desig_type; for (k = *off, ucp = initial_desig_desc ; (k + 3) < page_len; ) { k = (k < 0) ? 0 : (k + ucp[k + 3] + 4); if ((k + 4) > page_len) break; c_set = (ucp[k] & 0xf); if ((m_code_set >= 0) && (m_code_set != c_set)) continue; assoc = ((ucp[k + 1] >> 4) & 0x3); if ((m_assoc >= 0) && (m_assoc != assoc)) continue; desig_type = (ucp[k + 1] & 0xf); if ((m_desig_type >= 0) && (m_desig_type != desig_type)) continue; *off = k; return 0; } return (k == page_len) ? -1 : -2; } static const char * bad_sense_cat = "Bad sense category"; /* Yield string associated with sense++ category. Returns 'buff' (or pointer * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then * yield "Sense category: " string. */ const char * sg_get_category_sense_str(int sense_cat, int buff_len, char * buff, int verbose) { int n; if (NULL == buff) return bad_sense_cat; if (buff_len <= 0) return buff; switch (sense_cat) { case SG_LIB_CAT_CLEAN: /* 0 */ snprintf(buff, buff_len, "No errors"); break; case SG_LIB_SYNTAX_ERROR: /* 1 */ snprintf(buff, buff_len, "Syntax error"); break; case SG_LIB_CAT_NOT_READY: /* 2 */ n = snprintf(buff, buff_len, "Not ready"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_CAT_MEDIUM_HARD: /* 3 */ n = snprintf(buff, buff_len, "Medium or hardware error"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key (plus blank check)"); break; case SG_LIB_CAT_ILLEGAL_REQ: /* 5 */ n = snprintf(buff, buff_len, "Illegal request"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key, apart from Invalid " "opcode"); break; case SG_LIB_CAT_UNIT_ATTENTION: /* 6 */ n = snprintf(buff, buff_len, "Unit attention"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_CAT_DATA_PROTECT: /* 7 */ n = snprintf(buff, buff_len, "Data protect"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key, write protected " "media?"); break; case SG_LIB_CAT_INVALID_OP: /* 9 */ n = snprintf(buff, buff_len, "Illegal request, invalid opcode"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_CAT_COPY_ABORTED: /* 10 */ n = snprintf(buff, buff_len, "Copy aborted"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_CAT_ABORTED_COMMAND: /* 11 */ n = snprintf(buff, buff_len, "Aborted command"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key, other than " "protection related (asc=0x10)"); break; case SG_LIB_CAT_MISCOMPARE: /* 14 */ n = snprintf(buff, buff_len, "Miscompare"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_FILE_ERROR: /* 15 */ snprintf(buff, buff_len, "File error"); break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: /* 17 */ snprintf(buff, buff_len, "Illegal request with info"); break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: /* 18 */ snprintf(buff, buff_len, "Medium or hardware error with info"); break; case SG_LIB_CAT_NO_SENSE: /* 20 */ n = snprintf(buff, buff_len, "No sense key"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " probably additional sense " "information"); break; case SG_LIB_CAT_RECOVERED: /* 21 */ n = snprintf(buff, buff_len, "Recovered error"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " sense key"); break; case SG_LIB_CAT_RES_CONFLICT: /* 24 */ n = snprintf(buff, buff_len, "Reservation conflict"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " SCSI status"); break; case SG_LIB_CAT_TIMEOUT: /* 33 */ snprintf(buff, buff_len, "SCSI command timeout"); break; case SG_LIB_CAT_PROTECTION: /* 40 */ n = snprintf(buff, buff_len, "Aborted command, protection"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " information (PI) problem"); break; case SG_LIB_CAT_PROTECTION_WITH_INFO: /* 41 */ n = snprintf(buff, buff_len, "Aborted command with info, protection"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " information (PI) problem"); break; case SG_LIB_CAT_MALFORMED: /* 97 */ n = snprintf(buff, buff_len, "Malformed response"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, " to SCSI command"); break; case SG_LIB_CAT_SENSE: /* 98 */ n = snprintf(buff, buff_len, "Some other sense data problem"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, ", try '-v' option for more " "information"); break; case SG_LIB_CAT_OTHER: /* 99 */ n = snprintf(buff, buff_len, "Some other error/warning has occurred"); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, ", possible transport of driver " "issue"); default: n = snprintf(buff, buff_len, "Sense category: %d", sense_cat); if (verbose && (n < (buff_len - 1))) snprintf(buff + n, buff_len - n, ", try '-v' option for more " "information"); break; } return buff; } /* safe_strerror() contributed by Clayton Weaver * Allows for situation in which strerror() is given a wild value (or the * C library is incomplete) and returns NULL. Still not thread safe. */ static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'n', 'o', ':', ' ', 0}; char * safe_strerror(int errnum) { size_t len; char * errstr; if (errnum < 0) errnum = -errnum; errstr = strerror(errnum); if (NULL == errstr) { len = strlen(safe_errbuf); my_snprintf(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum); return safe_errbuf; } return errstr; } static void trimTrailingSpaces(char * b) { int k; for (k = ((int)strlen(b) - 1); k >= 0; --k) { if (' ' != b[k]) break; } if ('\0' != b[k + 1]) b[k + 1] = '\0'; } /* Note the ASCII-hex output goes to stdout. [Most other output from functions * in this file go to sg_warnings_strm (default stderr).] * 'no_ascii' allows for 3 output types: * > 0 each line has address then up to 16 ASCII-hex bytes * = 0 in addition, the bytes are listed in ASCII to the right * < 0 only the ASCII-hex bytes are listed (i.e. without address) */ static void dStrHexFp(const char* str, int len, int no_ascii, FILE * fp) { const char * p = str; const char * formatstr; unsigned char c; char buff[82]; int a = 0; int bpstart = 5; const int cpstart = 60; int cpos = cpstart; int bpos = bpstart; int i, k, blen; if (len <= 0) return; blen = (int)sizeof(buff); if (0 == no_ascii) /* address at left and ASCII at right */ formatstr = "%.76s\n"; else if (no_ascii > 0) formatstr = "%s\n"; /* was: "%.58s\n" */ else /* negative: no address at left and no ASCII at right */ formatstr = "%s\n"; /* was: "%.48s\n"; */ memset(buff, ' ', 80); buff[80] = '\0'; if (no_ascii < 0) { bpstart = 0; bpos = bpstart; for (k = 0; k < len; k++) { c = *p++; if (bpos == (bpstart + (8 * 3))) bpos++; my_snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if ((k > 0) && (0 == ((k + 1) % 16))) { trimTrailingSpaces(buff); fprintf(fp, formatstr, buff); bpos = bpstart; memset(buff, ' ', 80); } else bpos += 3; } if (bpos > bpstart) { buff[bpos + 2] = '\0'; trimTrailingSpaces(buff); fprintf(fp, "%s\n", buff); } return; } /* no_ascii>=0, start each line with address (offset) */ k = my_snprintf(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; for (i = 0; i < len; i++) { c = *p++; bpos += 3; if (bpos == (bpstart + (9 * 3))) bpos++; my_snprintf(&buff[bpos], blen - bpos, "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if (no_ascii) buff[cpos++] = ' '; else { if ((c < ' ') || (c >= 0x7f)) c = '.'; buff[cpos++] = c; } if (cpos > (cpstart + 15)) { if (no_ascii) trimTrailingSpaces(buff); fprintf(fp, formatstr, buff); bpos = bpstart; cpos = cpstart; a += 16; memset(buff, ' ', 80); k = my_snprintf(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; } } if (cpos > cpstart) { buff[cpos] = '\0'; if (no_ascii) trimTrailingSpaces(buff); fprintf(fp, "%s\n", buff); } } void dStrHex(const char* str, int len, int no_ascii) { dStrHexFp(str, len, no_ascii, stdout); } void dStrHexErr(const char* str, int len, int no_ascii) { dStrHexFp(str, len, no_ascii, (sg_warnings_strm ? sg_warnings_strm : stderr)); } /* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space * separated) to 'b' not to exceed 'b_len' characters. Each line * starts with 'leadin' (NULL for no leadin) and there are 16 bytes * per line with an extra space between the 8th and 9th bytes. 'format' * is unused (currently), set to 0 . */ void dStrHexStr(const char* str, int len, const char * leadin, int format, int b_len, char * b) { const char * p = str; unsigned char c; char buff[122]; int bpstart, bpos, k, n; if (len <= 0) { if (b_len > 0) b[0] = '\0'; return; } if (0 != format) { ; /* do nothing different for now */ } if (leadin) { bpstart = strlen(leadin); /* Cap leadin at 60 characters */ if (bpstart > 60) bpstart = 60; } else bpstart = 0; bpos = bpstart; n = 0; memset(buff, ' ', 120); buff[120] = '\0'; if (bpstart > 0) memcpy(buff, leadin, bpstart); for (k = 0; k < len; k++) { c = *p++; if (bpos == (bpstart + (8 * 3))) bpos++; my_snprintf(&buff[bpos], (int)sizeof(buff) - bpos, "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if ((k > 0) && (0 == ((k + 1) % 16))) { trimTrailingSpaces(buff); n += my_snprintf(b + n, b_len - n, "%s\n", buff); if (n >= (b_len - 1)) return; bpos = bpstart; memset(buff, ' ', 120); if (bpstart > 0) memcpy(buff, leadin, bpstart); } else bpos += 3; } if (bpos > bpstart) { trimTrailingSpaces(buff); n += my_snprintf(b + n, b_len - n, "%s\n", buff); } return; } /* Returns 1 when executed on big endian machine; else returns 0. * Useful for displaying ATA identify words (which need swapping on a * big endian machine). */ int sg_is_big_endian() { union u_t { unsigned short s; unsigned char c[sizeof(unsigned short)]; } u; u.s = 0x0102; return (u.c[0] == 0x01); /* The lowest address contains the most significant byte */ } static unsigned short swapb_ushort(unsigned short u) { unsigned short r; r = (u >> 8) & 0xff; r |= ((u & 0xff) << 8); return r; } /* Note the ASCII-hex output goes to stdout. [Most other output from functions * in this file go to sg_warnings_strm (default stderr).] * 'no_ascii' allows for 3 output types: * > 0 each line has address then up to 8 ASCII-hex 16 bit words * = 0 in addition, the ASCI bytes pairs are listed to the right * = -1 only the ASCII-hex words are listed (i.e. without address) * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin" * < -2 same as -1 * If 'swapb' non-zero then bytes in each word swapped. Needs to be set * for ATA IDENTIFY DEVICE response on big-endian machines. */ void dWordHex(const unsigned short* words, int num, int no_ascii, int swapb) { const unsigned short * p = words; unsigned short c; char buff[82]; unsigned char upp, low; int a = 0; const int bpstart = 3; const int cpstart = 52; int cpos = cpstart; int bpos = bpstart; int i, k, blen; if (num <= 0) return; blen = (int)sizeof(buff); memset(buff, ' ', 80); buff[80] = '\0'; if (no_ascii < 0) { for (k = 0; k < num; k++) { c = *p++; if (swapb) c = swapb_ushort(c); bpos += 5; my_snprintf(&buff[bpos], blen - bpos, "%.4x", (unsigned int)c); buff[bpos + 4] = ' '; if ((k > 0) && (0 == ((k + 1) % 8))) { if (-2 == no_ascii) printf("%.39s\n", buff +8); else printf("%.47s\n", buff); bpos = bpstart; memset(buff, ' ', 80); } } if (bpos > bpstart) { if (-2 == no_ascii) printf("%.39s\n", buff +8); else printf("%.47s\n", buff); } return; } /* no_ascii>=0, start each line with address (offset) */ k = my_snprintf(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; for (i = 0; i < num; i++) { c = *p++; if (swapb) c = swapb_ushort(c); bpos += 5; my_snprintf(&buff[bpos], blen - bpos, "%.4x", (unsigned int)c); buff[bpos + 4] = ' '; if (no_ascii) { buff[cpos++] = ' '; buff[cpos++] = ' '; buff[cpos++] = ' '; } else { upp = (c >> 8) & 0xff; low = c & 0xff; if ((upp < 0x20) || (upp >= 0x7f)) upp = '.'; buff[cpos++] = upp; if ((low < 0x20) || (low >= 0x7f)) low = '.'; buff[cpos++] = low; buff[cpos++] = ' '; } if (cpos > (cpstart + 23)) { printf("%.76s\n", buff); bpos = bpstart; cpos = cpstart; a += 8; memset(buff, ' ', 80); k = my_snprintf(buff + 1, blen - 1, "%.2x", a); buff[k + 1] = ' '; } } if (cpos > cpstart) printf("%.76s\n", buff); } /* If the number in 'buf' can be decoded or the multiplier is unknown * then -1 is returned. Accepts a hex prefix (0x or 0X) or a decimal * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). * Main (SI) multipliers supported: K, M, G. Ignore leading spaces and * tabs; accept comma, space, tab and hash as terminator. */ int sg_get_num(const char * buf) { int res, num, n, len; unsigned int unum; char * cp; const char * b; char c = 'c'; char c2, c3; char lb[16]; if ((NULL == buf) || ('\0' == buf[0])) return -1; len = strlen(buf); n = strspn(buf, " \t"); if (n > 0) { if (n == len) return -1; buf += n; len -=n; } /* following hack to keep C++ happy */ cp = strpbrk((char *)buf, " \t,#"); if (cp) { len = cp - buf; n = (int)sizeof(lb) - 1; len = (len < n) ? len : n; memcpy(lb, buf, len); lb[len] = '\0'; b = lb; } else b = buf; if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { res = sscanf(b + 2, "%x", &unum); num = unum; } else if ('H' == toupper((int)b[len - 1])) { res = sscanf(b, "%x", &unum); num = unum; } else res = sscanf(b, "%d%c%c%c", &num, &c, &c2, &c3); if (res < 1) return -1LL; else if (1 == res) return num; else { if (res > 2) c2 = toupper((int)c2); if (res > 3) c3 = toupper((int)c3); switch (toupper((int)c)) { case 'C': return num; case 'W': return num * 2; case 'B': return num * 512; case 'K': if (2 == res) return num * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1024; return -1; case 'M': if (2 == res) return num * 1048576; if (('B' == c2) || ('D' == c2)) return num * 1000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1048576; return -1; case 'G': if (2 == res) return num * 1073741824; if (('B' == c2) || ('D' == c2)) return num * 1000000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1073741824; return -1; case 'X': cp = (char *)strchr(b, 'x'); if (NULL == cp) cp = (char *)strchr(b, 'X'); if (cp) { n = sg_get_num(cp + 1); if (-1 != n) return num * n; } return -1; default: if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "unrecognized multiplier\n"); return -1; } } } /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is * assumed. Does not accept multipliers. Accept a comma (","), a whitespace * or newline as terminator. */ int sg_get_num_nomult(const char * buf) { int res, len, num; unsigned int unum; char * commap; if ((NULL == buf) || ('\0' == buf[0])) return -1; len = strlen(buf); commap = (char *)strchr(buf + 1, ','); if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { res = sscanf(buf + 2, "%x", &unum); num = unum; } else if (commap && ('H' == toupper((int)*(commap - 1)))) { res = sscanf(buf, "%x", &unum); num = unum; } else if ((NULL == commap) && ('H' == toupper((int)buf[len - 1]))) { res = sscanf(buf, "%x", &unum); num = unum; } else res = sscanf(buf, "%d", &num); if (1 == res) return num; else return -1; } /* If the number in 'buf' can be decoded or the multiplier is unknown * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a decimal * multiplier suffix (as per GNU's dd (since 2002: SI and IEC 60027-2)). * Main (SI) multipliers supported: K, M, G, T, P. Ignore leading spaces * and tabs; accept comma, space, tab and hash as terminator. */ int64_t sg_get_llnum(const char * buf) { int res, len, n; int64_t num, ll; uint64_t unum; char * cp; const char * b; char c = 'c'; char c2, c3; char lb[32]; if ((NULL == buf) || ('\0' == buf[0])) return -1LL; len = strlen(buf); n = strspn(buf, " \t"); if (n > 0) { if (n == len) return -1LL; buf += n; len -=n; } /* following hack to keep C++ happy */ cp = strpbrk((char *)buf, " \t,#"); if (cp) { len = cp - buf; n = (int)sizeof(lb) - 1; len = (len < n) ? len : n; memcpy(lb, buf, len); lb[len] = '\0'; b = lb; } else b = buf; if (('0' == b[0]) && (('x' == b[1]) || ('X' == b[1]))) { res = sscanf(b + 2, "%" SCNx64 "", &unum); num = unum; } else if ('H' == toupper((int)b[len - 1])) { res = sscanf(b, "%" SCNx64 "", &unum); num = unum; } else res = sscanf(b, "%" SCNd64 "%c%c%c", &num, &c, &c2, &c3); if (res < 1) return -1LL; else if (1 == res) return num; else { if (res > 2) c2 = toupper((int)c2); if (res > 3) c3 = toupper((int)c3); switch (toupper((int)c)) { case 'C': return num; case 'W': return num * 2; case 'B': return num * 512; case 'K': if (2 == res) return num * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1024; return -1LL; case 'M': if (2 == res) return num * 1048576; if (('B' == c2) || ('D' == c2)) return num * 1000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1048576; return -1LL; case 'G': if (2 == res) return num * 1073741824; if (('B' == c2) || ('D' == c2)) return num * 1000000000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1073741824; return -1LL; case 'T': if (2 == res) return num * 1099511627776LL; if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL; return -1LL; case 'P': if (2 == res) return num * 1099511627776LL * 1024; if (('B' == c2) || ('D' == c2)) return num * 1000000000000LL * 1000; if (('I' == c2) && (4 == res) && ('B' == c3)) return num * 1099511627776LL * 1024; return -1LL; case 'X': cp = (char *)strchr(b, 'x'); if (NULL == cp) cp = (char *)strchr(b, 'X'); if (cp) { ll = sg_get_llnum(cp + 1); if (-1LL != ll) return num * ll; } return -1LL; default: if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "unrecognized multiplier\n"); return -1LL; } } } /* Extract character sequence from ATA words as in the model string * in a IDENTIFY DEVICE response. Returns number of characters * written to 'ochars' before 0 character is found or 'num' words * are processed. */ int sg_ata_get_chars(const unsigned short * word_arr, int start_word, int num_words, int is_big_endian, char * ochars) { int k; unsigned short s; char a, b; char * op = ochars; for (k = start_word; k < (start_word + num_words); ++k) { s = word_arr[k]; if (is_big_endian) { a = s & 0xff; b = (s >> 8) & 0xff; } else { a = (s >> 8) & 0xff; b = s & 0xff; } if (a == 0) break; *op++ = a; if (b == 0) break; *op++ = b; } return op - ochars; } const char * sg_lib_version() { return sg_lib_version_str; } #ifdef SG_LIB_MINGW /* Non Unix OSes distinguish between text and binary files. Set text mode on fd. Does nothing in Unix. Returns negative number on failure. */ #include #include int sg_set_text_mode(int fd) { return setmode(fd, O_TEXT); } /* Set binary mode on fd. Does nothing in Unix. Returns negative number on failure. */ int sg_set_binary_mode(int fd) { return setmode(fd, O_BINARY); } #else /* For Unix the following functions are dummies. */ int sg_set_text_mode(int fd) { return fd; /* fd should be >= 0 */ } int sg_set_binary_mode(int fd) { return fd; } #endif sg3_utils-1.40/lib/sg_pt_freebsd.c0000664000175000017500000003307712227056727016114 0ustar douggdougg/* * Copyright (c) 2005-2013 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* sg_pt_freebsd version 1.12 20130919 */ #include #include #include #include #include #include #include #include #include #include // #include #include #include #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #define FREEBSD_MAXDEV 64 #define FREEBSD_FDOFFSET 16; struct freebsd_dev_channel { char* devname; // the SCSI device name int unitnum; // the SCSI unit number struct cam_device* cam_dev; }; // Private table of open devices: guaranteed zero on startup since // part of static data. static struct freebsd_dev_channel *devicetable[FREEBSD_MAXDEV]; #define DEF_TIMEOUT 60000 /* 60,000 milliseconds (60 seconds) */ struct sg_pt_freebsd_scsi { struct cam_device* cam_dev; // copy held for error processing union ccb *ccb; unsigned char * cdb; int cdb_len; unsigned char * sense; int sense_len; unsigned char * dxferp; int dxfer_len; int dxfer_dir; int scsi_status; int resid; int sense_resid; int in_err; int os_err; int transport_err; }; struct sg_pt_base { struct sg_pt_freebsd_scsi impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. The 'flags' argument is ignored in FreeBSD. * Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int flags __attribute__ ((unused)), int verbose) { struct freebsd_dev_channel *fdchan; struct cam_device* cam_dev; int k; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; // Search table for a free entry for (k = 0; k < FREEBSD_MAXDEV; k++) if (! devicetable[k]) break; // If no free entry found, return error. We have max allowed number // of "file descriptors" already allocated. if (k == FREEBSD_MAXDEV) { if (verbose) fprintf(sg_warnings_strm, "too many open file descriptors " "(%d)\n", FREEBSD_MAXDEV); errno = EMFILE; return -1; } fdchan = (struct freebsd_dev_channel *) calloc(1,sizeof(struct freebsd_dev_channel)); if (fdchan == NULL) { // errno already set by call to calloc() return -1; } if (! (fdchan->devname = (char *)calloc(1, DEV_IDLEN+1))) return -1; if (cam_get_device(device_name, fdchan->devname, DEV_IDLEN, &(fdchan->unitnum)) == -1) { if (verbose) fprintf(sg_warnings_strm, "bad device name structure\n"); errno = EINVAL; return -1; } if (! (cam_dev = cam_open_spec_device(fdchan->devname, fdchan->unitnum, O_RDWR, NULL))) { if (verbose) fprintf(sg_warnings_strm, "cam_open_spec_device: %s\n", cam_errbuf); errno = EPERM; /* permissions or no CAM */ return -1; } fdchan->cam_dev = cam_dev; // return pointer to "file descriptor" table entry, properly offset. devicetable[k] = fdchan; return k + FREEBSD_FDOFFSET; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { struct freebsd_dev_channel *fdchan; int fd = device_fd - FREEBSD_FDOFFSET; if ((fd < 0) || (fd >= FREEBSD_MAXDEV)) { errno = ENODEV; return -1; } fdchan = devicetable[fd]; if (NULL == fdchan) { errno = ENODEV; return -1; } if (fdchan->devname) free(fdchan->devname); if (fdchan->cam_dev) cam_close_device(fdchan->cam_dev); free(fdchan); devicetable[fd] = NULL; return 0; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_freebsd_scsi * ptp; ptp = (struct sg_pt_freebsd_scsi *) calloc(1, sizeof(struct sg_pt_freebsd_scsi)); if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi)); ptp->dxfer_dir = CAM_DIR_NONE; } return (struct sg_pt_base *)ptp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp) { if (ptp->ccb) cam_freeccb(ptp->ccb); free(ptp); } } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp) { if (ptp->ccb) cam_freeccb(ptp->ccb); memset(ptp, 0, sizeof(struct sg_pt_freebsd_scsi)); ptp->dxfer_dir = CAM_DIR_NONE; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->cdb) ++ptp->in_err; ptp->cdb = (unsigned char *)cdb; ptp->cdb_len = cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->sense) ++ptp->in_err; memset(sense, 0, max_sense_len); ptp->sense = sense; ptp->sense_len = max_sense_len; } /* Setup for data transfer from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->dxferp = dxferp; ptp->dxfer_len = dxfer_len; ptp->dxfer_dir = CAM_DIR_IN; } } /* Setup for data transfer toward device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->dxferp = (unsigned char *)dxferp; ptp->dxfer_len = dxfer_len; ptp->dxfer_dir = CAM_DIR_OUT; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp __attribute__ ((unused)), int pack_id __attribute__ ((unused))) { } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag __attribute__ ((unused))) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code __attribute__ ((unused))) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib __attribute__ ((unused)), int priority __attribute__ ((unused))) { struct sg_pt_freebsd_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_flags(struct sg_pt_base * objp, int flags) { if (objp) { ; } /* unused, suppress warning */ if (flags) { ; } /* unused, suppress warning */ } /* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { int fd = device_fd - FREEBSD_FDOFFSET; struct sg_pt_freebsd_scsi * ptp = &vp->impl; struct freebsd_dev_channel *fdchan; union ccb *ccb; int len, timout_ms; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->cdb) { if (verbose) fprintf(sg_warnings_strm, "No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } if ((fd < 0) || (fd >= FREEBSD_MAXDEV)) { if (verbose) fprintf(sg_warnings_strm, "Bad file descriptor\n"); ptp->os_err = ENODEV; return -ptp->os_err; } fdchan = devicetable[fd]; if (NULL == fdchan) { if (verbose) fprintf(sg_warnings_strm, "File descriptor closed??\n"); ptp->os_err = ENODEV; return -ptp->os_err; } if (NULL == fdchan->cam_dev) { if (verbose) fprintf(sg_warnings_strm, "No open CAM device\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->ccb) { /* re-use if we have one already */ if (! (ccb = cam_getccb(fdchan->cam_dev))) { if (verbose) fprintf(sg_warnings_strm, "cam_getccb: failed\n"); ptp->os_err = ENOMEM; return -ptp->os_err; } ptp->ccb = ccb; } else ccb = ptp->ccb; // clear out structure, except for header that was filled in for us bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - sizeof(struct ccb_hdr)); timout_ms = (time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT; cam_fill_csio(&ccb->csio, /* retries */ 1, /* cbfcnp */ NULL, /* flags */ ptp->dxfer_dir, /* tagaction */ MSG_SIMPLE_Q_TAG, /* dataptr */ ptp->dxferp, /* datalen */ ptp->dxfer_len, /* senselen */ ptp->sense_len, /* cdblen */ ptp->cdb_len, /* timeout (millisecs) */ timout_ms); memcpy(ccb->csio.cdb_io.cdb_bytes, ptp->cdb, ptp->cdb_len); if (cam_send_ccb(fdchan->cam_dev, ccb) < 0) { if (verbose) { warn("error sending SCSI ccb"); #if __FreeBSD_version > 500000 cam_error_print(fdchan->cam_dev, ccb, CAM_ESF_ALL, CAM_EPF_ALL, stderr); #endif } cam_freeccb(ptp->ccb); ptp->ccb = NULL; ptp->os_err = EIO; return -ptp->os_err; } if (((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP) || ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR)) { ptp->scsi_status = ccb->csio.scsi_status; ptp->resid = ccb->csio.resid; ptp->sense_resid = ccb->csio.sense_resid; if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status)) { if (ptp->sense_resid > ptp->sense_len) len = ptp->sense_len; /* crazy; ignore sense_resid */ else len = ptp->sense_len - ptp->sense_resid; if (len > 0) memcpy(ptp->sense, &(ccb->csio.sense_data), len); } } else ptp->transport_err = 1; ptp->cam_dev = fdchan->cam_dev; // for error processing return 0; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->transport_err) return SCSI_PT_RESULT_TRANSPORT_ERR; else if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status)) return SCSI_PT_RESULT_SENSE; else if (ptp->scsi_status) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->scsi_status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (ptp->sense_resid > ptp->sense_len) return ptp->sense_len; /* strange; ignore ptp->sense_resid */ else return ptp->sense_len - ptp->sense_resid; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused))) { // const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return -1; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->transport_err; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; return ptp->os_err; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; if (0 == ptp->transport_err) { strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; return b; } #if __FreeBSD_version > 500000 if (ptp->cam_dev) cam_error_string(ptp->cam_dev, ptp->ccb, b, max_b_len, CAM_ESF_ALL, CAM_EPF_ALL); else { strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; } #else strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; #endif return b; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_freebsd_scsi * ptp = &vp->impl; const char * cp; cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } sg3_utils-1.40/lib/sg_lib_data.c0000664000175000017500000017070712430315266015530 0ustar douggdougg/* * Copyright (c) 2007-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include "sg_lib.h" #include "sg_lib_data.h" #ifdef HAVE_CONFIG_H #include "config.h" #else #define SG_SCSI_STRINGS 1 #endif const char * sg_lib_version_str = "2.08 20141110"; /* spc4r37a, sbc4r02 */ #ifdef SG_SCSI_STRINGS struct sg_lib_value_name_t sg_lib_normal_opcodes[] = { {0, 0, "Test Unit Ready"}, {0x1, 0, "Rezero Unit"}, {0x1, PDT_TAPE, "Rewind"}, {0x3, 0, "Request Sense"}, {0x4, 0, "Format Unit"}, {0x4, PDT_TAPE, "Format medium"}, {0x4, PDT_PRINTER, "Format"}, {0x5, 0, "Read Block Limits"}, {0x7, 0, "Reassign Blocks"}, {0x7, PDT_MCHANGER, "Initialize element status"}, {0x8, 0, "Read(6)"}, /* obsolete in sbc3r30 */ {0x8, PDT_PROCESSOR, "Receive"}, {0xa, 0, "Write(6)"}, /* obsolete in sbc3r30 */ {0xa, PDT_PRINTER, "Print"}, {0xa, PDT_PROCESSOR, "Send"}, {0xb, 0, "Seek(6)"}, {0xb, PDT_TAPE, "Set capacity"}, {0xb, PDT_PRINTER, "Slew and print"}, {0xf, 0, "Read reverse(6)"}, {0x10, 0, "Write filemarks(6)"}, {0x10, PDT_PRINTER, "Synchronize buffer"}, {0x11, 0, "Space(6)"}, {0x12, 0, "Inquiry"}, {0x13, 0, "Verify(6)"}, /* SSC */ {0x14, 0, "Recover buffered data"}, {0x15, 0, "Mode select(6)"}, /* SBC-3 r31 recommends Mode select(10) */ {0x16, 0, "Reserve(6)"}, /* obsolete in SPC-4 r11 */ {0x16, PDT_MCHANGER, "Reserve element(6)"}, {0x17, 0, "Release(6)"}, /* obsolete in SPC-4 r11 */ {0x17, PDT_MCHANGER, "Release element(6)"}, {0x18, 0, "Copy"}, /* obsolete in SPC-4 r11 */ {0x19, 0, "Erase(6)"}, {0x1a, 0, "Mode sense(6)"}, /* SBC-3 r31 recommends Mode sense(10) */ {0x1b, 0, "Start stop unit"}, {0x1b, PDT_TAPE, "Load unload"}, {0x1b, PDT_ADC, "Load unload"}, {0x1b, PDT_PRINTER, "Stop print"}, {0x1c, 0, "Receive diagnostic results"}, {0x1d, 0, "Send diagnostic"}, {0x1e, 0, "Prevent allow medium removal"}, {0x23, 0, "Read Format capacities"}, {0x24, 0, "Set window"}, {0x25, 0, "Read capacity(10)"}, /* SBC-3 r31 recommends Read capacity(16) */ {0x25, PDT_OCRW, "Read card capacity"}, {0x28, 0, "Read(10)"}, /* SBC-3 r31 recommends Read(16) */ {0x29, 0, "Read generation"}, {0x2a, 0, "Write(10)"}, /* SBC-3 r31 recommends Write(16) */ {0x2b, 0, "Seek(10)"}, {0x2b, PDT_TAPE, "Locate(10)"}, {0x2b, PDT_MCHANGER, "Position to element"}, {0x2c, 0, "Erase(10)"}, {0x2d, 0, "Read updated block"}, {0x2e, 0, "Write and verify(10)"}, /* SBC-3 r31 recommends Write and verify(16) */ {0x2f, 0, "Verify(10)"}, /* SBC-3 r31 recommends Verify(16) */ {0x30, 0, "Search data high(10)"}, {0x31, 0, "Search data equal(10)"}, {0x32, 0, "Search data low(10)"}, {0x33, 0, "Set limits(10)"}, {0x34, 0, "Pre-fetch(10)"}, /* SBC-3 r31 recommends Pre-fetch(16) */ {0x34, PDT_TAPE, "Read position"}, {0x35, 0, "Synchronize cache(10)"}, /* SBC-3 r31 recommends Synchronize cache(16) */ {0x36, 0, "Lock unlock cache(10)"}, {0x37, 0, "Read defect data(10)"}, /* SBC-3 r31 recommends Read defect data(12) */ {0x37, PDT_MCHANGER, "Initialize element status with range"}, {0x38, 0, "Medium scan"}, {0x39, 0, "Compare"}, /* obsolete in SPC-4 r11 */ {0x3a, 0, "Copy and verify"}, /* obsolete in SPC-4 r11 */ {0x3b, 0, "Write buffer"}, {0x3c, 0, "Read buffer"}, {0x3d, 0, "Update block"}, {0x3e, 0, "Read long(10)"}, /* SBC-3 r31 recommends Read long(16) */ {0x3f, 0, "Write long(10)"}, /* SBC-3 r31 recommends Write long(16) */ {0x40, 0, "Change definition"}, /* obsolete in SPC-4 r11 */ {0x41, 0, "Write same(10)"}, /* SBC-3 r31 recommends Write same(16) */ {0x42, 0, "Unmap"}, /* added SPC-4 rev 18 */ {0x42, PDT_MMC, "Read sub-channel"}, {0x43, PDT_MMC, "Read TOC/PMA/ATIP"}, {0x44, 0, "Report density support"}, {0x45, PDT_MMC, "Play audio(10)"}, {0x46, PDT_MMC, "Get configuration"}, {0x47, PDT_MMC, "Play audio msf"}, {0x48, 0, "Sanitize"}, {0x4a, PDT_MMC, "Get event status notification"}, {0x4b, PDT_MMC, "Pause/resume"}, {0x4c, 0, "Log select"}, {0x4d, 0, "Log sense"}, {0x4e, 0, "Stop play/scan"}, {0x50, 0, "Xdwrite(10)"}, /* obsolete in SBC-3 r31 */ {0x51, 0, "Xpwrite(10)"}, {0x51, PDT_MMC, "Read disk information"}, {0x52, 0, "Xdread(10)"}, /* obsolete in SBC-3 r31 */ {0x52, PDT_MMC, "Read track information"}, {0x53, 0, "Xdwriteread(10)"}, {0x54, 0, "Send OPC information"}, {0x55, 0, "Mode select(10)"}, {0x56, 0, "Reserve(10)"}, /* obsolete in SPC-4 r11 */ {0x56, PDT_MCHANGER, "Reserve element(10)"}, {0x57, 0, "Release(10)"}, /* obsolete in SPC-4 r11 */ {0x57, PDT_MCHANGER, "Release element(10)"}, {0x58, 0, "Repair track"}, {0x5a, 0, "Mode sense(10)"}, {0x5b, 0, "Close track/session"}, {0x5c, 0, "Read buffer capacity"}, {0x5d, 0, "Send cue sheet"}, {0x5e, 0, "Persistent reserve in"}, {0x5f, 0, "Persistent reserve out"}, {0x7e, 0, "Extended cdb (XCBD)"}, /* added in SPC-4 r12 */ {0x80, 0, "Xdwrite extended(16)"}, {0x80, PDT_TAPE, "Write filemarks(16)"}, {0x81, 0, "Rebuild(16)"}, {0x81, PDT_TAPE, "Read reverse(16)"}, {0x82, 0, "Regenerate(16)"}, {0x83, 0, "Third party copy out"}, /* Extended copy, before spc4r34 */ /* Following was "Receive copy results", before spc4r34 */ {0x84, 0, "Third party copy in"}, {0x85, 0, "ATA pass-through(16)"}, /* was 0x98 in spc3 rev21c */ {0x86, 0, "Access control in"}, {0x87, 0, "Access control out"}, {0x88, 0, "Read(16)"}, {0x89, 0, "Compare and write"}, {0x8a, 0, "Write(16)"}, {0x8b, 0, "Orwrite(16)"}, {0x8c, 0, "Read attribute"}, {0x8d, 0, "Write attribute"}, {0x8e, 0, "Write and verify(16)"}, {0x8f, 0, "Verify(16)"}, {0x90, 0, "Pre-fetch(16)"}, {0x91, 0, "Synchronize cache(16)"}, {0x91, PDT_TAPE, "Space(16)"}, {0x92, 0, "Lock unlock cache(16)"}, {0x92, PDT_TAPE, "Locate(16)"}, {0x93, 0, "Write same(16)"}, {0x93, PDT_TAPE, "Erase(16)"}, {0x9c, 0, "Write atomic(16)"}, {0x9d, 0, "Service action bidirectional"}, /* added spc4r35 */ {0x9e, 0, "Service action in(16)"}, {0x9f, 0, "Service action out(16)"}, {0xa0, 0, "Report luns"}, {0xa1, 0, "ATA pass-through(12)"}, {0xa1, PDT_MMC, "Blank"}, {0xa2, 0, "Security protocol in"}, {0xa3, 0, "Maintenance in"}, {0xa3, PDT_MMC, "Send key"}, {0xa4, 0, "Maintenance out"}, {0xa4, PDT_MMC, "Report key"}, {0xa5, 0, "Move medium"}, {0xa5, PDT_MMC, "Play audio(12)"}, {0xa6, 0, "Exchange medium"}, {0xa6, PDT_MMC, "Load/unload medium"}, {0xa7, 0, "Move medium attached"}, {0xa7, PDT_MMC, "Set read ahead"}, {0xa8, 0, "Read(12)"}, /* SBC-3 r31 recommends Read(16) */ {0xa9, 0, "Service action out(12)"}, {0xaa, 0, "Write(12)"}, /* SBC-3 r31 recommends Write(16) */ {0xab, 0, "Service action in(12)"}, {0xac, 0, "erase(12)"}, {0xac, PDT_MMC, "Get performance"}, {0xad, PDT_MMC, "Read DVD/BD structure"}, {0xae, 0, "Write and verify(12)"}, /* SBC-3 r31 recommends Write and verify(16) */ {0xaf, 0, "Verify(12)"}, /* SBC-3 r31 recommends Verify(16) */ {0xb0, 0, "Search data high(12)"}, {0xb1, 0, "Search data equal(12)"}, {0xb1, PDT_MCHANGER, "Open/close import/export element"}, {0xb2, 0, "Search data low(12)"}, {0xb3, 0, "Set limits(12)"}, {0xb4, 0, "Read element status attached"}, {0xb5, 0, "Security protocol out"}, {0xb5, PDT_MCHANGER, "Request volume element address"}, {0xb6, 0, "Send volume tag"}, {0xb6, PDT_MMC, "Set streaming"}, {0xb7, 0, "Read defect data(12)"}, {0xb8, 0, "Read element status"}, {0xb9, 0, "Read CD msf"}, {0xba, 0, "Redundancy group in"}, {0xba, PDT_MMC, "Scan"}, {0xbb, 0, "Redundancy group out"}, {0xbb, PDT_MMC, "Set CD speed"}, {0xbc, 0, "Spare in"}, {0xbd, 0, "Spare out"}, {0xbd, PDT_MMC, "Mechanism status"}, {0xbe, 0, "Volume set in"}, {0xbe, PDT_MMC, "Read CD"}, {0xbf, 0, "Volume set out"}, {0xbf, PDT_MMC, "Send DVD/BD structure"}, {0xffff, 0, NULL}, }; /* Read buffer [0x3c] service actions, need prefix */ struct sg_lib_value_name_t sg_lib_read_buff_arr[] = { {0x0, 0, "combined header and data [or multiple modes]"}, {0x2, 0, "data"}, {0x3, 0, "descriptor"}, {0xa, 0, "read data from echo buffer"}, {0xb, 0, "echo buffer descriptor"}, {0x1a, 0, "enable expander comms protocol and echo buffer"}, {0x1c, 0, "error history"}, {0xffff, 0, NULL}, }; /* Write buffer [0x3b] service actions, need prefix */ struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { {0x0, 0, "combined header and data [or multiple modes]"}, {0x2, 0, "data"}, {0x4, 0, "download microcode and activate"}, {0x5, 0, "download microcode, save, and activate"}, {0x6, 0, "download microcode with offsets and activate"}, {0x7, 0, "download microcode with offsets, save, and activate"}, {0xa, 0, "write data to echo buffer"}, {0xd, 0, "download microcode with offsets, select activation events, " "save and defer activate"}, {0xe, 0, "download microcode with offsets, save and defer activate"}, {0xf, 0, "activate deferred microcode"}, {0x1a, 0, "enable expander comms protocol and echo buffer"}, {0x1b, 0, "disable expander comms protocol"}, {0x1c, 0, "download application client error history"}, {0xffff, 0, NULL}, }; /* Maintenance in [0xa3] service actions */ struct sg_lib_value_name_t sg_lib_maint_in_arr[] = { {0x5, 0, "Report identifying information"}, /* was "Report device identifier" prior to spc4r07 */ {0xa, 0, "Report target port groups"}, {0xb, 0, "Report aliases"}, {0xc, 0, "Report supported operation codes"}, {0xd, 0, "Report supported task management functions"}, {0xe, 0, "Report priority"}, {0xf, 0, "Report timestamp"}, {0x10, 0, "Management protocol in"}, {0x1f, 0, "Maintenance in vendor specific"}, {0xffff, 0, NULL}, }; /* Maintenance out [0xa4] service actions */ struct sg_lib_value_name_t sg_lib_maint_out_arr[] = { {0x6, 0, "Set identifying information"}, /* was "Set device identifier" prior to spc4r07 */ {0xa, 0, "Set target port groups"}, {0xb, 0, "Change aliases"}, {0xc, 0, "Remove I_T nexus"}, {0xe, 0, "Set priority"}, {0xf, 0, "Set timestamp"}, {0x10, 0, "Management protocol out"}, {0x1f, 0, "Maintenance out vendor specific"}, {0xffff, 0, NULL}, }; /* Sanitize [0x48] service actions, need prefix */ struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = { {0x1, 0, "overwrite"}, {0x2, 0, "block erase"}, {0x3, 0, "cryptographic erase"}, {0x1f, 0, "exit failure mode"}, {0xffff, 0, NULL}, }; /* Service action in(12) [0xab] service actions */ struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { {0x1, 0, "Read media serial number"}, {0xffff, 0, NULL}, }; /* Service action out(12) [0xa9] service actions */ struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = { {0xff, 0, "Impossible command name"}, {0xffff, 0, NULL}, }; /* Service action in(16) [0x9e] service actions */ struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = { {0x10, 0, "Read capacity(16)"}, {0x11, 0, "Read long(16)"}, {0x12, 0, "Get LBA status"}, {0x13, 0, "Report referrals"}, {0x14, PDT_ZBC, "Report zones"}, {0xffff, 0, NULL}, }; /* Service action out(16) [0x9f] service actions */ struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = { {0x11, 0, "Write long(16)"}, {0x14, PDT_ZBC, "Reset write pointer"}, {0x1f, PDT_ADC, "Notify data transfer device(16)"}, {0xffff, 0, NULL}, }; /* Service action bidirectional [0x9d] service actions */ struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = { {0xffff, 0, NULL}, }; /* Persistent reserve in [0x5e] service actions, need prefix */ struct sg_lib_value_name_t sg_lib_pr_in_arr[] = { {0x0, 0, "read keys"}, {0x1, 0, "read reservation"}, {0x2, 0, "report capabilities"}, {0x3, 0, "read full status"}, {0xffff, 0, NULL}, }; /* Persistent reserve out [0x5f] service actions, need prefix */ struct sg_lib_value_name_t sg_lib_pr_out_arr[] = { {0x0, 0, "register"}, {0x1, 0, "reserve"}, {0x2, 0, "release"}, {0x3, 0, "clear"}, {0x4, 0, "preempt"}, {0x5, 0, "preempt and abort"}, {0x6, 0, "register and ignore existing key"}, {0x7, 0, "register and move"}, {0x8, 0, "replace lost reservation"}, {0xffff, 0, NULL}, }; /* Third party copy in [0x83] service actions * Opcode 'Receive copy results' was renamed 'Third party copy in' in spc4r34 * LID1 is an abbreviation of List Identifier length of 1 byte */ struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = { {0x0, 0, "Extended copy(LID1)"}, {0x1, 0, "Extended copy(LID4)"}, {0x10, 0, "Populate token"}, {0x11, 0, "Write using token"}, {0x1c, 0, "Copy operation abort"}, {0xffff, 0, NULL}, }; /* Third party copy out [0x84] service actions * Opcode 'Extended copy' was renamed 'Third party copy out' in spc4r34 * LID4 is an abbreviation of List Identifier length of 4 bytes */ struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = { {0x0, 0, "Receive copy status(LID1)"}, {0x1, 0, "Receive copy data(LID1)"}, {0x3, 0, "Receive copy operating parameters"}, {0x4, 0, "Receive copy failure details(LID1)"}, {0x5, 0, "Receive copy status(LID4)"}, {0x6, 0, "Receive copy data(LID4)"}, {0x7, 0, "Receive ROD token information"}, {0x8, 0, "Report all ROD tokens"}, {0xffff, 0, NULL}, }; /* Variable length cdb [0x7f] service actions (more than 16 bytes long) */ struct sg_lib_value_name_t sg_lib_variable_length_arr[] = { {0x1, 0, "Rebuild(32)"}, {0x2, 0, "Regenerate(32)"}, {0x3, 0, "Xdread(32)"}, /* obsolete in SBC-3 r31 */ {0x4, 0, "Xdwrite(32)"}, /* obsolete in SBC-3 r31 */ {0x5, 0, "Xdwrite extended(32)"}, {0x6, 0, "Xpwrite(32)"}, {0x7, 0, "Xdwriteread(32)"}, {0x8, 0, "Xdwrite extended(64)"}, {0x9, 0, "Read(32)"}, {0xa, 0, "Verify(32)"}, {0xb, 0, "Write(32)"}, {0xc, 0, "Write and verify(32)"}, {0xd, 0, "Write same(32)"}, {0xe, 0, "Orwrite(32)"}, /* added sbc3r25 */ {0xf, 0, "Atomic write(32)"}, /* added sbc4r02 */ {0x1800, 0, "Receive credential"}, {0x8801, 0, "Format OSD (osd)"}, {0x8802, 0, "Create (osd)"}, {0x8803, 0, "List (osd)"}, {0x8805, 0, "Read (osd)"}, {0x8806, 0, "Write (osd)"}, {0x8807, 0, "Append (osd)"}, {0x8808, 0, "Flush (osd)"}, {0x880a, 0, "Remove (osd)"}, {0x880b, 0, "Create partition (osd)"}, {0x880c, 0, "Remove partition (osd)"}, {0x880e, 0, "Get attributes (osd)"}, {0x880f, 0, "Set attributes (osd)"}, {0x8812, 0, "Create and write (osd)"}, {0x8815, 0, "Create collection (osd)"}, {0x8816, 0, "Remove collection (osd)"}, {0x8817, 0, "List collection (osd)"}, {0x8818, 0, "Set key (osd)"}, {0x8819, 0, "Set master key (osd)"}, {0x881a, 0, "Flush collection (osd)"}, {0x881b, 0, "Flush partition (osd)"}, {0x881c, 0, "Flush OSD (osd)"}, {0x8880, 0, "Object structure check (osd-2)"}, {0x8881, 0, "Format OSD (osd-2)"}, {0x8882, 0, "Create (osd-2)"}, {0x8883, 0, "List (osd-2)"}, {0x8884, 0, "Punch (osd-2)"}, {0x8885, 0, "Read (osd-2)"}, {0x8886, 0, "Write (osd-2)"}, {0x8887, 0, "Append (osd-2)"}, {0x8888, 0, "Flush (osd-2)"}, {0x8889, 0, "Clear (osd-2)"}, {0x888a, 0, "Remove (osd-2)"}, {0x888b, 0, "Create partition (osd-2)"}, {0x888c, 0, "Remove partition (osd-2)"}, {0x888e, 0, "Get attributes (osd-2)"}, {0x888f, 0, "Set attributes (osd-2)"}, {0x8892, 0, "Create and write (osd-2)"}, {0x8895, 0, "Create collection (osd-2)"}, {0x8896, 0, "Remove collection (osd-2)"}, {0x8897, 0, "List collection (osd-2)"}, {0x8898, 0, "Set key (osd-2)"}, {0x8899, 0, "Set master key (osd-2)"}, {0x889a, 0, "Flush collection (osd-2)"}, {0x889b, 0, "Flush partition (osd-2)"}, {0x889c, 0, "Flush OSD (osd-2)"}, {0x88a0, 0, "Query (osd-2)"}, {0x88a1, 0, "Remove member objects (osd-2)"}, {0x88a2, 0, "Get member attributes (osd-2)"}, {0x88a3, 0, "Set member attributes (osd-2)"}, {0x88b1, 0, "Read map (osd-2)"}, {0x8f7c, 0, "Perform SCSI command (osd-2)"}, {0x8f7d, 0, "Perform task management function (osd-2)"}, {0x8f7e, 0, "Perform SCSI command (osd)"}, {0x8f7f, 0, "Perform task management function (osd)"}, {0xffff, 0, NULL}, }; #else struct sg_lib_value_name_t sg_lib_normal_opcodes[] = { {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_read_buff_arr[] = { /* opcode 0x3c */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_write_buff_arr[] = { /* opcode 0x3b */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_maint_in_arr[] = { /* opcode 0xa3 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_maint_out_arr[] = { /* opcode 0xa4 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[] = { /* opcode 0x94 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_serv_in12_arr[] = { /* opcode 0xab */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_serv_out12_arr[] = { /* opcode 0xa9 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_serv_in16_arr[] = { /* opcode 0x9e */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_serv_out16_arr[] = { /* opcode 0x9f */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_serv_bidi_arr[] = { /* opcode 0x9d */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_pr_in_arr[] = { /* opcode 0x5e */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_pr_out_arr[] = { /* opcode 0x5f */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[] = { /* opcode 0x83 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[] = { /* opcode 0x84 */ {0xffff, 0, NULL}, }; struct sg_lib_value_name_t sg_lib_variable_length_arr[] = { {0xffff, 0, NULL}, }; #endif /* A conveniently formatted list of SCSI ASC/ASCQ codes and their * corresponding text can be found at: www.t10.org/lists/asc-num.txt * The following should match asc-num.txt dated 20140924 */ #ifdef SG_SCSI_STRINGS struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[] = { {0x40,0x01,0x7f,"Ram failure [0x%x]"}, {0x40,0x80,0xff,"Diagnostic failure on component [0x%x]"}, {0x41,0x01,0xff,"Data path failure [0x%x]"}, {0x42,0x01,0xff,"Power-on or self-test failure [0x%x]"}, {0x4d,0x00,0xff,"Tagged overlapped commands [0x%x]"}, {0x70,0x00,0xff,"Decompression exception short algorithm id of 0x%x"}, {0, 0, 0, NULL} }; struct sg_lib_asc_ascq_t sg_lib_asc_ascq[] = { {0x00,0x00,"No additional sense information"}, {0x00,0x01,"Filemark detected"}, {0x00,0x02,"End-of-partition/medium detected"}, {0x00,0x03,"Setmark detected"}, {0x00,0x04,"Beginning-of-partition/medium detected"}, {0x00,0x05,"End-of-data detected"}, {0x00,0x06,"I/O process terminated"}, {0x00,0x07,"Programmable early warning detected"}, {0x00,0x11,"Audio play operation in progress"}, {0x00,0x12,"Audio play operation paused"}, {0x00,0x13,"Audio play operation successfully completed"}, {0x00,0x14,"Audio play operation stopped due to error"}, {0x00,0x15,"No current audio status to return"}, {0x00,0x16,"operation in progress"}, {0x00,0x17,"Cleaning requested"}, {0x00,0x18,"Erase operation in progress"}, {0x00,0x19,"Locate operation in progress"}, {0x00,0x1a,"Rewind operation in progress"}, {0x00,0x1b,"Set capacity operation in progress"}, {0x00,0x1c,"Verify operation in progress"}, {0x00,0x1d,"ATA pass through information available"}, {0x00,0x1e,"Conflicting SA creation request"}, {0x00,0x1f,"Logical unit transitioning to another power condition"}, {0x00,0x20,"Extended copy information available"}, {0x00,0x21,"Atomic command aborted due to ACA"}, {0x01,0x00,"No index/sector signal"}, {0x02,0x00,"No seek complete"}, {0x03,0x00,"Peripheral device write fault"}, {0x03,0x01,"No write current"}, {0x03,0x02,"Excessive write errors"}, {0x04,0x00,"Logical unit not ready, cause not reportable"}, {0x04,0x01,"Logical unit is in process of becoming ready"}, {0x04,0x02,"Logical unit not ready, " "initializing command required"}, {0x04,0x03,"Logical unit not ready, " "manual intervention required"}, {0x04,0x04,"Logical unit not ready, format in progress"}, {0x04,0x05,"Logical unit not ready, rebuild in progress"}, {0x04,0x06,"Logical unit not ready, recalculation in progress"}, {0x04,0x07,"Logical unit not ready, operation in progress"}, {0x04,0x08,"Logical unit not ready, long write in progress"}, {0x04,0x09,"Logical unit not ready, self-test in progress"}, {0x04,0x0a,"Logical unit " "not accessible, asymmetric access state transition"}, {0x04,0x0b,"Logical unit " "not accessible, target port in standby state"}, {0x04,0x0c,"Logical unit " "not accessible, target port in unavailable state"}, {0x04,0x0d,"Logical unit not ready, structure check required"}, {0x04,0x0e,"Logical unit not ready, security session in progress"}, {0x04,0x10,"Logical unit not ready, " "auxiliary memory not accessible"}, {0x04,0x11,"Logical unit not ready, " "notify (enable spinup) required"}, {0x04,0x12,"Logical unit not ready, offline"}, {0x04,0x13,"Logical unit not ready, SA creation in progress"}, {0x04,0x14,"Logical unit not ready, space allocation in progress"}, {0x04,0x15,"Logical unit not ready, robotics disabled"}, {0x04,0x16,"Logical unit not ready, configuration required"}, {0x04,0x17,"Logical unit not ready, calibration required"}, {0x04,0x18,"Logical unit not ready, a door is open"}, {0x04,0x19,"Logical unit not ready, operating in sequential mode"}, {0x04,0x1a,"Logical unit not ready, start stop unit command in progress"}, {0x04,0x1b,"Logical unit not ready, sanitize in progress"}, {0x04,0x1c,"Logical unit not ready, additional power use not yet " "granted"}, {0x04,0x1d,"Logical unit not ready, configuration in progress"}, {0x04,0x1e,"Logical unit not ready, microcode activation required"}, {0x04,0x1f,"Logical unit not ready, microcode download required"}, {0x04,0x20,"Logical unit not ready, logical unit reset required"}, {0x04,0x21,"Logical unit not ready, hard reset required"}, {0x04,0x22,"Logical unit not ready, power cycle required"}, {0x05,0x00,"Logical unit does not respond to selection"}, {0x06,0x00,"No reference position found"}, {0x07,0x00,"Multiple peripheral devices selected"}, {0x08,0x00,"Logical unit communication failure"}, {0x08,0x01,"Logical unit communication time-out"}, {0x08,0x02,"Logical unit communication parity error"}, {0x08,0x03,"Logical unit communication CRC error (Ultra-DMA/32)"}, {0x08,0x04,"Unreachable copy target"}, {0x09,0x00,"Track following error"}, {0x09,0x01,"Tracking servo failure"}, {0x09,0x02,"Focus servo failure"}, {0x09,0x03,"Spindle servo failure"}, {0x09,0x04,"Head select fault"}, {0x09,0x05,"Vibration induced tracking error"}, {0x0A,0x00,"Error log overflow"}, {0x0B,0x00,"Warning"}, {0x0B,0x01,"Warning - specified temperature exceeded"}, {0x0B,0x02,"Warning - enclosure degraded"}, {0x0B,0x03,"Warning - background self-test failed"}, {0x0B,0x04,"Warning - background pre-scan detected medium error"}, {0x0B,0x05,"Warning - background medium scan detected medium error"}, {0x0B,0x06,"Warning - non-volatile cache now volatile"}, {0x0B,0x07,"Warning - degraded power to non-volatile cache"}, {0x0B,0x08,"Warning - power loss expected"}, {0x0B,0x09,"Warning - device statistics notification active"}, {0x0C,0x00,"Write error"}, {0x0C,0x01,"Write error - recovered with auto reallocation"}, {0x0C,0x02,"Write error - auto reallocation failed"}, {0x0C,0x03,"Write error - recommend reassignment"}, {0x0C,0x04,"Compression check miscompare error"}, {0x0C,0x05,"Data expansion occurred during compression"}, {0x0C,0x06,"Block not compressible"}, {0x0C,0x07,"Write error - recovery needed"}, {0x0C,0x08,"Write error - recovery failed"}, {0x0C,0x09,"Write error - loss of streaming"}, {0x0C,0x0A,"Write error - padding blocks added"}, {0x0C,0x0B,"Auxiliary memory write error"}, {0x0C,0x0C,"Write error - unexpected unsolicited data"}, {0x0C,0x0D,"Write error - not enough unsolicited data"}, {0x0C,0x0E,"Multiple write errors"}, {0x0C,0x0F,"Defects in error window"}, {0x0C,0x10,"Incomplete multiple atomic write operations"}, {0x0D,0x00,"Error detected by third party temporary initiator"}, {0x0D,0x01,"Third party device failure"}, {0x0D,0x02,"Copy target device not reachable"}, {0x0D,0x03,"Incorrect copy target device type"}, {0x0D,0x04,"Copy target device data underrun"}, {0x0D,0x05,"Copy target device data overrun"}, {0x0E,0x00,"Invalid information unit"}, {0x0E,0x01,"Information unit too short"}, {0x0E,0x02,"Information unit too long"}, {0x0E,0x03,"Invalid field in command information unit"}, {0x10,0x00,"Id CRC or ECC error"}, {0x10,0x01,"Logical block guard check failed"}, {0x10,0x02,"Logical block application tag check failed"}, {0x10,0x03,"Logical block reference tag check failed"}, {0x10,0x04,"Logical block protection error on recover buffered data"}, {0x10,0x05,"Logical block protection method error"}, {0x11,0x00,"Unrecovered read error"}, {0x11,0x01,"Read retries exhausted"}, {0x11,0x02,"Error too long to correct"}, {0x11,0x03,"Multiple read errors"}, {0x11,0x04,"Unrecovered read error - auto reallocate failed"}, {0x11,0x05,"L-EC uncorrectable error"}, {0x11,0x06,"CIRC unrecovered error"}, {0x11,0x07,"Data re-synchronization error"}, {0x11,0x08,"Incomplete block read"}, {0x11,0x09,"No gap found"}, {0x11,0x0A,"Miscorrected error"}, {0x11,0x0B,"Unrecovered read error - recommend reassignment"}, {0x11,0x0C,"Unrecovered read error - recommend rewrite the data"}, {0x11,0x0D,"De-compression CRC error"}, {0x11,0x0E,"Cannot decompress using declared algorithm"}, {0x11,0x0F,"Error reading UPC/EAN number"}, {0x11,0x10,"Error reading ISRC number"}, {0x11,0x11,"Read error - loss of streaming"}, {0x11,0x12,"Auxiliary memory read error"}, {0x11,0x13,"Read error - failed retransmission request"}, {0x11,0x14,"Read error - LBA marked bad by application client"}, {0x11,0x15,"Write after sanitize required"}, {0x12,0x00,"Address mark not found for id field"}, {0x13,0x00,"Address mark not found for data field"}, {0x14,0x00,"Recorded entity not found"}, {0x14,0x01,"Record not found"}, {0x14,0x02,"Filemark or setmark not found"}, {0x14,0x03,"End-of-data not found"}, {0x14,0x04,"Block sequence error"}, {0x14,0x05,"Record not found - recommend reassignment"}, {0x14,0x06,"Record not found - data auto-reallocated"}, {0x14,0x07,"Locate operation failure"}, {0x15,0x00,"Random positioning error"}, {0x15,0x01,"Mechanical positioning error"}, {0x15,0x02,"Positioning error detected by read of medium"}, {0x16,0x00,"Data synchronization mark error"}, {0x16,0x01,"Data sync error - data rewritten"}, {0x16,0x02,"Data sync error - recommend rewrite"}, {0x16,0x03,"Data sync error - data auto-reallocated"}, {0x16,0x04,"Data sync error - recommend reassignment"}, {0x17,0x00,"Recovered data with no error correction applied"}, {0x17,0x01,"Recovered data with retries"}, {0x17,0x02,"Recovered data with positive head offset"}, {0x17,0x03,"Recovered data with negative head offset"}, {0x17,0x04,"Recovered data with retries and/or circ applied"}, {0x17,0x05,"Recovered data using previous sector id"}, {0x17,0x06,"Recovered data without ECC - data auto-reallocated"}, {0x17,0x07,"Recovered data without ECC - recommend reassignment"}, {0x17,0x08,"Recovered data without ECC - recommend rewrite"}, {0x17,0x09,"Recovered data without ECC - data rewritten"}, {0x18,0x00,"Recovered data with error correction applied"}, {0x18,0x01,"Recovered data with error corr. & retries applied"}, {0x18,0x02,"Recovered data - data auto-reallocated"}, {0x18,0x03,"Recovered data with CIRC"}, {0x18,0x04,"Recovered data with L-EC"}, {0x18,0x05,"Recovered data - recommend reassignment"}, {0x18,0x06,"Recovered data - recommend rewrite"}, {0x18,0x07,"Recovered data with ECC - data rewritten"}, {0x18,0x08,"Recovered data with linking"}, {0x19,0x00,"Defect list error"}, {0x19,0x01,"Defect list not available"}, {0x19,0x02,"Defect list error in primary list"}, {0x19,0x03,"Defect list error in grown list"}, {0x1A,0x00,"Parameter list length error"}, {0x1B,0x00,"Synchronous data transfer error"}, {0x1C,0x00,"Defect list not found"}, {0x1C,0x01,"Primary defect list not found"}, {0x1C,0x02,"Grown defect list not found"}, {0x1D,0x00,"Miscompare during verify operation"}, {0x1D,0x01,"Miscompare verify of unmapped lba"}, {0x1E,0x00,"Recovered id with ECC correction"}, {0x1F,0x00,"Partial defect list transfer"}, {0x20,0x00,"Invalid command operation code"}, {0x20,0x01,"Access denied - initiator pending-enrolled"}, {0x20,0x02,"Access denied - no access rights"}, {0x20,0x03,"Access denied - invalid mgmt id key"}, {0x20,0x04,"Illegal command while in write capable state"}, {0x20,0x05,"Write type operation while in read capable state (obs)"}, {0x20,0x06,"Illegal command while in explicit address mode"}, {0x20,0x07,"Illegal command while in implicit address mode"}, {0x20,0x08,"Access denied - enrollment conflict"}, {0x20,0x09,"Access denied - invalid LU identifier"}, {0x20,0x0A,"Access denied - invalid proxy token"}, {0x20,0x0B,"Access denied - ACL LUN conflict"}, {0x20,0x0C,"Illegal command when not in append-only mode"}, {0x21,0x00,"Logical block address out of range"}, {0x21,0x01,"Invalid element address"}, {0x21,0x02,"Invalid address for write"}, {0x21,0x03,"Invalid write crossing layer jump"}, {0x21,0x04,"Unaligned write command"}, {0x21,0x05,"Write boundary violation"}, {0x21,0x06,"Attempt to read invalid data"}, {0x21,0x07,"Read boundary violation"}, {0x22,0x00,"Illegal function (use 20 00, 24 00, or 26 00)"}, {0x23,0x00,"Invalid token operation, cause not reportable"}, {0x23,0x01,"Invalid token operation, unsupported token type"}, {0x23,0x02,"Invalid token operation, remote token usage not supported"}, {0x23,0x03,"invalid token operation, remote rod token creation not " "supported"}, {0x23,0x04,"Invalid token operation, token unknown"}, {0x23,0x05,"Invalid token operation, token corrupt"}, {0x23,0x06,"Invalid token operation, token revoked"}, {0x23,0x07,"Invalid token operation, token expired"}, {0x23,0x08,"Invalid token operation, token cancelled"}, {0x23,0x09,"Invalid token operation, token deleted"}, {0x23,0x0a,"Invalid token operation, invalid token length"}, {0x24,0x00,"Invalid field in cdb"}, {0x24,0x01,"CDB decryption error"}, {0x24,0x02,"Invalid cdb field while in explicit block model (obs)"}, {0x24,0x03,"Invalid cdb field while in implicit block model (obs)"}, {0x24,0x04,"Security audit value frozen"}, {0x24,0x05,"Security working key frozen"}, {0x24,0x06,"Nonce not unique"}, {0x24,0x07,"Nonce timestamp out of range"}, {0x24,0x08,"Invalid xcdb"}, {0x25,0x00,"Logical unit not supported"}, {0x26,0x00,"Invalid field in parameter list"}, {0x26,0x01,"Parameter not supported"}, {0x26,0x02,"Parameter value invalid"}, {0x26,0x03,"Threshold parameters not supported"}, {0x26,0x04,"Invalid release of persistent reservation"}, {0x26,0x05,"Data decryption error"}, {0x26,0x06,"Too many target descriptors"}, {0x26,0x07,"Unsupported target descriptor type code"}, {0x26,0x08,"Too many segment descriptors"}, {0x26,0x09,"Unsupported segment descriptor type code"}, {0x26,0x0A,"Unexpected inexact segment"}, {0x26,0x0B,"Inline data length exceeded"}, {0x26,0x0C,"Invalid operation for copy source or destination"}, {0x26,0x0D,"Copy segment granularity violation"}, {0x26,0x0E,"Invalid parameter while port is enabled"}, {0x26,0x0F,"Invalid data-out buffer integrity check value"}, {0x26,0x10,"Data decryption key fail limit reached"}, {0x26,0x11,"Incomplete key-associated data set"}, {0x26,0x12,"Vendor specific key reference not found"}, {0x27,0x00,"Write protected"}, {0x27,0x01,"Hardware write protected"}, {0x27,0x02,"Logical unit software write protected"}, {0x27,0x03,"Associated write protect"}, {0x27,0x04,"Persistent write protect"}, {0x27,0x05,"Permanent write protect"}, {0x27,0x06,"Conditional write protect"}, {0x27,0x07,"Space allocation failed write protect"}, {0x27,0x08,"Zone is read only"}, {0x28,0x00,"Not ready to ready change, medium may have changed"}, {0x28,0x01,"Import or export element accessed"}, {0x28,0x02,"Format-layer may have changed"}, {0x28,0x03,"Import/export element accessed, medium changed"}, {0x29,0x00,"Power on, reset, or bus device reset occurred"}, {0x29,0x01,"Power on occurred"}, {0x29,0x02,"SCSI bus reset occurred"}, {0x29,0x03,"Bus device reset function occurred"}, {0x29,0x04,"Device internal reset"}, {0x29,0x05,"Transceiver mode changed to single-ended"}, {0x29,0x06,"Transceiver mode changed to lvd"}, {0x29,0x07,"I_T nexus loss occurred"}, {0x2A,0x00,"Parameters changed"}, {0x2A,0x01,"Mode parameters changed"}, {0x2A,0x02,"Log parameters changed"}, {0x2A,0x03,"Reservations preempted"}, {0x2A,0x04,"Reservations released"}, {0x2A,0x05,"Registrations preempted"}, {0x2A,0x06,"Asymmetric access state changed"}, {0x2A,0x07,"Implicit asymmetric access state transition failed"}, {0x2A,0x08,"Priority changed"}, {0x2A,0x09,"Capacity data has changed"}, {0x2A,0x0c, "Error recovery attributes have changed"}, {0x2A,0x0d, "Data encryption capabilities changed"}, {0x2A,0x10,"Timestamp changed"}, {0x2A,0x11,"Data encryption parameters changed by another i_t nexus"}, {0x2A,0x12,"Data encryption parameters changed by vendor specific event"}, {0x2A,0x13,"Data encryption key instance counter has changed"}, {0x2A,0x0a,"Error history i_t nexus cleared"}, {0x2A,0x0b,"Error history snapshot released"}, {0x2A,0x14,"SA creation capabilities data has changed"}, {0x2A,0x15,"Medium removal prevention preempted"}, {0x2B,0x00,"Copy cannot execute since host cannot disconnect"}, {0x2C,0x00,"Command sequence error"}, {0x2C,0x01,"Too many windows specified"}, {0x2C,0x02,"Invalid combination of windows specified"}, {0x2C,0x03,"Current program area is not empty"}, {0x2C,0x04,"Current program area is empty"}, {0x2C,0x05,"Illegal power condition request"}, {0x2C,0x06,"Persistent prevent conflict"}, {0x2C,0x07,"Previous busy status"}, {0x2C,0x08,"Previous task set full status"}, {0x2C,0x09,"Previous reservation conflict status"}, {0x2C,0x0A,"Partition or collection contains user objects"}, {0x2C,0x0B,"Not reserved"}, {0x2C,0x0C,"ORWRITE generation does not match"}, {0x2D,0x00,"Overwrite error on update in place"}, {0x2E,0x00,"Insufficient time for operation"}, {0x2E,0x01,"Command timeout before processing"}, {0x2E,0x02,"Command timeout during processing"}, {0x2E,0x03,"Command timeout during processing due to error recovery"}, {0x2F,0x00,"Commands cleared by another initiator"}, {0x2F,0x01,"Commands cleared by power loss notification"}, {0x2F,0x02,"Commands cleared by device server"}, {0x2F,0x03,"Some commands cleared by queuing layer event"}, {0x30,0x00,"Incompatible medium installed"}, {0x30,0x01,"Cannot read medium - unknown format"}, {0x30,0x02,"Cannot read medium - incompatible format"}, {0x30,0x03,"Cleaning cartridge installed"}, {0x30,0x04,"Cannot write medium - unknown format"}, {0x30,0x05,"Cannot write medium - incompatible format"}, {0x30,0x06,"Cannot format medium - incompatible medium"}, {0x30,0x07,"Cleaning failure"}, {0x30,0x08,"Cannot write - application code mismatch"}, {0x30,0x09,"Current session not fixated for append"}, {0x30,0x0A,"Cleaning request rejected"}, {0x30,0x0B,"Cleaning tape expired"}, {0x30,0x0C,"WORM medium - overwrite attempted"}, {0x30,0x0D,"WORM medium - integrity check"}, {0x30,0x10,"Medium not formatted"}, {0x30,0x11,"Incompatible volume type"}, {0x30,0x12,"Incompatible volume qualifier"}, {0x30,0x13,"Cleaning volume expired"}, {0x31,0x00,"Medium format corrupted"}, {0x31,0x01,"Format command failed"}, {0x31,0x02,"Zoned formatting failed due to spare linking"}, {0x31,0x03,"Sanitize command failed"}, {0x32,0x00,"No defect spare location available"}, {0x32,0x01,"Defect list update failure"}, {0x33,0x00,"Tape length error"}, {0x34,0x00,"Enclosure failure"}, {0x35,0x00,"Enclosure services failure"}, {0x35,0x01,"Unsupported enclosure function"}, {0x35,0x02,"Enclosure services unavailable"}, {0x35,0x03,"Enclosure services transfer failure"}, {0x35,0x04,"Enclosure services transfer refused"}, {0x35,0x05,"Enclosure services checksum error"}, {0x36,0x00,"Ribbon, ink, or toner failure"}, {0x37,0x00,"Rounded parameter"}, {0x38,0x00,"Event status notification"}, {0x38,0x02,"Esn - power management class event"}, {0x38,0x04,"Esn - media class event"}, {0x38,0x06,"Esn - device busy class event"}, {0x38,0x07,"Thin provisioning soft threshold reached"}, {0x39,0x00,"Saving parameters not supported"}, {0x3A,0x00,"Medium not present"}, {0x3A,0x01,"Medium not present - tray closed"}, {0x3A,0x02,"Medium not present - tray open"}, {0x3A,0x03,"Medium not present - loadable"}, {0x3A,0x04,"Medium not present - medium auxiliary memory accessible"}, {0x3B,0x00,"Sequential positioning error"}, {0x3B,0x01,"Tape position error at beginning-of-medium"}, {0x3B,0x02,"Tape position error at end-of-medium"}, {0x3B,0x03,"Tape or electronic vertical forms unit not ready"}, {0x3B,0x04,"Slew failure"}, {0x3B,0x05,"Paper jam"}, {0x3B,0x06,"Failed to sense top-of-form"}, {0x3B,0x07,"Failed to sense bottom-of-form"}, {0x3B,0x08,"Reposition error"}, {0x3B,0x09,"Read past end of medium"}, {0x3B,0x0A,"Read past beginning of medium"}, {0x3B,0x0B,"Position past end of medium"}, {0x3B,0x0C,"Position past beginning of medium"}, {0x3B,0x0D,"Medium destination element full"}, {0x3B,0x0E,"Medium source element empty"}, {0x3B,0x0F,"End of medium reached"}, {0x3B,0x11,"Medium magazine not accessible"}, {0x3B,0x12,"Medium magazine removed"}, {0x3B,0x13,"Medium magazine inserted"}, {0x3B,0x14,"Medium magazine locked"}, {0x3B,0x15,"Medium magazine unlocked"}, {0x3B,0x16,"Mechanical positioning or changer error"}, {0x3B,0x17,"Read past end of user object"}, {0x3B,0x18,"Element disabled"}, {0x3B,0x19,"Element enabled"}, {0x3B,0x1a,"Data transfer device removed"}, {0x3B,0x1b,"Data transfer device inserted"}, {0x3B,0x1c,"Too many logical objects on partition to support operation"}, {0x3D,0x00,"Invalid bits in identify message"}, {0x3E,0x00,"Logical unit has not self-configured yet"}, {0x3E,0x01,"Logical unit failure"}, {0x3E,0x02,"Timeout on logical unit"}, {0x3E,0x03,"Logical unit failed self-test"}, {0x3E,0x04,"Logical unit unable to update self-test log"}, {0x3F,0x00,"Target operating conditions have changed"}, {0x3F,0x01,"Microcode has been changed"}, {0x3F,0x02,"Changed operating definition"}, {0x3F,0x03,"Inquiry data has changed"}, {0x3F,0x04,"Component device attached"}, {0x3F,0x05,"Device identifier changed"}, {0x3F,0x06,"Redundancy group created or modified"}, {0x3F,0x07,"Redundancy group deleted"}, {0x3F,0x08,"Spare created or modified"}, {0x3F,0x09,"Spare deleted"}, {0x3F,0x0A,"Volume set created or modified"}, {0x3F,0x0B,"Volume set deleted"}, {0x3F,0x0C,"Volume set deassigned"}, {0x3F,0x0D,"Volume set reassigned"}, {0x3F,0x0E,"Reported luns data has changed"}, {0x3F,0x0F,"Echo buffer overwritten"}, {0x3F,0x10,"Medium loadable"}, {0x3F,0x11,"Medium auxiliary memory accessible"}, {0x3F,0x12,"iSCSI IP address added"}, {0x3F,0x13,"iSCSI IP address removed"}, {0x3F,0x14,"iSCSI IP address changed"}, {0x3F,0x15,"Inspect referrals sense descriptors"}, {0x3F,0x16,"Microcode has been changed without reset"}, /* * ASC 0x40, 0x41 and 0x42 overridden by "additional2" array entries * for ascq > 1. Preferred error message for this group is * "Diagnostic failure on component nn (80h-ffh)". */ {0x40,0x00,"Ram failure (should use 40 nn)"}, {0x41,0x00,"Data path failure (should use 40 nn)"}, {0x42,0x00,"Power-on or self-test failure (should use 40 nn)"}, {0x43,0x00,"Message error"}, {0x44,0x00,"Internal target failure"}, {0x44,0x01,"Persistent reservation information lost"}, {0x44,0x71,"ATA device failed Set Features"}, {0x45,0x00,"Select or reselect failure"}, {0x46,0x00,"Unsuccessful soft reset"}, {0x47,0x00,"SCSI parity error"}, {0x47,0x01,"Data phase CRC error detected"}, {0x47,0x02,"SCSI parity error detected during st data phase"}, {0x47,0x03,"Information unit iuCRC error detected"}, {0x47,0x04,"Asynchronous information protection error detected"}, {0x47,0x05,"Protocol service CRC error"}, {0x47,0x06,"Phy test function in progress"}, {0x47,0x7F,"Some commands cleared by iSCSI protocol event"}, {0x48,0x00,"Initiator detected error message received"}, {0x49,0x00,"Invalid message error"}, {0x4A,0x00,"Command phase error"}, {0x4B,0x00,"Data phase error"}, {0x4B,0x01,"Invalid target port transfer tag received"}, {0x4B,0x02,"Too much write data"}, {0x4B,0x03,"Ack/nak timeout"}, {0x4B,0x04,"Nak received"}, {0x4B,0x05,"Data offset error"}, {0x4B,0x06,"Initiator response timeout"}, {0x4B,0x07,"Connection lost"}, {0x4B,0x08,"Data-in buffer overflow - data buffer size"}, {0x4B,0x09,"Data-in buffer overflow - data buffer descriptor area"}, {0x4B,0x0A,"Data-in buffer error"}, {0x4B,0x0B,"Data-out buffer overflow - data buffer size"}, {0x4B,0x0C,"Data-out buffer overflow - data buffer descriptor area"}, {0x4B,0x0D,"Data-out buffer error"}, {0x4B,0x0E,"PCIe fabric error"}, {0x4B,0x0f,"PCIe completion timeout"}, {0x4B,0x10,"PCIe completer abort"}, {0x4B,0x11,"PCIe poisoned tlp received"}, {0x4B,0x12,"PCIe ecrc check failed"}, {0x4B,0x13,"PCIe unsupported request"}, {0x4B,0x14,"PCIe acs violation"}, {0x4B,0x15,"PCIe tlp prefix blocked"}, {0x4C,0x00,"Logical unit failed self-configuration"}, /* * ASC 0x4D overridden by an "additional2" array entry * so there is no need to have them here. */ /* {0x4D,0x00,"Tagged overlapped commands (nn = queue tag)"}, */ {0x4E,0x00,"Overlapped commands attempted"}, {0x50,0x00,"Write append error"}, {0x50,0x01,"Write append position error"}, {0x50,0x02,"Position error related to timing"}, {0x51,0x00,"Erase failure"}, {0x51,0x01,"Erase failure - incomplete erase operation detected"}, {0x52,0x00,"Cartridge fault"}, {0x53,0x00,"Media load or eject failed"}, {0x53,0x01,"Unload tape failure"}, {0x53,0x02,"Medium removal prevented"}, {0x53,0x03,"Medium removal prevented by data transfer element"}, {0x53,0x04,"Medium thread or unthread failure"}, {0x53,0x05,"Volume identifier invalid"}, {0x53,0x06,"Volume identifier missing"}, {0x53,0x07,"Duplicate volume identifier"}, {0x53,0x08,"Element status unknown"}, {0x53,0x09,"Data transfer device error - load failed"}, {0x53,0x0A,"Data transfer device error - unload failed"}, {0x53,0x0B,"Data transfer device error - unload missing"}, {0x53,0x0C,"Data transfer device error - eject failed"}, {0x53,0x0D,"Data transfer device error - library communication failed"}, {0x54,0x00,"SCSI to host system interface failure"}, {0x55,0x00,"System resource failure"}, {0x55,0x01,"System buffer full"}, {0x55,0x02,"Insufficient reservation resources"}, {0x55,0x03,"Insufficient resources"}, {0x55,0x04,"Insufficient registration resources"}, {0x55,0x05,"Insufficient access control resources"}, {0x55,0x06,"Auxiliary memory out of space"}, {0x55,0x07,"Quota error"}, {0x55,0x08,"Maximum number of supplemental decryption keys exceeded"}, {0x55,0x09,"Medium auxiliary memory not accessible"}, {0x55,0x0a,"Data currently unavailable"}, {0x55,0x0b,"Insufficient power for operation"}, {0x55,0x0c,"Insufficient resources to create rod"}, {0x55,0x0d,"Insufficient resources to create rod token"}, {0x57,0x00,"Unable to recover table-of-contents"}, {0x58,0x00,"Generation does not exist"}, {0x59,0x00,"Updated block read"}, {0x5A,0x00,"Operator request or state change input"}, {0x5A,0x01,"Operator medium removal request"}, {0x5A,0x02,"Operator selected write protect"}, {0x5A,0x03,"Operator selected write permit"}, {0x5B,0x00,"Log exception"}, {0x5B,0x01,"Threshold condition met"}, {0x5B,0x02,"Log counter at maximum"}, {0x5B,0x03,"Log list codes exhausted"}, {0x5C,0x00,"Rpl status change"}, {0x5C,0x01,"Spindles synchronized"}, {0x5C,0x02,"Spindles not synchronized"}, {0x5D,0x00,"Failure prediction threshold exceeded"}, {0x5D,0x01,"Media failure prediction threshold exceeded"}, {0x5D,0x02,"Logical unit failure prediction threshold exceeded"}, {0x5D,0x03,"spare area exhaustion prediction threshold exceeded"}, {0x5D,0x10,"Hardware impending failure general hard drive failure"}, {0x5D,0x11,"Hardware impending failure drive error rate too high" }, {0x5D,0x12,"Hardware impending failure data error rate too high" }, {0x5D,0x13,"Hardware impending failure seek error rate too high" }, {0x5D,0x14,"Hardware impending failure too many block reassigns"}, {0x5D,0x15,"Hardware impending failure access times too high" }, {0x5D,0x16,"Hardware impending failure start unit times too high" }, {0x5D,0x17,"Hardware impending failure channel parametrics"}, {0x5D,0x18,"Hardware impending failure controller detected"}, {0x5D,0x19,"Hardware impending failure throughput performance"}, {0x5D,0x1A,"Hardware impending failure seek time performance"}, {0x5D,0x1B,"Hardware impending failure spin-up retry count"}, {0x5D,0x1C,"Hardware impending failure drive calibration retry count"}, {0x5D,0x20,"Controller impending failure general hard drive failure"}, {0x5D,0x21,"Controller impending failure drive error rate too high" }, {0x5D,0x22,"Controller impending failure data error rate too high" }, {0x5D,0x23,"Controller impending failure seek error rate too high" }, {0x5D,0x24,"Controller impending failure too many block reassigns"}, {0x5D,0x25,"Controller impending failure access times too high" }, {0x5D,0x26,"Controller impending failure start unit times too high" }, {0x5D,0x27,"Controller impending failure channel parametrics"}, {0x5D,0x28,"Controller impending failure controller detected"}, {0x5D,0x29,"Controller impending failure throughput performance"}, {0x5D,0x2A,"Controller impending failure seek time performance"}, {0x5D,0x2B,"Controller impending failure spin-up retry count"}, {0x5D,0x2C,"Controller impending failure drive calibration retry count"}, {0x5D,0x30,"Data channel impending failure general hard drive failure"}, {0x5D,0x31,"Data channel impending failure drive error rate too high" }, {0x5D,0x32,"Data channel impending failure data error rate too high" }, {0x5D,0x33,"Data channel impending failure seek error rate too high" }, {0x5D,0x34,"Data channel impending failure too many block reassigns"}, {0x5D,0x35,"Data channel impending failure access times too high" }, {0x5D,0x36,"Data channel impending failure start unit times too high" }, {0x5D,0x37,"Data channel impending failure channel parametrics"}, {0x5D,0x38,"Data channel impending failure controller detected"}, {0x5D,0x39,"Data channel impending failure throughput performance"}, {0x5D,0x3A,"Data channel impending failure seek time performance"}, {0x5D,0x3B,"Data channel impending failure spin-up retry count"}, {0x5D,0x3C,"Data channel impending failure drive calibration retry count"}, {0x5D,0x40,"Servo impending failure general hard drive failure"}, {0x5D,0x41,"Servo impending failure drive error rate too high" }, {0x5D,0x42,"Servo impending failure data error rate too high" }, {0x5D,0x43,"Servo impending failure seek error rate too high" }, {0x5D,0x44,"Servo impending failure too many block reassigns"}, {0x5D,0x45,"Servo impending failure access times too high" }, {0x5D,0x46,"Servo impending failure start unit times too high" }, {0x5D,0x47,"Servo impending failure channel parametrics"}, {0x5D,0x48,"Servo impending failure controller detected"}, {0x5D,0x49,"Servo impending failure throughput performance"}, {0x5D,0x4A,"Servo impending failure seek time performance"}, {0x5D,0x4B,"Servo impending failure spin-up retry count"}, {0x5D,0x4C,"Servo impending failure drive calibration retry count"}, {0x5D,0x50,"Spindle impending failure general hard drive failure"}, {0x5D,0x51,"Spindle impending failure drive error rate too high" }, {0x5D,0x52,"Spindle impending failure data error rate too high" }, {0x5D,0x53,"Spindle impending failure seek error rate too high" }, {0x5D,0x54,"Spindle impending failure too many block reassigns"}, {0x5D,0x55,"Spindle impending failure access times too high" }, {0x5D,0x56,"Spindle impending failure start unit times too high" }, {0x5D,0x57,"Spindle impending failure channel parametrics"}, {0x5D,0x58,"Spindle impending failure controller detected"}, {0x5D,0x59,"Spindle impending failure throughput performance"}, {0x5D,0x5A,"Spindle impending failure seek time performance"}, {0x5D,0x5B,"Spindle impending failure spin-up retry count"}, {0x5D,0x5C,"Spindle impending failure drive calibration retry count"}, {0x5D,0x60,"Firmware impending failure general hard drive failure"}, {0x5D,0x61,"Firmware impending failure drive error rate too high" }, {0x5D,0x62,"Firmware impending failure data error rate too high" }, {0x5D,0x63,"Firmware impending failure seek error rate too high" }, {0x5D,0x64,"Firmware impending failure too many block reassigns"}, {0x5D,0x65,"Firmware impending failure access times too high" }, {0x5D,0x66,"Firmware impending failure start unit times too high" }, {0x5D,0x67,"Firmware impending failure channel parametrics"}, {0x5D,0x68,"Firmware impending failure controller detected"}, {0x5D,0x69,"Firmware impending failure throughput performance"}, {0x5D,0x6A,"Firmware impending failure seek time performance"}, {0x5D,0x6B,"Firmware impending failure spin-up retry count"}, {0x5D,0x6C,"Firmware impending failure drive calibration retry count"}, {0x5D,0xFF,"Failure prediction threshold exceeded (false)"}, {0x5E,0x00,"Low power condition on"}, {0x5E,0x01,"Idle condition activated by timer"}, {0x5E,0x02,"Standby condition activated by timer"}, {0x5E,0x03,"Idle condition activated by command"}, {0x5E,0x04,"Standby condition activated by command"}, {0x5E,0x05,"Idle_b condition activated by timer"}, {0x5E,0x06,"Idle_b condition activated by command"}, {0x5E,0x07,"Idle_c condition activated by timer"}, {0x5E,0x08,"Idle_c condition activated by command"}, {0x5E,0x09,"Standby_y condition activated by timer"}, {0x5E,0x0a,"Standby_y condition activated by command"}, {0x5E,0x41,"Power state change to active"}, {0x5E,0x42,"Power state change to idle"}, {0x5E,0x43,"Power state change to standby"}, {0x5E,0x45,"Power state change to sleep"}, {0x5E,0x47,"Power state change to device control"}, {0x60,0x00,"Lamp failure"}, {0x61,0x00,"Video acquisition error"}, {0x61,0x01,"Unable to acquire video"}, {0x61,0x02,"Out of focus"}, {0x62,0x00,"Scan head positioning error"}, {0x63,0x00,"End of user area encountered on this track"}, {0x63,0x01,"Packet does not fit in available space"}, {0x64,0x00,"Illegal mode for this track"}, {0x64,0x01,"Invalid packet size"}, {0x65,0x00,"Voltage fault"}, {0x66,0x00,"Automatic document feeder cover up"}, {0x66,0x01,"Automatic document feeder lift up"}, {0x66,0x02,"Document jam in automatic document feeder"}, {0x66,0x03,"Document miss feed automatic in document feeder"}, {0x67,0x00,"Configuration failure"}, {0x67,0x01,"Configuration of incapable logical units failed"}, {0x67,0x02,"Add logical unit failed"}, {0x67,0x03,"Modification of logical unit failed"}, {0x67,0x04,"Exchange of logical unit failed"}, {0x67,0x05,"Remove of logical unit failed"}, {0x67,0x06,"Attachment of logical unit failed"}, {0x67,0x07,"Creation of logical unit failed"}, {0x67,0x08,"Assign failure occurred"}, {0x67,0x09,"Multiply assigned logical unit"}, {0x67,0x0A,"Set target port groups command failed"}, {0x67,0x0B,"ATA device feature not enabled"}, {0x68,0x00,"Logical unit not configured"}, {0x68,0x01,"Subsidiary logical unit not configured"}, {0x69,0x00,"Data loss on logical unit"}, {0x69,0x01,"Multiple logical unit failures"}, {0x69,0x02,"Parity/data mismatch"}, {0x6A,0x00,"Informational, refer to log"}, {0x6B,0x00,"State change has occurred"}, {0x6B,0x01,"Redundancy level got better"}, {0x6B,0x02,"Redundancy level got worse"}, {0x6C,0x00,"Rebuild failure occurred"}, {0x6D,0x00,"Recalculate failure occurred"}, {0x6E,0x00,"Command to logical unit failed"}, {0x6F,0x00,"Copy protection key exchange failure - authentication " "failure"}, {0x6F,0x01,"Copy protection key exchange failure - key not present"}, {0x6F,0x02,"Copy protection key exchange failure - key not established"}, {0x6F,0x03,"Read of scrambled sector without authentication"}, {0x6F,0x04,"Media region code is mismatched to logical unit region"}, {0x6F,0x05,"Drive region must be permanent/region reset count error"}, {0x6F,0x06,"Insufficient block count for binding nonce recording"}, {0x6F,0x07,"Conflict in binding nonce recording"}, /* * ASC 0x70 overridden by an "additional2" array entry * so there is no need to have them here. */ /* {0x70,0x00,"Decompression exception short algorithm id of nn"}, */ {0x71,0x00,"Decompression exception long algorithm id"}, {0x72,0x00,"Session fixation error"}, {0x72,0x01,"Session fixation error writing lead-in"}, {0x72,0x02,"Session fixation error writing lead-out"}, {0x72,0x03,"Session fixation error - incomplete track in session"}, {0x72,0x04,"Empty or partially written reserved track"}, {0x72,0x05,"No more track reservations allowed"}, {0x72,0x06,"RMZ extension is not allowed"}, {0x72,0x07,"No more test zone extensions are allowed"}, {0x73,0x00,"CD control error"}, {0x73,0x01,"Power calibration area almost full"}, {0x73,0x02,"Power calibration area is full"}, {0x73,0x03,"Power calibration area error"}, {0x73,0x04,"Program memory area update failure"}, {0x73,0x05,"Program memory area is full"}, {0x73,0x06,"RMA/PMA is almost full"}, {0x73,0x10,"Current power calibration area almost full"}, {0x73,0x11,"Current power calibration area is full"}, {0x73,0x17,"RDZ is full"}, {0x74,0x00,"Security error"}, {0x74,0x01,"Unable to decrypt data"}, {0x74,0x02,"Unencrypted data encountered while decrypting"}, {0x74,0x03,"Incorrect data encryption key"}, {0x74,0x04,"Cryptographic integrity validation failed"}, {0x74,0x05,"Error decrypting data"}, {0x74,0x06,"Unknown signature verification key"}, {0x74,0x07,"Encryption parameters not useable"}, {0x74,0x08,"Digital signature validation failure"}, {0x74,0x09,"Encryption mode mismatch on read"}, {0x74,0x0a,"Encrypted block not raw read enabled"}, {0x74,0x0b,"Incorrect Encryption parameters"}, {0x74,0x0c,"Unable to decrypt parameter list"}, {0x74,0x0d,"Encryption algorithm disabled"}, {0x74,0x10,"SA creation parameter value invalid"}, {0x74,0x11,"SA creation parameter value rejected"}, {0x74,0x12,"Invalid SA usage"}, {0x74,0x21,"Data encryption configuration prevented"}, {0x74,0x30,"SA creation parameter not supported"}, {0x74,0x40,"Authentication failed"}, {0x74,0x61,"External data encryption key manager access error"}, {0x74,0x62,"External data encryption key manager error"}, {0x74,0x63,"External data encryption key not found"}, {0x74,0x64,"External data encryption request not authorized"}, {0x74,0x6e,"External data encryption control timeout"}, {0x74,0x6f,"External data encryption control error"}, {0x74,0x71,"Logical unit access not authorized"}, {0x74,0x79,"Security conflict in translated device"}, {0, 0, NULL} }; #else struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[] = { {0, 0, 0, NULL} }; struct sg_lib_asc_ascq_t sg_lib_asc_ascq[] = { {0, 0, NULL} }; #endif /* SG_SCSI_STRINGS */ const char * sg_lib_sense_key_desc[] = { "No Sense", /* Filemark, ILI and/or EOM; progress indication (during FORMAT); power condition sensing (REQUEST SENSE) */ "Recovered Error", /* The last command completed successfully but used error correction */ "Not Ready", /* The addressed target is not ready */ "Medium Error", /* Data error detected on the medium */ "Hardware Error", /* Controller or device failure */ "Illegal Request", "Unit Attention", /* Removable medium was changed, or the target has been reset */ "Data Protect", /* Access to the data is blocked */ "Blank Check", /* Reached unexpected written or unwritten region of the medium */ "Vendor specific(9)", /* Vendor specific */ "Copy Aborted", /* COPY or COMPARE was aborted */ "Aborted Command", /* The target aborted the command */ "Equal", /* SEARCH DATA found data equal (obsolete) */ "Volume Overflow", /* Medium full with data to be written */ "Miscompare", /* Source data and data on the medium do not agree */ "Completed" /* may occur for successful cmd (spc4r23) */ }; const char * sg_lib_pdt_strs[] = { /* 0 */ "disk", "tape", "printer", "processor", /* often SAF-TE device, copy manager */ "write once optical disk", /* 5 */ "cd/dvd", "scanner", /* obsolete */ "optical memory device", "medium changer", "communications", /* obsolete */ /* 0xa */ "graphics [0xa]", /* obsolete */ "graphics [0xb]", /* obsolete */ "storage array controller", "enclosure services device", "simplified direct access device", "optical card reader/writer device", /* 0x10 */ "bridge controller commands", "object based storage", "automation/driver interface", "security manager device", "zoned block commands", "0x15", "0x16", "0x17", "0x18", "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "well known logical unit", "no physical device on this lu", }; const char * sg_lib_transport_proto_strs[] = { "Fibre Channel Protocol for SCSI (FCP-4)", "SCSI Parallel Interface (SPI-5)", "Serial Storage Architecture SCSI-3 Protocol (SSA-S3P)", "Serial Bus Protocol for IEEE 1394 (SBP-3)", "SCSI RDMA Protocol (SRP)", "Internet SCSI (iSCSI)", "Serial Attached SCSI Protocol (SPL-3)", "Automation/Drive Interface Transport (ADT-2)", "AT Attachment Interface (ACS-2)", /* 0x8 */ "USB Attached SCSI (UAS-2)", "SCSI over PCI Express (SOP)", "Oxb", "Oxc", "Oxd", "Oxe", "No specific protocol" }; sg3_utils-1.40/lib/sg_cmds_basic.c0000664000175000017500000004661312414667052016063 0ustar douggdougg/* * Copyright (c) 1999-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * CONTENTS * Some SCSI commands are executed in many contexts and hence began * to appear in several sg3_utils utilities. This files centralizes * some of the low level command execution code. In most cases the * interpretation of the command response is left to the each * utility. */ #include #include #include #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif static const char * version_str = "1.69 20141006"; #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define EBUFF_SZ 256 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define START_PT_TIMEOUT 120 /* 120 seconds == 2 minutes */ #define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */ #define INQUIRY_CMD 0x12 #define INQUIRY_CMDLEN 6 #define REQUEST_SENSE_CMD 0x3 #define REQUEST_SENSE_CMDLEN 6 #define REPORT_LUNS_CMD 0xa0 #define REPORT_LUNS_CMDLEN 12 #define TUR_CMD 0x0 #define TUR_CMDLEN 6 #define SAFE_STD_INQ_RESP_LEN 36 /* other lengths lock up some devices */ const char * sg_cmds_version() { return version_str; } /* Returns file descriptor >= 0 if successful. If error in Unix returns negated errno. */ int sg_cmds_open_device(const char * device_name, int read_only, int verbose) { return scsi_pt_open_device(device_name, read_only, verbose); } /* Returns file descriptor >= 0 if successful. If error in Unix returns negated errno. */ int sg_cmds_open_flags(const char * device_name, int flags, int verbose) { return scsi_pt_open_flags(device_name, flags, verbose); } /* Returns 0 if successful. If error in Unix returns negated errno. */ int sg_cmds_close_device(int device_fd) { return scsi_pt_close_device(device_fd); } static int sg_cmds_process_helper(const char * leadin, int mx_di_len, int resid, const unsigned char * sbp, int slen, int noisy, int verbose, int * o_sense_cat) { int scat, got; int n = 0; int check_data_in = 0; char b[512]; scat = sg_err_category_sense(sbp, slen); switch (scat) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_COPY_ABORTED: case SG_LIB_CAT_DATA_PROTECT: case SG_LIB_CAT_PROTECTION: case SG_LIB_CAT_NO_SENSE: case SG_LIB_CAT_MISCOMPARE: n = 0; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_MEDIUM_HARD: ++check_data_in; /* drop through */ case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_SENSE: default: n = noisy; break; } if (verbose || n) { sg_get_sense_str(leadin, sbp, slen, (verbose > 1), sizeof(b), b); fprintf(sg_warnings_strm, "%s", b); if ((mx_di_len > 0) && (resid > 0)) { got = mx_di_len - resid; if ((verbose > 2) || check_data_in || (got > 0)) fprintf(sg_warnings_strm, " pass-through requested %d " "bytes (data-in) but got %d bytes\n", mx_di_len, got); } } if (o_sense_cat) *o_sense_cat = scat; return -2; } /* This is a helper function used by sg_cmds_* implementations after the * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid * sense data is found it is decoded and output to sg_warnings_strm (def: * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for * "sense" category (may not be fatal), -1 for failed, 0, or a positive * number. If 'mx_di_len > 0' then asks pass-through for resid and returns * (mx_di_len - resid); otherwise returns 0. So for data-in it should return * the actual number of bytes received. For data-out (to device) or no data * call with 'mx_di_len' set to 0 or less. If -2 returned then sense category * output via 'o_sense_cat' pointer (if not NULL). Note that several sense * categories also have data in bytes received; -2 is still returned. */ int sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin, int pt_res, int mx_di_len, const unsigned char * sbp, int noisy, int verbose, int * o_sense_cat) { int got, cat, duration, slen, resid, resp_code, sstat; char b[1024]; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (NULL == leadin) leadin = ""; if (pt_res < 0) { if (noisy || verbose) fprintf(sg_warnings_strm, "%s: pass through os error: %s\n", leadin, safe_strerror(-pt_res)); return -1; } else if (SCSI_PT_DO_BAD_PARAMS == pt_res) { fprintf(sg_warnings_strm, "%s: bad pass through setup\n", leadin); return -1; } else if (SCSI_PT_DO_TIMEOUT == pt_res) { fprintf(sg_warnings_strm, "%s: pass through timeout\n", leadin); return -1; } if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) fprintf(sg_warnings_strm, " duration=%d ms\n", duration); resid = (mx_di_len > 0) ? get_scsi_pt_resid(ptvp) : 0; slen = get_scsi_pt_sense_len(ptvp); switch ((cat = get_scsi_pt_result_category(ptvp))) { case SCSI_PT_RESULT_GOOD: if (slen > 7) { resp_code = sbp[0] & 0x7f; /* SBC referrals can have status=GOOD and sense_key=COMPLETED */ if (resp_code >= 0x70) { if (resp_code < 0x72) { if (SPC_SK_NO_SENSE != (0xf & sbp[2])) sg_err_category_sense(sbp, slen); } else if (resp_code < 0x74) { if (SPC_SK_NO_SENSE != (0xf & sbp[1])) sg_err_category_sense(sbp, slen); } } } if (mx_di_len > 0) { got = mx_di_len - resid; if ((verbose > 1) && (resid > 0)) fprintf(sg_warnings_strm, " %s: pass-through requested " "%d bytes (data-in) but got %d bytes\n", leadin, mx_di_len, got); return got; } else return 0; case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ sstat = get_scsi_pt_status_response(ptvp); if ((SAM_STAT_RESERVATION_CONFLICT == sstat) && o_sense_cat) { /* treat this SCSI status as "sense" category */ *o_sense_cat = SG_LIB_CAT_RES_CONFLICT; return -2; } if (verbose || noisy) { sg_get_scsi_status_str(sstat, sizeof(b), b); fprintf(sg_warnings_strm, "%s: scsi status: %s\n", leadin, b); } return -1; case SCSI_PT_RESULT_SENSE: return sg_cmds_process_helper(leadin, mx_di_len, resid, sbp, slen, noisy, verbose, o_sense_cat); case SCSI_PT_RESULT_TRANSPORT_ERR: if (verbose || noisy) { get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); fprintf(sg_warnings_strm, "%s: transport: %s\n", leadin, b); } if ((SAM_STAT_CHECK_CONDITION == get_scsi_pt_status_response(ptvp)) && (slen > 0)) return sg_cmds_process_helper(leadin, mx_di_len, resid, 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); fprintf(sg_warnings_strm, "%s: os: %s\n", leadin, b); } return -1; default: fprintf(sg_warnings_strm, "%s: unknown pass through result " "category (%d)\n", leadin, cat); return -1; } } /* Invokes a SCSI INQUIRY command and yields the response. Returns 0 when * successful, various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp, int mx_resp_len, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; unsigned char * up; struct sg_pt_base * ptvp; if (cmddt) inqCmdBlk[1] |= 2; if (evpd) inqCmdBlk[1] |= 1; inqCmdBlk[2] = (unsigned char)pg_op; /* 16 bit allocation length (was 8) is a recent SPC-3 addition */ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); inqCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " inquiry cdb: "); for (k = 0; k < INQUIRY_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", inqCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if (resp && (mx_resp_len > 0)) { up = (unsigned char *)resp; up[0] = 0x7f; /* defensive prefill */ if (mx_resp_len > 4) up[4] = 0; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "inquiry: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else if (ret < 4) { if (verbose) fprintf(sg_warnings_strm, "inquiry: got too few " "bytes (%d)\n", ret); ret = SG_LIB_CAT_MALFORMED; } else ret = 0; if (resid > 0) { if (resid > mx_resp_len) { fprintf(sg_warnings_strm, "inquiry: resid (%d) should never " "exceed requested len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } /* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response. * Returns 0 when successful, various SG_LIB_CAT_* positive values or * -1 -> other errors */ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN]; struct sg_pt_base * ptvp; if (inq_data) { memset(inq_data, 0, sizeof(* inq_data)); inq_data->peripheral_qualifier = 0x3; inq_data->peripheral_type = 0x1f; } inqCmdBlk[4] = (unsigned char)sizeof(inq_resp); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " inquiry cdb: "); for (k = 0; k < INQUIRY_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", inqCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } memset(inq_resp, 0, sizeof(inq_resp)); inq_resp[0] = 0x7f; /* defensive prefill */ ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "inquiry: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, inq_resp, sizeof(inq_resp)); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "inquiry", res, sizeof(inq_resp), sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else if (ret < 4) { if (verbose) fprintf(sg_warnings_strm, "inquiry: got too few " "bytes (%d)\n", ret); ret = SG_LIB_CAT_MALFORMED; } else ret = 0; if (inq_data && (0 == ret)) { inq_data->peripheral_qualifier = (inq_resp[0] >> 5) & 0x7; inq_data->peripheral_type = inq_resp[0] & 0x1f; inq_data->byte_1 = inq_resp[1]; inq_data->version = inq_resp[2]; inq_data->byte_3 = inq_resp[3]; inq_data->byte_5 = inq_resp[5]; inq_data->byte_6 = inq_resp[6]; inq_data->byte_7 = inq_resp[7]; memcpy(inq_data->vendor, inq_resp + 8, 8); memcpy(inq_data->product, inq_resp + 16, 16); memcpy(inq_data->revision, inq_resp + 32, 4); } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI TEST UNIT READY command. * 'pack_id' is just for diagnostics, safe to set to 0. * Looks for progress indicator if 'progress' non-NULL; * if found writes value [0..65535] else write -1. * Returns 0 when successful, various SG_LIB_CAT_* positive values or * -1 -> other errors */ int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char turCmdBlk[TUR_CMDLEN] = {TUR_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " test unit ready cdb: "); for (k = 0; k < TUR_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", turCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "test unit ready: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, turCmdBlk, sizeof(turCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_packet_id(ptvp, pack_id); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "test unit ready", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { if (progress) { int slen = get_scsi_pt_sense_len(ptvp); if (! sg_get_sense_progress_fld(sense_b, slen, progress)) *progress = -1; } switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI TEST UNIT READY command. * 'pack_id' is just for diagnostics, safe to set to 0. * Returns 0 when successful, various SG_LIB_CAT_* positive values or * -1 -> other errors */ int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose) { return sg_ll_test_unit_ready_progress(sg_fd, pack_id, NULL, noisy, verbose); } /* Invokes a SCSI REQUEST SENSE command. Returns 0 when successful, various * SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rsCmdBlk[REQUEST_SENSE_CMDLEN] = {REQUEST_SENSE_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (desc) rsCmdBlk[1] |= 0x1; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (mx_resp_len > 0xff) { fprintf(sg_warnings_strm, "mx_resp_len cannot exceed 255\n"); return -1; } rsCmdBlk[4] = mx_resp_len & 0xff; if (verbose) { fprintf(sg_warnings_strm, " Request Sense cmd: "); for (k = 0; k < REQUEST_SENSE_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rsCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "request sense: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rsCmdBlk, sizeof(rsCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "request sense", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((mx_resp_len >= 8) && (ret < 8)) { if (verbose) fprintf(sg_warnings_strm, " request sense: got %d " "bytes in response, too short\n", ret); ret = -1; } else ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rlCmdBlk[REPORT_LUNS_CMDLEN] = {REPORT_LUNS_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; rlCmdBlk[2] = select_report & 0xff; rlCmdBlk[6] = (mx_resp_len >> 24) & 0xff; rlCmdBlk[7] = (mx_resp_len >> 16) & 0xff; rlCmdBlk[8] = (mx_resp_len >> 8) & 0xff; rlCmdBlk[9] = mx_resp_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " report luns cdb: "); for (k = 0; k < REPORT_LUNS_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rlCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "report luns: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rlCmdBlk, sizeof(rlCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report luns", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.40/lib/BSD_LICENSE0000664000175000017500000000275211346470114014622 0ustar douggdougg/* * Copyright (c) 1999-2010 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ sg3_utils-1.40/lib/sg_pt_linux.c0000664000175000017500000007074312344371176015640 0ustar douggdougg/* * Copyright (c) 2005-2013 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* sg_pt_linux version 1.22 20140606 */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_pt.h" #include "sg_lib.h" #include "sg_linux_inc.h" #define DEF_TIMEOUT 60000 /* 60,000 millisecs (60 seconds) */ static const char * linux_host_bytes[] = { "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE" /* 0xd */, "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE" /* 0x10 */, "DID_NEXUS_FAILURE (reservation conflict)", }; #define LINUX_HOST_BYTES_SZ \ (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0])) static const char * linux_driver_bytes[] = { "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE" }; #define LINUX_DRIVER_BYTES_SZ \ (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0])) static const char * linux_driver_suggests[] = { "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN", "SUGGEST_SENSE" }; #define LINUX_DRIVER_SUGGESTS_SZ \ (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0])) /* * These defines are for constants that should be visible in the * /usr/include/scsi directory (brought in by sg_linux_inc.h). * Redefined and aliased here to decouple this code from * sg_io_linux.h */ #ifndef DRIVER_MASK #define DRIVER_MASK 0x0f #endif #ifndef SUGGEST_MASK #define SUGGEST_MASK 0xf0 #endif #ifndef DRIVER_SENSE #define DRIVER_SENSE 0x08 #endif #define SG_LIB_DRIVER_MASK DRIVER_MASK #define SG_LIB_SUGGEST_MASK SUGGEST_MASK #define SG_LIB_DRIVER_SENSE DRIVER_SENSE // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #if defined(IGNORE_LINUX_BSG) || ! defined(HAVE_LINUX_BSG_H) /* * sg(v3) via SG_IO ioctl on a sg node or other node that accepts that ioctl. * Decision has been made at compile time because either: * a) no /usr/include/linux/bsg.h header file was found, or * b) the builder gave the '--enable-no-linux-bsg' option to ./configure */ struct sg_pt_linux_scsi { struct sg_io_hdr io_hdr; int in_err; int os_err; }; struct sg_pt_base { struct sg_pt_linux_scsi impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = O_NONBLOCK; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */ /* together. The 'flags' argument is advisory and may be ignored. */ /* Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; if (verbose > 1) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "open %s with flags=0x%x\n", device_name, flags); } fd = open(device_name, flags); if (fd < 0) fd = -errno; return fd; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { int res; res = close(device_fd); if (res < 0) res = -errno; return res; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { ptp->io_hdr.interface_id = 'S'; ptp->io_hdr.dxfer_direction = SG_DXFER_NONE; } return (struct sg_pt_base *)ptp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.interface_id = 'S'; ptp->io_hdr.dxfer_direction = SG_DXFER_NONE; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.cmdp) ++ptp->in_err; ptp->io_hdr.cmdp = (unsigned char *)cdb; ptp->io_hdr.cmd_len = cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.sbp) ++ptp->in_err; memset(sense, 0, max_sense_len); ptp->io_hdr.sbp = sense; ptp->io_hdr.mx_sb_len = max_sense_len; } /* Setup for data transfer from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->io_hdr.dxferp = dxferp; ptp->io_hdr.dxfer_len = dxfer_len; ptp->io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; } } /* Setup for data transfer toward device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->io_hdr.dxferp = (unsigned char *)dxferp; ptp->io_hdr.dxfer_len = dxfer_len; ptp->io_hdr.dxfer_direction = SG_DXFER_TO_DEV; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.pack_id = pack_id; } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; ++ptp->in_err; if (tag) { ; } /* unused, suppress warning */ } /* Note that task management function codes are transport specific */ void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; ++ptp->in_err; if (tmf_code) { ; } /* unused, suppress warning */ } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; ++ptp->in_err; if (attribute) { ; } /* unused, suppress warning */ if (priority) { ; } /* unused, suppress warning */ } #ifndef SG_FLAG_Q_AT_TAIL #define SG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef SG_FLAG_Q_AT_HEAD #define SG_FLAG_Q_AT_HEAD 0x20 #endif void set_scsi_pt_flags(struct sg_pt_base * vp, int flags) { struct sg_pt_linux_scsi * ptp = &vp->impl; /* default action of sg driver [sg v3 interface] is QUEUE_AT_HEAD */ /* default action of block layer SG_IO ioctl is QUEUE_AT_TAIL */ if (SCSI_PT_FLAGS_QUEUE_AT_HEAD & flags) { /* favour AT_HEAD */ ptp->io_hdr.flags |= SG_FLAG_Q_AT_HEAD; ptp->io_hdr.flags &= ~SG_FLAG_Q_AT_TAIL; } else if (SCSI_PT_FLAGS_QUEUE_AT_TAIL & flags) { ptp->io_hdr.flags |= SG_FLAG_Q_AT_TAIL; ptp->io_hdr.flags &= ~SG_FLAG_Q_AT_HEAD; } } /* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt... " "functions\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->io_hdr.cmdp) { if (verbose) fprintf(sg_warnings_strm, "No SCSI command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } /* io_hdr.timeout is in milliseconds */ ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT); if (ptp->io_hdr.sbp && (ptp->io_hdr.mx_sb_len > 0)) memset(ptp->io_hdr.sbp, 0, ptp->io_hdr.mx_sb_len); if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) { ptp->os_err = errno; if (verbose > 1) fprintf(sg_warnings_strm, "ioctl(SG_IO) failed: %s (errno=%d)\n", strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } return 0; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.status & 0x7e; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.host_status) return SCSI_PT_RESULT_TRANSPORT_ERR; else if (dr_st && (SG_LIB_DRIVER_SENSE != dr_st)) return SCSI_PT_RESULT_TRANSPORT_ERR; else if ((SG_LIB_DRIVER_SENSE == dr_st) || (SAM_STAT_CHECK_CONDITION == scsi_st) || (SAM_STAT_COMMAND_TERMINATED == scsi_st)) return SCSI_PT_RESULT_SENSE; else if (scsi_st) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.sb_len_wr; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.duration; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return (ptp->io_hdr.host_status << 8) + ptp->io_hdr.driver_status; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->os_err; } /* Returns b which will contain a null char terminated string (if * max_b_len > 0). That string should decode Linux driver and host * status values. */ char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_linux_scsi * ptp = &vp->impl; int ds = ptp->io_hdr.driver_status; int hs = ptp->io_hdr.host_status; int n, m; char * cp = b; int driv, sugg; const char * driv_cp = "unknown"; const char * sugg_cp = "unknown"; if (max_b_len < 1) return b; m = max_b_len; n = 0; if (hs) { if ((hs < 0) || (hs >= LINUX_HOST_BYTES_SZ)) n = snprintf(cp, m, "Host_status=0x%02x is unknown\n", hs); else n = snprintf(cp, m, "Host_status=0x%02x [%s]\n", hs, linux_host_bytes[hs]); } m -= n; if (m < 1) { b[max_b_len - 1] = '\0'; return b; } cp += n; driv = ds & SG_LIB_DRIVER_MASK; if (driv < LINUX_DRIVER_BYTES_SZ) driv_cp = linux_driver_bytes[driv]; sugg = (ds & SG_LIB_SUGGEST_MASK) >> 4; if (sugg < LINUX_DRIVER_SUGGESTS_SZ) sugg_cp = linux_driver_suggests[sugg]; n = snprintf(cp, m, "Driver_status=0x%02x [%s, %s]\n", ds, driv_cp, sugg_cp); m -= n; if (m < 1) b[max_b_len - 1] = '\0'; return b; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< #else /* allow for runtime selection of sg v3 or v4 (via bsg) */ // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< /* * So bsg is an option. Thus we make a runtime decision. If all the following * are true we use sg v4 which is only currently supported on bsg device * nodes: * a) there is a bsg entry in the /proc/devices file * b) the device node given to scsi_pt_open() is a char device * c) the char major number of the device node given to scsi_pt_open() * matches the char major number of the bsg entry in /proc/devices * Otherwise the sg v3 interface is used. * * Note that in either case we prepare the data in a sg v4 structure. If * the runtime tests indicate that the v3 interface is needed then * do_scsi_pt_v3() transfers the input data into a v3 structure and * then the output data is transferred back into a sg v4 structure. * That implementation detail could change in the future. * * [20120806] Only use MAJOR() macro in kdev_t.h if that header file is * available and major() macro [N.B. lower case] is not available. */ #include #include #ifdef major #define SG_DEV_MAJOR major #else #ifdef HAVE_LINUX_KDEV_T_H #include #endif #define SG_DEV_MAJOR MAJOR /* MAJOR() macro faulty if > 255 minors */ #endif struct sg_pt_linux_scsi { struct sg_io_v4 io_hdr; /* use v4 header as it is more general */ int in_err; int os_err; unsigned char tmf_request[4]; }; struct sg_pt_base { struct sg_pt_linux_scsi impl; }; static int bsg_major_checked = 0; static int bsg_major = 0; static void find_bsg_major(int verbose) { const char * proc_devices = "/proc/devices"; FILE *fp; char a[128]; char b[128]; char * cp; int n; if (NULL == (fp = fopen(proc_devices, "r"))) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) fprintf(sg_warnings_strm, "fopen %s failed: %s\n", proc_devices, strerror(errno)); return; } while ((cp = fgets(b, sizeof(b), fp))) { if ((1 == sscanf(b, "%s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, sizeof(b), fp))) { if (2 == sscanf(b, "%d %s", &n, a)) { if (0 == strcmp("bsg", a)) { bsg_major = n; break; } } else break; } if (verbose > 3) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (cp) fprintf(sg_warnings_strm, "found bsg_major=%d\n", bsg_major); else fprintf(sg_warnings_strm, "found no bsg char device in %s\n", proc_devices); } fclose(fp); } /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = O_NONBLOCK; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed */ /* together. The 'flags' argument is advisory and may be ignored. */ /* Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int fd; if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose); } if (verbose > 1) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "open %s with flags=0x%x\n", device_name, flags); } fd = open(device_name, flags); if (fd < 0) fd = -errno; return fd; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { int res; res = close(device_fd); if (res < 0) res = -errno; return res; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_linux_scsi * ptp; ptp = (struct sg_pt_linux_scsi *) calloc(1, sizeof(struct sg_pt_linux_scsi)); if (ptp) { ptp->io_hdr.guard = 'Q'; #ifdef BSG_PROTOCOL_SCSI ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI; #endif #ifdef BSG_SUB_PROTOCOL_SCSI_CMD ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; #endif } return (struct sg_pt_base *)ptp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp) { memset(ptp, 0, sizeof(struct sg_pt_linux_scsi)); ptp->io_hdr.guard = 'Q'; #ifdef BSG_PROTOCOL_SCSI ptp->io_hdr.protocol = BSG_PROTOCOL_SCSI; #endif #ifdef BSG_SUB_PROTOCOL_SCSI_CMD ptp->io_hdr.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD; #endif } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.request) ++ptp->in_err; /* C99 has intptr_t instead of long */ ptp->io_hdr.request = (__u64)(long)cdb; ptp->io_hdr.request_len = cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.response) ++ptp->in_err; memset(sense, 0, max_sense_len); ptp->io_hdr.response = (__u64)(long)sense; ptp->io_hdr.max_response_len = max_sense_len; } /* Setup for data transfer from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.din_xferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->io_hdr.din_xferp = (__u64)(long)dxferp; ptp->io_hdr.din_xfer_len = dxfer_len; } } /* Setup for data transfer toward device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (ptp->io_hdr.dout_xferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->io_hdr.dout_xferp = (__u64)(long)dxferp; ptp->io_hdr.dout_xfer_len = dxfer_len; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.spare_in = pack_id; } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.request_tag = tag; } /* Note that task management function codes are transport specific */ void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.subprotocol = 1; /* SCSI task management function */ ptp->tmf_request[0] = (unsigned char)tmf_code; /* assume it fits */ ptp->io_hdr.request = (__u64)(long)(&(ptp->tmf_request[0])); ptp->io_hdr.request_len = 1; } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attribute, int priority) { struct sg_pt_linux_scsi * ptp = &vp->impl; ptp->io_hdr.request_attr = attribute; ptp->io_hdr.request_priority = priority; } #ifndef BSG_FLAG_Q_AT_TAIL #define BSG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef BSG_FLAG_Q_AT_HEAD #define BSG_FLAG_Q_AT_HEAD 0x20 #endif /* Need this later if translated to v3 interface */ #ifndef SG_FLAG_Q_AT_TAIL #define SG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef SG_FLAG_Q_AT_HEAD #define SG_FLAG_Q_AT_HEAD 0x20 #endif void set_scsi_pt_flags(struct sg_pt_base * vp, int flags) { struct sg_pt_linux_scsi * ptp = &vp->impl; /* default action of bsg driver (sg v4) is QUEUE_AT_HEAD */ /* default action of block layer SG_IO ioctl is QUEUE_AT_TAIL */ if (SCSI_PT_FLAGS_QUEUE_AT_HEAD & flags) { /* favour AT_HEAD */ ptp->io_hdr.flags |= BSG_FLAG_Q_AT_HEAD; ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_TAIL; } else if (SCSI_PT_FLAGS_QUEUE_AT_TAIL & flags) { ptp->io_hdr.flags |= BSG_FLAG_Q_AT_TAIL; ptp->io_hdr.flags &= ~BSG_FLAG_Q_AT_HEAD; } } /* N.B. Returns din_resid and ignores dout_resid */ int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.din_resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.device_status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.response_len; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.duration; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->io_hdr.transport_status; } /* Returns b which will contain a null char terminated string (if * max_b_len > 0). Combined driver and transport (called "host" in Linux * kernel) statuses */ char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_linux_scsi * ptp = &vp->impl; int ds = ptp->io_hdr.driver_status; int hs = ptp->io_hdr.transport_status; int n, m; char * cp = b; int driv, sugg; const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; if (max_b_len < 1) return b; m = max_b_len; n = 0; if (hs) { if ((hs < 0) || (hs >= LINUX_HOST_BYTES_SZ)) n = snprintf(cp, m, "Host_status=0x%02x is invalid\n", hs); else n = snprintf(cp, m, "Host_status=0x%02x [%s]\n", hs, linux_host_bytes[hs]); } m -= n; if (m < 1) { b[max_b_len - 1] = '\0'; return b; } cp += n; driv = ds & SG_LIB_DRIVER_MASK; if (driv < LINUX_DRIVER_BYTES_SZ) driv_cp = linux_driver_bytes[driv]; sugg = (ds & SG_LIB_SUGGEST_MASK) >> 4; if (sugg < LINUX_DRIVER_SUGGESTS_SZ) sugg_cp = linux_driver_suggests[sugg]; n = snprintf(cp, m, "Driver_status=0x%02x [%s, %s]\n", ds, driv_cp, sugg_cp); m -= n; if (m < 1) b[max_b_len - 1] = '\0'; return b; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; int dr_st = ptp->io_hdr.driver_status & SG_LIB_DRIVER_MASK; int scsi_st = ptp->io_hdr.device_status & 0x7e; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->io_hdr.transport_status) return SCSI_PT_RESULT_TRANSPORT_ERR; else if (dr_st && (SG_LIB_DRIVER_SENSE != dr_st)) return SCSI_PT_RESULT_TRANSPORT_ERR; else if ((SG_LIB_DRIVER_SENSE == dr_st) || (SAM_STAT_CHECK_CONDITION == scsi_st) || (SAM_STAT_COMMAND_TERMINATED == scsi_st)) return SCSI_PT_RESULT_SENSE; else if (scsi_st) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_linux_scsi * ptp = &vp->impl; return ptp->os_err; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_linux_scsi * ptp = &vp->impl; const char * cp; cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } /* Executes SCSI command using sg v3 interface */ static int do_scsi_pt_v3(struct sg_pt_linux_scsi * ptp, int fd, int time_secs, int verbose) { struct sg_io_hdr v3_hdr; memset(&v3_hdr, 0, sizeof(v3_hdr)); /* convert v4 to v3 header */ v3_hdr.interface_id = 'S'; v3_hdr.dxfer_direction = SG_DXFER_NONE; v3_hdr.cmdp = (unsigned char *)(long)ptp->io_hdr.request; v3_hdr.cmd_len = (unsigned char)ptp->io_hdr.request_len; if (ptp->io_hdr.din_xfer_len > 0) { if (ptp->io_hdr.dout_xfer_len > 0) { if (verbose) fprintf(sg_warnings_strm, "sgv3 doesn't support bidi\n"); return SCSI_PT_DO_BAD_PARAMS; } v3_hdr.dxferp = (void *)(long)ptp->io_hdr.din_xferp; v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.din_xfer_len; v3_hdr.dxfer_direction = SG_DXFER_FROM_DEV; } else if (ptp->io_hdr.dout_xfer_len > 0) { v3_hdr.dxferp = (void *)(long)ptp->io_hdr.dout_xferp; v3_hdr.dxfer_len = (unsigned int)ptp->io_hdr.dout_xfer_len; v3_hdr.dxfer_direction = SG_DXFER_TO_DEV; } if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) { v3_hdr.sbp = (unsigned char *)(long)ptp->io_hdr.response; v3_hdr.mx_sb_len = (unsigned char)ptp->io_hdr.max_response_len; } v3_hdr.pack_id = (int)ptp->io_hdr.spare_in; if (BSG_FLAG_Q_AT_HEAD & ptp->io_hdr.flags) v3_hdr.flags |= SG_FLAG_Q_AT_HEAD; /* favour AT_HEAD */ else if (BSG_FLAG_Q_AT_TAIL & ptp->io_hdr.flags) v3_hdr.flags |= SG_FLAG_Q_AT_TAIL; if (NULL == v3_hdr.cmdp) { if (verbose) fprintf(sg_warnings_strm, "No SCSI command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } /* io_hdr.timeout is in milliseconds, if greater than zero */ v3_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT); /* Finally do the v3 SG_IO ioctl */ if (ioctl(fd, SG_IO, &v3_hdr) < 0) { ptp->os_err = errno; if (verbose > 1) fprintf(sg_warnings_strm, "ioctl(SG_IO v3) failed: %s " "(errno=%d)\n", strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } ptp->io_hdr.device_status = (__u32)v3_hdr.status; ptp->io_hdr.driver_status = (__u32)v3_hdr.driver_status; ptp->io_hdr.transport_status = (__u32)v3_hdr.host_status; ptp->io_hdr.response_len = (__u32)v3_hdr.sb_len_wr; ptp->io_hdr.duration = (__u32)v3_hdr.duration; ptp->io_hdr.din_resid = (__s32)v3_hdr.resid; /* v3_hdr.info not passed back since no mapping defined (yet) */ return 0; } /* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int fd, int time_secs, int verbose) { struct sg_pt_linux_scsi * ptp = &vp->impl; if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(verbose); } if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt... " "functions\n"); return SCSI_PT_DO_BAD_PARAMS; } if (bsg_major <= 0) return do_scsi_pt_v3(ptp, fd, time_secs, verbose); else { struct stat a_stat; if (fstat(fd, &a_stat) < 0) { ptp->os_err = errno; if (verbose > 1) fprintf(sg_warnings_strm, "fstat() failed: %s (errno=%d)\n", strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } if (! S_ISCHR(a_stat.st_mode) || (bsg_major != (int)SG_DEV_MAJOR(a_stat.st_rdev))) return do_scsi_pt_v3(ptp, fd, time_secs, verbose); } if (! ptp->io_hdr.request) { if (verbose) fprintf(sg_warnings_strm, "No SCSI command (cdb) given (v4)\n"); return SCSI_PT_DO_BAD_PARAMS; } /* io_hdr.timeout is in milliseconds */ ptp->io_hdr.timeout = ((time_secs > 0) ? (time_secs * 1000) : DEF_TIMEOUT); #if 0 /* sense buffer already zeroed */ if (ptp->io_hdr.response && (ptp->io_hdr.max_response_len > 0)) { void * p; p = (void *)(long)ptp->io_hdr.response; memset(p, 0, ptp->io_hdr.max_response_len); } #endif if (ioctl(fd, SG_IO, &ptp->io_hdr) < 0) { ptp->os_err = errno; if (verbose > 1) fprintf(sg_warnings_strm, "ioctl(SG_IO v4) failed: %s " "(errno=%d)\n", strerror(ptp->os_err), ptp->os_err); return -ptp->os_err; } return 0; } #endif // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< sg3_utils-1.40/lib/sg_pt_win32.c0000664000175000017500000006115712401205666015434 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* sg_pt_win32 version 1.15 20140901 */ #include #include #include #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" #include "sg_pt_win32.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef O_EXCL // #define O_EXCL 0x80 // cygwin ?? // #define O_EXCL 0x80 // Linux #define O_EXCL 0x400 // mingw #warning "O_EXCL not defined" #endif /* Use the Microsoft SCSI Pass Through (SPT) interface. It has two * variants: "SPT" where data is double buffered; and "SPTD" where data * pointers to the user space are passed to the OS. Only Windows * 2000 and later (i.e. not 95,98 or ME). * There is no ASPI interface which relies on a dll from adaptec. * This code uses cygwin facilities and is built in a cygwin * shell. It can be run in a normal DOS shell if the cygwin1.dll * file is put in an appropriate place. * This code can build in a MinGW environment. * * N.B. MSDN says that the "SPT" interface (i.e. double buffered) * should be used for small amounts of data (it says "< 16 KB"). * The direct variant (i.e. IOCTL_SCSI_PASS_THROUGH_DIRECT) should * be used for larger amounts of data but the buffer needs to be * "cache aligned". Is that 16 byte alignment or greater? * * This code will default to indirect (i.e. double buffered) access * unless the WIN32_SPT_DIRECT preprocessor constant is defined in * config.h . In version 1.12 runtime selection of direct and indirect * access was added; the default is still determined by the * WIN32_SPT_DIRECT preprocessor constant. */ #define DEF_TIMEOUT 60 /* 60 seconds */ #define MAX_OPEN_SIMULT 8 #define WIN32_FDOFFSET 32 struct sg_pt_handle { int in_use; HANDLE fh; char adapter[32]; int bus; int target; int lun; int verbose; /* tunnel verbose through to scsi_pt_close_device */ }; static struct sg_pt_handle handle_arr[MAX_OPEN_SIMULT]; struct sg_pt_win32_scsi { unsigned char * dxferp; int dxfer_len; unsigned char * sensep; int sense_len; int scsi_status; int resid; int sense_resid; int in_err; int os_err; /* pseudo unix error */ int transport_err; /* windows error number */ union { SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb_d; /* Last entry in structure so data buffer can be extended */ SCSI_PASS_THROUGH_WITH_BUFFERS swb_i; }; }; /* embed pointer so can change on fly if (non-direct) data buffer * is not big enough */ struct sg_pt_base { struct sg_pt_win32_scsi * implp; }; #ifdef WIN32_SPT_DIRECT static int spt_direct = 1; #else static int spt_direct = 0; #endif /* Request SPT direct interface when state_direct is 1, state_direct set * to 0 for the SPT indirect interface. */ void scsi_pt_win32_direct(int state_direct) { spt_direct = state_direct; } /* Returns current SPT interface state, 1 for direct, 0 for indirect */ int scsi_pt_win32_spt_state(void) { return spt_direct; } /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? 0 : 0); /* was ... ? O_RDONLY : O_RDWR) */ return scsi_pt_open_flags(device_name, oflags, verbose); } /* * Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. The 'flags' argument is ignored in Windows. * Returns >= 0 if successful, otherwise returns negated errno. * Optionally accept leading "\\.\". If given something of the form * "SCSI:,," where the values in angle brackets * are integers, then will attempt to open "\\.\SCSI:" and save the * other three values for the DeviceIoControl call. The trailing "." * is optionally and if not given 0 is assumed. Since "PhysicalDrive" * is a lot of keystrokes, "PD" is accepted and converted to the longer * form. */ int scsi_pt_open_flags(const char * device_name, int flags, int verbose) { int len, k, adapter_num, bus, target, lun, off, got_scsi_name; int index, num, got_pd_name, pd_num, share_mode; struct sg_pt_handle * shp; char buff[8]; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; share_mode = (O_EXCL & flags) ? 0 : (FILE_SHARE_READ | FILE_SHARE_WRITE); /* lock */ for (k = 0; k < MAX_OPEN_SIMULT; k++) if (0 == handle_arr[k].in_use) break; if (k == MAX_OPEN_SIMULT) { if (verbose) fprintf(sg_warnings_strm, "too many open handles " "(%d)\n", MAX_OPEN_SIMULT); return -EMFILE; } else handle_arr[k].in_use = 1; /* unlock */ index = k; shp = handle_arr + index; adapter_num = 0; bus = 0; /* also known as 'PathId' in MS docs */ target = 0; lun = 0; got_pd_name = 0; got_scsi_name = 0; len = strlen(device_name); if ((len > 4) && (0 == strncmp("\\\\.\\", device_name, 4))) off = 4; else off = 0; if (len > (off + 2)) { buff[0] = toupper((int)device_name[off + 0]); buff[1] = toupper((int)device_name[off + 1]); if (0 == strncmp("PD", buff, 2)) { num = sscanf(device_name + off + 2, "%d", &pd_num); if (1 == num) got_pd_name = 1; } if (0 == got_pd_name) { buff[2] = toupper((int)device_name[off + 2]); buff[3] = toupper((int)device_name[off + 3]); if (0 == strncmp("SCSI", buff, 4)) { num = sscanf(device_name + off + 4, "%d:%d,%d,%d", &adapter_num, &bus, &target, &lun); if (num < 3) { if (verbose) fprintf(sg_warnings_strm, "expected format like: " "'SCSI:.[.]'\n"); shp->in_use = 0; return -EINVAL; } got_scsi_name = 1; } } } shp->bus = bus; shp->target = target; shp->lun = lun; shp->verbose = verbose; memset(shp->adapter, 0, sizeof(shp->adapter)); strncpy(shp->adapter, "\\\\.\\", 4); if (got_pd_name) snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5, "PhysicalDrive%d", pd_num); else if (got_scsi_name) snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5, "SCSI%d:", adapter_num); else snprintf(shp->adapter + 4, sizeof(shp->adapter) - 5, "%s", device_name + off); shp->fh = CreateFile(shp->adapter, GENERIC_READ | GENERIC_WRITE, share_mode, NULL, OPEN_EXISTING, 0, NULL); if (shp->fh == INVALID_HANDLE_VALUE) { if (verbose) fprintf(sg_warnings_strm, "Windows CreateFile error=%u\n", (unsigned int)GetLastError()); shp->in_use = 0; return -ENODEV; } return index + WIN32_FDOFFSET; } /* Returns 0 if successful. If device_id seems wild returns -ENODEV, * other errors return 0. If CloseHandle() fails and verbose > 0 then * outputs warning with value from GetLastError(). The verbose value * defaults to zero and is potentially set from the most recent call * to scsi_pt_open_device() or do_scsi_pt(). */ int scsi_pt_close_device(int device_fd) { struct sg_pt_handle * shp; int index; index = device_fd - WIN32_FDOFFSET; if ((index < 0) || (index >= WIN32_FDOFFSET)) return -ENODEV; shp = handle_arr + index; if ((! CloseHandle(shp->fh)) && shp->verbose) fprintf(sg_warnings_strm, "Windows CloseHandle error=%u\n", (unsigned int)GetLastError()); shp->bus = 0; shp->target = 0; shp->lun = 0; memset(shp->adapter, 0, sizeof(shp->adapter)); shp->in_use = 0; shp->verbose = 0; return 0; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_win32_scsi * psp; struct sg_pt_base * vp = NULL; psp = (struct sg_pt_win32_scsi *)calloc(sizeof(struct sg_pt_win32_scsi), 1); if (psp) { if (spt_direct) { psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; psp->swb_d.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN; psp->swb_d.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); psp->swb_d.spt.TimeOutValue = DEF_TIMEOUT; } else { psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; psp->swb_i.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN; psp->swb_i.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); psp->swb_i.spt.TimeOutValue = DEF_TIMEOUT; } vp = malloc(sizeof(struct sg_pt_win32_scsi *)); // yes a pointer if (vp) vp->implp = psp; else free(psp); } return vp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { if (vp) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp) { free(psp); } free(vp); } } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp) { memset(psp, 0, sizeof(struct sg_pt_win32_scsi)); if (spt_direct) { psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; psp->swb_d.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN; psp->swb_d.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); psp->swb_d.spt.TimeOutValue = DEF_TIMEOUT; } else { psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_UNSPECIFIED; psp->swb_i.spt.SenseInfoLength = SCSI_MAX_SENSE_LEN; psp->swb_i.spt.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucSenseBuf); psp->swb_i.spt.TimeOutValue = DEF_TIMEOUT; } } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (spt_direct) { if (psp->swb_d.spt.CdbLength > 0) ++psp->in_err; if (cdb_len > (int)sizeof(psp->swb_d.spt.Cdb)) { ++psp->in_err; return; } memcpy(psp->swb_d.spt.Cdb, cdb, cdb_len); psp->swb_d.spt.CdbLength = cdb_len; } else { if (psp->swb_i.spt.CdbLength > 0) ++psp->in_err; if (cdb_len > (int)sizeof(psp->swb_i.spt.Cdb)) { ++psp->in_err; return; } memcpy(psp->swb_i.spt.Cdb, cdb, cdb_len); psp->swb_i.spt.CdbLength = cdb_len; } } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int sense_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp->sensep) ++psp->in_err; memset(sense, 0, sense_len); psp->sensep = sense; psp->sense_len = sense_len; } /* from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp->dxferp) ++psp->in_err; if (dxfer_len > 0) { psp->dxferp = dxferp; psp->dxfer_len = dxfer_len; if (spt_direct) psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_IN; else psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_IN; } } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_win32_scsi * psp = vp->implp; if (psp->dxferp) ++psp->in_err; if (dxfer_len > 0) { psp->dxferp = (unsigned char *)dxferp; psp->dxfer_len = dxfer_len; if (spt_direct) psp->swb_d.spt.DataIn = SCSI_IOCTL_DATA_OUT; else psp->swb_i.spt.DataIn = SCSI_IOCTL_DATA_OUT; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp __attribute__ ((unused)), int pack_id __attribute__ ((unused))) { } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag __attribute__ ((unused))) { struct sg_pt_win32_scsi * psp = vp->implp; ++psp->in_err; } void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code __attribute__ ((unused))) { struct sg_pt_win32_scsi * psp = vp->implp; ++psp->in_err; } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib __attribute__ ((unused)), int priority __attribute__ ((unused))) { struct sg_pt_win32_scsi * psp = vp->implp; ++psp->in_err; } void set_scsi_pt_flags(struct sg_pt_base * objp, int flags) { /* do nothing, suppress warnings */ objp = objp; flags = flags; } /* Executes SCSI command (or at least forwards it to lower layers) * using direct interface. Clears os_err field prior to active call (whose * result may set it again). */ static int do_scsi_pt_direct(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { int index = device_fd - WIN32_FDOFFSET; struct sg_pt_win32_scsi * psp = vp->implp; struct sg_pt_handle * shp; BOOL status; DWORD returned; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; psp->os_err = 0; if (psp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (0 == psp->swb_d.spt.CdbLength) { if (verbose) fprintf(sg_warnings_strm, "No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } index = device_fd - WIN32_FDOFFSET; if ((index < 0) || (index >= WIN32_FDOFFSET)) { if (verbose) fprintf(sg_warnings_strm, "Bad file descriptor\n"); psp->os_err = ENODEV; return -psp->os_err; } shp = handle_arr + index; if (0 == shp->in_use) { if (verbose) fprintf(sg_warnings_strm, "File descriptor closed??\n"); psp->os_err = ENODEV; return -psp->os_err; } shp->verbose = verbose; psp->swb_d.spt.Length = sizeof (SCSI_PASS_THROUGH_DIRECT); psp->swb_d.spt.PathId = shp->bus; psp->swb_d.spt.TargetId = shp->target; psp->swb_d.spt.Lun = shp->lun; psp->swb_d.spt.TimeOutValue = time_secs; psp->swb_d.spt.DataTransferLength = psp->dxfer_len; if (verbose > 4) { fprintf(stderr, " spt_direct, adapter: %s Length=%d ScsiStatus=%d " "PathId=%d TargetId=%d Lun=%d\n", shp->adapter, (int)psp->swb_d.spt.Length, (int)psp->swb_d.spt.ScsiStatus, (int)psp->swb_d.spt.PathId, (int)psp->swb_d.spt.TargetId, (int)psp->swb_d.spt.Lun); fprintf(stderr, " CdbLength=%d SenseInfoLength=%d DataIn=%d " "DataTransferLength=%u\n", (int)psp->swb_d.spt.CdbLength, (int)psp->swb_d.spt.SenseInfoLength, (int)psp->swb_d.spt.DataIn, (unsigned int)psp->swb_d.spt.DataTransferLength); fprintf(stderr, " TimeOutValue=%u SenseInfoOffset=%u\n", (unsigned int)psp->swb_d.spt.TimeOutValue, (unsigned int)psp->swb_d.spt.SenseInfoOffset); } psp->swb_d.spt.DataBuffer = psp->dxferp; status = DeviceIoControl(shp->fh, IOCTL_SCSI_PASS_THROUGH_DIRECT, &psp->swb_d, sizeof(psp->swb_d), &psp->swb_d, sizeof(psp->swb_d), &returned, NULL); if (! status) { unsigned int u; u = (unsigned int)GetLastError(); if (verbose) fprintf(sg_warnings_strm, "Windows DeviceIoControl error=%u\n", u); psp->transport_err = (int)u; psp->os_err = EIO; return 0; /* let app find transport error */ } psp->scsi_status = psp->swb_d.spt.ScsiStatus; if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status)) memcpy(psp->sensep, psp->swb_d.ucSenseBuf, psp->sense_len); else psp->sense_len = 0; psp->sense_resid = 0; if ((psp->dxfer_len > 0) && (psp->swb_d.spt.DataTransferLength > 0)) psp->resid = psp->dxfer_len - psp->swb_d.spt.DataTransferLength; else psp->resid = 0; return 0; } /* Executes SCSI command (or at least forwards it to lower layers) using * indirect interface. Clears os_err field prior to active call (whose * result may set it again). */ static int do_scsi_pt_indirect(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { int index = device_fd - WIN32_FDOFFSET; struct sg_pt_win32_scsi * psp = vp->implp; struct sg_pt_handle * shp; BOOL status; DWORD returned; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; psp->os_err = 0; if (psp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused " "set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (0 == psp->swb_i.spt.CdbLength) { if (verbose) fprintf(sg_warnings_strm, "No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } index = device_fd - WIN32_FDOFFSET; if ((index < 0) || (index >= WIN32_FDOFFSET)) { if (verbose) fprintf(sg_warnings_strm, "Bad file descriptor\n"); psp->os_err = ENODEV; return -psp->os_err; } shp = handle_arr + index; if (0 == shp->in_use) { if (verbose) fprintf(sg_warnings_strm, "File descriptor closed??\n"); psp->os_err = ENODEV; return -psp->os_err; } shp->verbose = verbose; if (psp->dxfer_len > (int)sizeof(psp->swb_i.ucDataBuf)) { int extra = psp->dxfer_len - (int)sizeof(psp->swb_i.ucDataBuf); struct sg_pt_win32_scsi * epsp; if (verbose > 4) fprintf(sg_warnings_strm, "spt_indirect: dxfer_len (%d) too " "large for initial data\n buffer (%d bytes), try " "enlarging\n", psp->dxfer_len, (int)sizeof(psp->swb_i.ucDataBuf)); epsp = (struct sg_pt_win32_scsi *) calloc(sizeof(struct sg_pt_win32_scsi) + extra, 1); if (NULL == epsp) { fprintf(sg_warnings_strm, "do_scsi_pt: failed to enlarge data " "buffer to %d bytes\n", psp->dxfer_len); psp->os_err = ENOMEM; return -psp->os_err; } memcpy(epsp, psp, sizeof(struct sg_pt_win32_scsi)); free(psp); vp->implp = epsp; psp = epsp; } psp->swb_i.spt.Length = sizeof (SCSI_PASS_THROUGH); psp->swb_i.spt.DataBufferOffset = offsetof(SCSI_PASS_THROUGH_WITH_BUFFERS, ucDataBuf); psp->swb_i.spt.PathId = shp->bus; psp->swb_i.spt.TargetId = shp->target; psp->swb_i.spt.Lun = shp->lun; psp->swb_i.spt.TimeOutValue = time_secs; psp->swb_i.spt.DataTransferLength = psp->dxfer_len; if (verbose > 4) { fprintf(stderr, " spt_indirect, adapter: %s Length=%d ScsiStatus=%d " "PathId=%d TargetId=%d Lun=%d\n", shp->adapter, (int)psp->swb_i.spt.Length, (int)psp->swb_i.spt.ScsiStatus, (int)psp->swb_i.spt.PathId, (int)psp->swb_i.spt.TargetId, (int)psp->swb_i.spt.Lun); fprintf(stderr, " CdbLength=%d SenseInfoLength=%d DataIn=%d " "DataTransferLength=%u\n", (int)psp->swb_i.spt.CdbLength, (int)psp->swb_i.spt.SenseInfoLength, (int)psp->swb_i.spt.DataIn, (unsigned int)psp->swb_i.spt.DataTransferLength); fprintf(stderr, " TimeOutValue=%u DataBufferOffset=%u " "SenseInfoOffset=%u\n", (unsigned int)psp->swb_i.spt.TimeOutValue, (unsigned int)psp->swb_i.spt.DataBufferOffset, (unsigned int)psp->swb_i.spt.SenseInfoOffset); } if ((psp->dxfer_len > 0) && (SCSI_IOCTL_DATA_OUT == psp->swb_i.spt.DataIn)) memcpy(psp->swb_i.ucDataBuf, psp->dxferp, psp->dxfer_len); status = DeviceIoControl(shp->fh, IOCTL_SCSI_PASS_THROUGH, &psp->swb_i, sizeof(psp->swb_i), &psp->swb_i, sizeof(psp->swb_i), &returned, NULL); if (! status) { unsigned int u; u = (unsigned int)GetLastError(); if (verbose) fprintf(sg_warnings_strm, "Windows DeviceIoControl error=%u\n", u); psp->transport_err = (int)u; psp->os_err = EIO; return 0; /* let app find transport error */ } if ((psp->dxfer_len > 0) && (SCSI_IOCTL_DATA_IN == psp->swb_i.spt.DataIn)) memcpy(psp->dxferp, psp->swb_i.ucDataBuf, psp->dxfer_len); psp->scsi_status = psp->swb_i.spt.ScsiStatus; if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status)) memcpy(psp->sensep, psp->swb_i.ucSenseBuf, psp->sense_len); else psp->sense_len = 0; psp->sense_resid = 0; if ((psp->dxfer_len > 0) && (psp->swb_i.spt.DataTransferLength > 0)) psp->resid = psp->dxfer_len - psp->swb_i.spt.DataTransferLength; else psp->resid = 0; return 0; } /* Executes SCSI command (or at least forwards it to lower layers). * Clears os_err field prior to active call (whose result may set it * again). */ int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { if (spt_direct) return do_scsi_pt_direct(vp, device_fd, time_secs, verbose); else return do_scsi_pt_indirect(vp, device_fd, time_secs, verbose); } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; if (psp->transport_err) /* give transport error highest priority */ return SCSI_PT_RESULT_TRANSPORT_ERR; else if (psp->os_err) return SCSI_PT_RESULT_OS_ERR; else if ((SAM_STAT_CHECK_CONDITION == psp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == psp->scsi_status)) return SCSI_PT_RESULT_SENSE; else if (psp->scsi_status) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->scsi_status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; int len; len = psp->sense_len - psp->sense_resid; return (len > 0) ? len : 0; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp __attribute__ ((unused))) { // const struct sg_pt_freebsd_scsi * psp = vp->implp; return -1; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->transport_err; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_win32_scsi * psp = vp->implp; return psp->os_err; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { struct sg_pt_win32_scsi * psp = (struct sg_pt_win32_scsi *)vp->implp; LPVOID lpMsgBuf; int k, num, ch; if (max_b_len < 2) { if (1 == max_b_len) b[0] = '\0'; return b; } memset(b, 0, max_b_len); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, psp->transport_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); num = lstrlen((LPCTSTR)lpMsgBuf); if (num < 1) return b; num = (num < max_b_len) ? num : (max_b_len - 1); for (k = 0; k < num; ++k) { ch = *((LPCTSTR)lpMsgBuf + k); if ((ch >= 0x0) && (ch < 0x7f)) b[k] = ch & 0x7f; else b[k] = '?'; } return b; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_win32_scsi * psp = vp->implp; const char * cp; cp = safe_strerror(psp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } sg3_utils-1.40/lib/sg_cmds_mmc.c0000664000175000017500000003002512176051475015545 0ustar douggdougg/* * Copyright (c) 2008-2013 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_mmc.h" #include "sg_pt.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define GET_CONFIG_CMD 0x46 #define GET_CONFIG_CMD_LEN 10 #define GET_PERFORMANCE_CMD 0xac #define GET_PERFORMANCE_CMD_LEN 12 #define SET_CD_SPEED_CMD 0xbb #define SET_CD_SPEED_CMDLEN 12 #define SET_STREAMING_CMD 0xb6 #define SET_STREAMING_CMDLEN 12 /* Invokes a SCSI SET CD SPEED command (MMC). * Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> command not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_set_cd_speed(int sg_fd, int rot_control, int drv_read_speed, int drv_write_speed, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char scsCmdBlk[SET_CD_SPEED_CMDLEN] = {SET_CD_SPEED_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ,0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; scsCmdBlk[1] |= (rot_control & 0x3); scsCmdBlk[2] = (drv_read_speed >> 8) & 0xff; scsCmdBlk[3] = drv_read_speed & 0xff; scsCmdBlk[4] = (drv_write_speed >> 8) & 0xff; scsCmdBlk[5] = drv_write_speed & 0xff; if (verbose) { fprintf(sg_warnings_strm, " set cd speed cdb: "); for (k = 0; k < SET_CD_SPEED_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", scsCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "set cd speed: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, scsCmdBlk, sizeof(scsCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "set cd speed", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: case SG_LIB_CAT_ABORTED_COMMAND: ret = sense_cat; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = -1; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI GET CONFIGURATION command (MMC-3,4,5). * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp, int mx_resp_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char gcCmdBlk[GET_CONFIG_CMD_LEN] = {GET_CONFIG_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if ((rt < 0) || (rt > 3)) { fprintf(sg_warnings_strm, "Bad rt value: %d\n", rt); return -1; } gcCmdBlk[1] = (rt & 0x3); if ((starting < 0) || (starting > 0xffff)) { fprintf(sg_warnings_strm, "Bad starting field number: 0x%x\n", starting); return -1; } gcCmdBlk[2] = (unsigned char)((starting >> 8) & 0xff); gcCmdBlk[3] = (unsigned char)(starting & 0xff); if ((mx_resp_len < 0) || (mx_resp_len > 0xffff)) { fprintf(sg_warnings_strm, "Bad mx_resp_len: 0x%x\n", starting); return -1; } gcCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); gcCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { fprintf(sg_warnings_strm, " Get Configuration cdb: "); for (k = 0; k < GET_CONFIG_CMD_LEN; ++k) fprintf(sg_warnings_strm, "%02x ", gcCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "get configuration: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, gcCmdBlk, sizeof(gcCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "get configuration", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_ABORTED_COMMAND: ret = sense_cat; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = -1; break; } } else { if ((verbose > 2) && (ret > 3)) { unsigned char * ucp; int len; ucp = (unsigned char *)resp; len = (ucp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3] + 4; if (len < 0) len = 0; len = (ret < len) ? ret : len; fprintf(sg_warnings_strm, " get configuration: response%s\n", (len > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (len > 256 ? 256 : len), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI GET PERFORMANCE command (MMC-3...6). * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_get_performance(int sg_fd, int data_type, unsigned int starting_lba, int max_num_desc, int ttype, void * resp, int mx_resp_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char gpCmdBlk[GET_PERFORMANCE_CMD_LEN] = {GET_PERFORMANCE_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if ((data_type < 0) || (data_type > 0x1f)) { fprintf(sg_warnings_strm, "Bad data_type value: %d\n", data_type); return -1; } gpCmdBlk[1] = (data_type & 0x1f); gpCmdBlk[2] = (unsigned char)((starting_lba >> 24) & 0xff); gpCmdBlk[3] = (unsigned char)((starting_lba >> 16) & 0xff); gpCmdBlk[4] = (unsigned char)((starting_lba >> 8) & 0xff); gpCmdBlk[3] = (unsigned char)(starting_lba & 0xff); if ((max_num_desc < 0) || (max_num_desc > 0xffff)) { fprintf(sg_warnings_strm, "Bad max_num_desc: 0x%x\n", max_num_desc); return -1; } gpCmdBlk[8] = (unsigned char)((max_num_desc >> 8) & 0xff); gpCmdBlk[9] = (unsigned char)(max_num_desc & 0xff); if ((ttype < 0) || (ttype > 0xff)) { fprintf(sg_warnings_strm, "Bad type: 0x%x\n", ttype); return -1; } gpCmdBlk[10] = (unsigned char)ttype; if (verbose) { fprintf(sg_warnings_strm, " Get Performance cdb: "); for (k = 0; k < GET_PERFORMANCE_CMD_LEN; ++k) fprintf(sg_warnings_strm, "%02x ", gpCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "get performance: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, gpCmdBlk, sizeof(gpCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "get performance", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_ABORTED_COMMAND: ret = sense_cat; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = -1; break; } } else { if ((verbose > 2) && (ret > 3)) { unsigned char * ucp; int len; ucp = (unsigned char *)resp; len = (ucp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3] + 4; if (len < 0) len = 0; len = (ret < len) ? ret : len; fprintf(sg_warnings_strm, " get performance:: response%s\n", (len > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (len > 256 ? 256 : len), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI SET STREAMING command (MMC). Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Set Streaming not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_NOT_READY -> device not ready, * -1 -> other failure */ int sg_ll_set_streaming(int sg_fd, int type, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char ssCmdBlk[SET_STREAMING_CMDLEN] = {SET_STREAMING_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; ssCmdBlk[8] = type; ssCmdBlk[9] = (param_len >> 8) & 0xff; ssCmdBlk[10] = param_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " set streaming cdb: "); for (k = 0; k < SET_STREAMING_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", ssCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " set streaming " "parameter list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "set streaming: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, ssCmdBlk, sizeof(ssCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "set streaming", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_ABORTED_COMMAND: ret = sense_cat; break; case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = -1; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.40/lib/sg_pt_osf1.c0000664000175000017500000003033412061626602015332 0ustar douggdougg/* * Copyright (c) 2005-2010 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_pt.h" #include "sg_lib.h" /* Changed to use struct sg_pt_base 20070403 */ #define OSF1_MAXDEV 64 struct osf1_dev_channel { int bus; int tgt; int lun; }; // Private table of open devices: guaranteed zero on startup since // part of static data. static struct osf1_dev_channel *devicetable[OSF1_MAXDEV] = {0}; static char *cam_dev = "/dev/cam"; static int camfd; static int camopened = 0; struct sg_pt_osf1_scsi { unsigned char * cdb; int cdb_len; unsigned char * sense; int sense_len; unsigned char * dxferp; int dxfer_len; int dxfer_dir; int scsi_status; int resid; int sense_resid; int in_err; int os_err; int transport_err; }; struct sg_pt_base { struct sg_pt_osf1_scsi impl; }; /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose) { int oflags = 0 /* O_NONBLOCK*/ ; oflags |= (read_only ? O_RDONLY : O_RDWR); return scsi_pt_open_flags(device_name, oflags, verbose); } /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. The 'flags' argument is ignored in OSF-1. * Returns >= 0 if successful, otherwise returns negated errno. */ int scsi_pt_open_flags(const char * device_name, int flags, int verbose) { struct osf1_dev_channel *fdchan; int fd, k; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (!camopened) { camfd = open(cam_dev, O_RDWR, 0); if (camfd < 0) return -1; camopened++; } // Search table for a free entry for (k = 0; k < OSF1_MAXDEV; k++) if (! devicetable[k]) break; if (k == OSF1_MAXDEV) { if (verbose) fprintf(sg_warnings_strm, "too many open devices " "(%d)\n", OSF1_MAXDEV); errno=EMFILE; return -1; } fdchan = (struct osf1_dev_channel *)calloc(1, sizeof(struct osf1_dev_channel)); if (fdchan == NULL) { // errno already set by call to malloc() return -1; } fd = open(device_name, O_RDONLY|O_NONBLOCK); if (fd > 0) { device_info_t devinfo; bzero(&devinfo, sizeof(devinfo)); if (ioctl(fd, DEVGETINFO, &devinfo) == 0) { fdchan->bus = devinfo.v1.businfo.bus.scsi.bus_num; fdchan->tgt = devinfo.v1.businfo.bus.scsi.tgt_id; fdchan->lun = devinfo.v1.businfo.bus.scsi.lun; } close (fd); } else { free(fdchan); return -1; } devicetable[k] = fdchan; return k; } /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd) { struct osf1_dev_channel *fdchan; int i; if ((device_fd < 0) || (device_fd >= OSF1_MAXDEV)) { errno = ENODEV; return -1; } fdchan = devicetable[device_fd]; if (NULL == fdchan) { errno = ENODEV; return -1; } free(fdchan); devicetable[device_fd] = NULL; for (i = 0; i < OSF1_MAXDEV; i++) { if (devicetable[i]) break; } if (i == OSF1_MAXDEV) { close(camfd); camopened = 0; } return 0; } struct sg_pt_base * construct_scsi_pt_obj() { struct sg_pt_osf1_scsi * ptp; ptp = (struct sg_pt_osf1_scsi *)malloc(sizeof(struct sg_pt_osf1_scsi)); if (ptp) { bzero(ptp, sizeof(struct sg_pt_osf1_scsi)); ptp->dxfer_dir = CAM_DIR_NONE; } return (struct sg_pt_base *)ptp; } void destruct_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp) free(ptp); } void clear_scsi_pt_obj(struct sg_pt_base * vp) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp) { bzero(ptp, sizeof(struct sg_pt_osf1_scsi)); ptp->dxfer_dir = CAM_DIR_NONE; } } void set_scsi_pt_cdb(struct sg_pt_base * vp, const unsigned char * cdb, int cdb_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->cdb) ++ptp->in_err; ptp->cdb = (unsigned char *)cdb; ptp->cdb_len = cdb_len; } void set_scsi_pt_sense(struct sg_pt_base * vp, unsigned char * sense, int max_sense_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->sense) ++ptp->in_err; bzero(sense, max_sense_len); ptp->sense = sense; ptp->sense_len = max_sense_len; } /* from device */ void set_scsi_pt_data_in(struct sg_pt_base * vp, unsigned char * dxferp, int dxfer_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->dxferp = dxferp; ptp->dxfer_len = dxfer_len; ptp->dxfer_dir = CAM_DIR_IN; } } /* to device */ void set_scsi_pt_data_out(struct sg_pt_base * vp, const unsigned char * dxferp, int dxfer_len) { struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->dxferp) ++ptp->in_err; if (dxfer_len > 0) { ptp->dxferp = (unsigned char *)dxferp; ptp->dxfer_len = dxfer_len; ptp->dxfer_dir = CAM_DIR_OUT; } } void set_scsi_pt_packet_id(struct sg_pt_base * vp, int pack_id) { } void set_scsi_pt_tag(struct sg_pt_base * vp, uint64_t tag) { struct sg_pt_osf1_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_task_management(struct sg_pt_base * vp, int tmf_code) { struct sg_pt_osf1_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_task_attr(struct sg_pt_base * vp, int attrib, int priority) { struct sg_pt_osf1_scsi * ptp = &vp->impl; ++ptp->in_err; } void set_scsi_pt_flags(struct sg_pt_base * objp, int flags) { /* do nothing, suppress warnings */ objp = objp; flags = flags; } static int release_sim(struct sg_pt_base *vp, int device_fd, int verbose) { struct sg_pt_osf1_scsi * ptp = &vp->impl; struct osf1_dev_channel *fdchan = devicetable[device_fd]; UAGT_CAM_CCB uagt; CCB_RELSIM relsim; int retval; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; bzero(&uagt, sizeof(uagt)); bzero(&relsim, sizeof(relsim)); uagt.uagt_ccb = (CCB_HEADER *) &relsim; uagt.uagt_ccblen = sizeof(relsim); relsim.cam_ch.cam_ccb_len = sizeof(relsim); relsim.cam_ch.cam_func_code = XPT_REL_SIMQ; relsim.cam_ch.cam_flags = CAM_DIR_IN | CAM_DIS_CALLBACK; relsim.cam_ch.cam_path_id = fdchan->bus; relsim.cam_ch.cam_target_id = fdchan->tgt; relsim.cam_ch.cam_target_lun = fdchan->lun; retval = ioctl(camfd, UAGT_CAM_IO, &uagt); if (retval < 0) { if (verbose) fprintf(sg_warnings_strm, "CAM ioctl error (Release SIM Queue)\n"); } return retval; } int do_scsi_pt(struct sg_pt_base * vp, int device_fd, int time_secs, int verbose) { struct sg_pt_osf1_scsi * ptp = &vp->impl; struct osf1_dev_channel *fdchan; int len, retval; CCB_SCSIIO ccb; UAGT_CAM_CCB uagt; unsigned char sensep[ADDL_SENSE_LENGTH]; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; ptp->os_err = 0; if (ptp->in_err) { if (verbose) fprintf(sg_warnings_strm, "Replicated or unused set_scsi_pt...\n"); return SCSI_PT_DO_BAD_PARAMS; } if (NULL == ptp->cdb) { if (verbose) fprintf(sg_warnings_strm, "No command (cdb) given\n"); return SCSI_PT_DO_BAD_PARAMS; } if ((device_fd < 0) || (device_fd >= OSF1_MAXDEV)) { if (verbose) fprintf(sg_warnings_strm, "Bad file descriptor\n"); ptp->os_err = ENODEV; return -ptp->os_err; } fdchan = devicetable[device_fd]; if (NULL == fdchan) { if (verbose) fprintf(sg_warnings_strm, "File descriptor closed??\n"); ptp->os_err = ENODEV; return -ptp->os_err; } if (0 == camopened) { if (verbose) fprintf(sg_warnings_strm, "No open CAM device\n"); return SCSI_PT_DO_BAD_PARAMS; } bzero(&uagt, sizeof(uagt)); bzero(&ccb, sizeof(ccb)); uagt.uagt_ccb = (CCB_HEADER *) &ccb; uagt.uagt_ccblen = sizeof(ccb); uagt.uagt_snsbuf = ccb.cam_sense_ptr = ptp->sense ? ptp->sense : sensep; uagt.uagt_snslen = ccb.cam_sense_len = ptp->sense ? ptp->sense_len : sizeof sensep; uagt.uagt_buffer = ccb.cam_data_ptr = ptp->dxferp; uagt.uagt_buflen = ccb.cam_dxfer_len = ptp->dxfer_len; ccb.cam_timeout = time_secs; ccb.cam_ch.my_addr = (CCB_HEADER *) &ccb; ccb.cam_ch.cam_ccb_len = sizeof(ccb); ccb.cam_ch.cam_func_code = XPT_SCSI_IO; ccb.cam_ch.cam_flags = ptp->dxfer_dir; ccb.cam_cdb_len = ptp->cdb_len; memcpy(ccb.cam_cdb_io.cam_cdb_bytes, ptp->cdb, ptp->cdb_len); ccb.cam_ch.cam_path_id = fdchan->bus; ccb.cam_ch.cam_target_id = fdchan->tgt; ccb.cam_ch.cam_target_lun = fdchan->lun; if (ioctl(camfd, UAGT_CAM_IO, &uagt) < 0) { if (verbose) fprintf(sg_warnings_strm, "CAN I/O Error\n"); ptp->os_err = EIO; return -ptp->os_err; } if (((ccb.cam_ch.cam_status & CAM_STATUS_MASK) == CAM_REQ_CMP) || ((ccb.cam_ch.cam_status & CAM_STATUS_MASK) == CAM_REQ_CMP_ERR)) { ptp->scsi_status = ccb.cam_scsi_status; ptp->resid = ccb.cam_resid; if (ptp->sense) ptp->sense_resid = ccb.cam_sense_resid; } else { ptp->transport_err = 1; } /* If the SIM queue is frozen, release SIM queue. */ if (ccb.cam_ch.cam_status & CAM_SIM_QFRZN) release_sim(vp, device_fd, verbose); return 0; } int get_scsi_pt_result_category(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; if (ptp->os_err) return SCSI_PT_RESULT_OS_ERR; else if (ptp->transport_err) return SCSI_PT_RESULT_TRANSPORT_ERR; else if ((SAM_STAT_CHECK_CONDITION == ptp->scsi_status) || (SAM_STAT_COMMAND_TERMINATED == ptp->scsi_status)) return SCSI_PT_RESULT_SENSE; else if (ptp->scsi_status) return SCSI_PT_RESULT_STATUS; else return SCSI_PT_RESULT_GOOD; } int get_scsi_pt_resid(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->resid; } int get_scsi_pt_status_response(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->scsi_status; } int get_scsi_pt_sense_len(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; int len; len = ptp->sense_len - ptp->sense_resid; return (len > 0) ? len : 0; } int get_scsi_pt_duration_ms(const struct sg_pt_base * vp) { // const struct sg_pt_osf1_scsi * ptp = &vp->impl; return -1; } int get_scsi_pt_transport_err(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->transport_err; } int get_scsi_pt_os_err(const struct sg_pt_base * vp) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; return ptp->os_err; } char * get_scsi_pt_transport_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; if (0 == ptp->transport_err) { strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; return b; } strncpy(b, "no transport error available", max_b_len); b[max_b_len - 1] = '\0'; return b; } char * get_scsi_pt_os_err_str(const struct sg_pt_base * vp, int max_b_len, char * b) { const struct sg_pt_osf1_scsi * ptp = &vp->impl; const char * cp; cp = safe_strerror(ptp->os_err); strncpy(b, cp, max_b_len); if ((int)strlen(cp) >= max_b_len) b[max_b_len - 1] = '\0'; return b; } sg3_utils-1.40/lib/sg_cmds_extra.c0000664000175000017500000023601612407706337016125 0ustar douggdougg/* * Copyright (c) 1999-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include "sg_lib.h" #include "sg_lib_data.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" #ifdef HAVE_CONFIG_H #include "config.h" #endif #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ #define LONG_PT_TIMEOUT 7200 /* 7,200 seconds == 120 minutes */ #define SERVICE_ACTION_IN_16_CMD 0x9e #define SERVICE_ACTION_IN_16_CMDLEN 16 #define SERVICE_ACTION_OUT_16_CMD 0x9f #define SERVICE_ACTION_OUT_16_CMDLEN 16 #define MAINTENANCE_IN_CMD 0xa3 #define MAINTENANCE_IN_CMDLEN 12 #define MAINTENANCE_OUT_CMD 0xa4 #define MAINTENANCE_OUT_CMDLEN 12 #define ATA_PT_12_CMD 0xa1 #define ATA_PT_12_CMDLEN 12 #define ATA_PT_16_CMD 0x85 #define ATA_PT_16_CMDLEN 16 #define FORMAT_UNIT_CMD 0x4 #define FORMAT_UNIT_CMDLEN 6 #define PERSISTENT_RESERVE_IN_CMD 0x5e #define PERSISTENT_RESERVE_IN_CMDLEN 10 #define PERSISTENT_RESERVE_OUT_CMD 0x5f #define PERSISTENT_RESERVE_OUT_CMDLEN 10 #define READ_BLOCK_LIMITS_CMD 0x5 #define READ_BLOCK_LIMITS_CMDLEN 6 #define READ_BUFFER_CMD 0x3c #define READ_BUFFER_CMDLEN 10 #define READ_DEFECT10_CMD 0x37 #define READ_DEFECT10_CMDLEN 10 #define REASSIGN_BLKS_CMD 0x7 #define REASSIGN_BLKS_CMDLEN 6 #define RECEIVE_DIAGNOSTICS_CMD 0x1c #define RECEIVE_DIAGNOSTICS_CMDLEN 6 #define THIRD_PARTY_COPY_OUT_CMD 0x83 /* was EXTENDED_COPY_CMD */ #define THIRD_PARTY_COPY_OUT_CMDLEN 16 #define THIRD_PARTY_COPY_IN_CMD 0x84 /* was RECEIVE_COPY_RESULTS_CMD */ #define THIRD_PARTY_COPY_IN_CMDLEN 16 #define SEND_DIAGNOSTIC_CMD 0x1d #define SEND_DIAGNOSTIC_CMDLEN 6 #define SERVICE_ACTION_IN_12_CMD 0xab #define SERVICE_ACTION_IN_12_CMDLEN 12 #define READ_LONG10_CMD 0x3e #define READ_LONG10_CMDLEN 10 #define UNMAP_CMD 0x42 #define UNMAP_CMDLEN 10 #define VERIFY10_CMD 0x2f #define VERIFY10_CMDLEN 10 #define VERIFY16_CMD 0x8f #define VERIFY16_CMDLEN 16 #define WRITE_LONG10_CMD 0x3f #define WRITE_LONG10_CMDLEN 10 #define WRITE_BUFFER_CMD 0x3b #define WRITE_BUFFER_CMDLEN 10 #define GET_LBA_STATUS_SA 0x12 #define READ_LONG_16_SA 0x11 #define READ_MEDIA_SERIAL_NUM_SA 0x1 #define REPORT_IDENTIFYING_INFORMATION_SA 0x5 #define REPORT_TGT_PRT_GRP_SA 0xa #define SET_IDENTIFYING_INFORMATION_SA 0x6 #define SET_TGT_PRT_GRP_SA 0xa #define WRITE_LONG_16_SA 0x11 #define REPORT_REFERRALS_SA 0x13 #define EXTENDED_COPY_LID1_SA 0x0 /* Invokes a SCSI GET LBA STATUS command (SBC). Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp, int alloc_len, int noisy, int verbose) { int k, res, sense_cat, ret; unsigned char getLbaStatCmd[SERVICE_ACTION_IN_16_CMDLEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; memset(getLbaStatCmd, 0, sizeof(getLbaStatCmd)); getLbaStatCmd[0] = SERVICE_ACTION_IN_16_CMD; getLbaStatCmd[1] = GET_LBA_STATUS_SA; getLbaStatCmd[2] = (start_llba >> 56) & 0xff; getLbaStatCmd[3] = (start_llba >> 48) & 0xff; getLbaStatCmd[4] = (start_llba >> 40) & 0xff; getLbaStatCmd[5] = (start_llba >> 32) & 0xff; getLbaStatCmd[6] = (start_llba >> 24) & 0xff; getLbaStatCmd[7] = (start_llba >> 16) & 0xff; getLbaStatCmd[8] = (start_llba >> 8) & 0xff; getLbaStatCmd[9] = start_llba & 0xff; getLbaStatCmd[10] = (alloc_len >> 24) & 0xff; getLbaStatCmd[11] = (alloc_len >> 16) & 0xff; getLbaStatCmd[12] = (alloc_len >> 8) & 0xff; getLbaStatCmd[13] = alloc_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Get LBA status cmd: "); for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", getLbaStatCmd[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "get LBA status: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, getLbaStatCmd, sizeof(getLbaStatCmd)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, alloc_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "get LBA status", res, alloc_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " get LBA status: response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose) { return sg_ll_report_tgt_prt_grp2(sg_fd, resp, mx_resp_len, 0, noisy, verbose); } /* Invokes a SCSI REPORT TARGET PORT GROUPS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len, int extended, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char rtpgCmdBlk[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD, REPORT_TGT_PRT_GRP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (extended) { rtpgCmdBlk[1] |= 0x20; } rtpgCmdBlk[6] = (mx_resp_len >> 24) & 0xff; rtpgCmdBlk[7] = (mx_resp_len >> 16) & 0xff; rtpgCmdBlk[8] = (mx_resp_len >> 8) & 0xff; rtpgCmdBlk[9] = mx_resp_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " report target port groups cdb: "); for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rtpgCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "report target port groups: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rtpgCmdBlk, sizeof(rtpgCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report target port group", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " report target port group: " "response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI SET TARGET PORT GROUPS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_set_tgt_prt_grp(int sg_fd, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char stpgCmdBlk[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD, SET_TGT_PRT_GRP_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; stpgCmdBlk[6] = (param_len >> 24) & 0xff; stpgCmdBlk[7] = (param_len >> 16) & 0xff; stpgCmdBlk[8] = (param_len >> 8) & 0xff; stpgCmdBlk[9] = param_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " set target port groups cdb: "); for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", stpgCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " set target port groups " "parameter list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "set target port groups: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, stpgCmdBlk, sizeof(stpgCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "set target port group", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI REPORT REFERRALS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_report_referrals(int sg_fd, uint64_t start_llba, int one_seg, void * resp, int mx_resp_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char repRefCmdBlk[SERVICE_ACTION_IN_16_CMDLEN] = {SERVICE_ACTION_IN_16_CMD, REPORT_REFERRALS_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; repRefCmdBlk[2] = (start_llba >> 56) & 0xff; repRefCmdBlk[3] = (start_llba >> 48) & 0xff; repRefCmdBlk[4] = (start_llba >> 40) & 0xff; repRefCmdBlk[5] = (start_llba >> 32) & 0xff; repRefCmdBlk[6] = (start_llba >> 24) & 0xff; repRefCmdBlk[7] = (start_llba >> 16) & 0xff; repRefCmdBlk[8] = (start_llba >> 8) & 0xff; repRefCmdBlk[9] = start_llba & 0xff; repRefCmdBlk[10] = (mx_resp_len >> 24) & 0xff; repRefCmdBlk[11] = (mx_resp_len >> 16) & 0xff; repRefCmdBlk[12] = (mx_resp_len >> 8) & 0xff; repRefCmdBlk[13] = mx_resp_len & 0xff; repRefCmdBlk[14] = one_seg & 0x1; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " report referrals cdb: "); for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", repRefCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "report target port groups: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, repRefCmdBlk, sizeof(repRefCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report referrals", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " report referrals: response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can * take a long time, if so set long_duration flag in which case the timout * is set to 7200 seconds; if the value of long_duration is > 7200 then that * value is taken as the timeout value in seconds. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit, int devofl_bit, int unitofl_bit, int long_duration, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat, tmout; unsigned char senddiagCmdBlk[SEND_DIAGNOSTIC_CMDLEN] = {SEND_DIAGNOSTIC_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; senddiagCmdBlk[1] = (unsigned char)((sf_code << 5) | (pf_bit << 4) | (sf_bit << 2) | (devofl_bit << 1) | unitofl_bit); senddiagCmdBlk[3] = (unsigned char)((param_len >> 8) & 0xff); senddiagCmdBlk[4] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Send diagnostic cmd: "); for (k = 0; k < SEND_DIAGNOSTIC_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", senddiagCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " Send diagnostic parameter " "list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } } if (long_duration > LONG_PT_TIMEOUT) tmout = long_duration; else tmout = long_duration ? LONG_PT_TIMEOUT : DEF_PT_TIMEOUT; ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "send diagnostic: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, senddiagCmdBlk, sizeof(senddiagCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, verbose); ret = sg_cmds_process_resp(ptvp, "send diagnostic", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_receive_diag(int sg_fd, int pcv, int pg_code, void * resp, int mx_resp_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char rcvdiagCmdBlk[RECEIVE_DIAGNOSTICS_CMDLEN] = {RECEIVE_DIAGNOSTICS_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; rcvdiagCmdBlk[1] = (unsigned char)(pcv ? 0x1 : 0); rcvdiagCmdBlk[2] = (unsigned char)(pg_code); rcvdiagCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); rcvdiagCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Receive diagnostic results cmd: "); for (k = 0; k < RECEIVE_DIAGNOSTICS_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rcvdiagCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "receive diagnostic results: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rcvdiagCmdBlk, sizeof(rcvdiagCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "receive diagnostic results", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " receive diagnostic results: " "response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> success * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist, int dl_format, void * resp, int mx_resp_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char rdefCmdBlk[READ_DEFECT10_CMDLEN] = {READ_DEFECT10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; rdefCmdBlk[2] = (unsigned char)(((req_plist << 4) & 0x10) | ((req_glist << 3) & 0x8) | (dl_format & 0x7)); rdefCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); rdefCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (mx_resp_len > 0xffff) { fprintf(sg_warnings_strm, "mx_resp_len too big\n"); return -1; } if (verbose) { fprintf(sg_warnings_strm, " read defect (10) cdb: "); for (k = 0; k < READ_DEFECT10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rdefCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read defect (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rdefCmdBlk, sizeof(rdefCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read defect (10)", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read defect (10): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ MEDIA SERIAL NUMBER command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char rmsnCmdBlk[SERVICE_ACTION_IN_12_CMDLEN] = {SERVICE_ACTION_IN_12_CMD, READ_MEDIA_SERIAL_NUM_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; rmsnCmdBlk[6] = (mx_resp_len >> 24) & 0xff; rmsnCmdBlk[7] = (mx_resp_len >> 16) & 0xff; rmsnCmdBlk[8] = (mx_resp_len >> 8) & 0xff; rmsnCmdBlk[9] = mx_resp_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " read media serial number cdb: "); for (k = 0; k < SERVICE_ACTION_IN_12_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rmsnCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read media serial number: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rmsnCmdBlk, sizeof(rmsnCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read media serial number", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read media serial number: respon" "se%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI REPORT IDENTIFYING INFORMATION command. This command was * called REPORT DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_report_id_info(int sg_fd, int itype, void * resp, int max_resp_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char riiCmdBlk[MAINTENANCE_IN_CMDLEN] = {MAINTENANCE_IN_CMD, REPORT_IDENTIFYING_INFORMATION_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; riiCmdBlk[6] = (max_resp_len >> 24) & 0xff; riiCmdBlk[7] = (max_resp_len >> 16) & 0xff; riiCmdBlk[8] = (max_resp_len >> 8) & 0xff; riiCmdBlk[9] = max_resp_len & 0xff; riiCmdBlk[10] |= (itype << 1) & 0xfe; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Report identifying information cdb: "); for (k = 0; k < MAINTENANCE_IN_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", riiCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "report identifying information: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, riiCmdBlk, sizeof(riiCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, max_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report identifying information", res, max_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " report identifying information: " "response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI SET IDENTIFYING INFORMATION command. This command was * called SET DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_set_id_info(int sg_fd, int itype, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char siiCmdBlk[MAINTENANCE_OUT_CMDLEN] = {MAINTENANCE_OUT_CMD, SET_IDENTIFYING_INFORMATION_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; siiCmdBlk[6] = (param_len >> 24) & 0xff; siiCmdBlk[7] = (param_len >> 16) & 0xff; siiCmdBlk[8] = (param_len >> 8) & 0xff; siiCmdBlk[9] = param_len & 0xff; siiCmdBlk[10] |= (itype << 1) & 0xfe; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Set identifying information cdb: "); for (k = 0; k < MAINTENANCE_OUT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", siiCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " Set identifying information " "parameter list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Set identifying information: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, siiCmdBlk, sizeof(siiCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "set identifying information", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_format_unit(int sg_fd, int fmtpinfo, int longlist, int fmtdata, int cmplst, int dlist_format, int timeout_secs, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat, tmout; unsigned char fuCmdBlk[FORMAT_UNIT_CMDLEN] = {FORMAT_UNIT_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (fmtpinfo) fuCmdBlk[1] |= (fmtpinfo << 6); if (longlist) fuCmdBlk[1] |= 0x20; if (fmtdata) fuCmdBlk[1] |= 0x10; if (cmplst) fuCmdBlk[1] |= 0x8; if (dlist_format) fuCmdBlk[1] |= (dlist_format & 0x7); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; if (verbose) { fprintf(sg_warnings_strm, " format cdb: "); for (k = 0; k < 6; ++k) fprintf(sg_warnings_strm, "%02x ", fuCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if ((verbose > 1) && (param_len > 0)) { fprintf(sg_warnings_strm, " format parameter list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "format unit: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, fuCmdBlk, sizeof(fuCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, verbose); ret = sg_cmds_process_resp(ptvp, "format unit", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI REASSIGN BLOCKS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_reassign_blocks(int sg_fd, int longlba, int longlist, void * paramp, int param_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char reassCmdBlk[REASSIGN_BLKS_CMDLEN] = {REASSIGN_BLKS_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; reassCmdBlk[1] = (unsigned char)(((longlba << 1) & 0x2) | (longlist & 0x1)); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " reassign blocks cdb: "); for (k = 0; k < REASSIGN_BLKS_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", reassCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } if (verbose > 1) { fprintf(sg_warnings_strm, " reassign blocks parameter list\n"); dStrHexErr((const char *)paramp, param_len, -1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "reassign blocks: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, reassCmdBlk, sizeof(reassCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "reassign blocks", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI PERSISTENT RESERVE IN command (SPC). Returns 0 * when successful, various SG_LIB_CAT_* positive values or * -1 -> other errors */ int sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp, int mx_resp_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char prinCmdBlk[PERSISTENT_RESERVE_IN_CMDLEN] = {PERSISTENT_RESERVE_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (rq_servact > 0) prinCmdBlk[1] = (unsigned char)(rq_servact & 0x1f); prinCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); prinCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Persistent Reservation In cmd: "); for (k = 0; k < PERSISTENT_RESERVE_IN_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", prinCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "persistent reservation in: out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, prinCmdBlk, sizeof(prinCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "persistent reservation in", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " persistent reserve in: " "response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI PERSISTENT RESERVE OUT command (SPC). Returns 0 * when successful, various SG_LIB_CAT_* positive values or * -1 -> other errors */ int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope, unsigned int rq_type, void * paramp, int param_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char proutCmdBlk[PERSISTENT_RESERVE_OUT_CMDLEN] = {PERSISTENT_RESERVE_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (rq_servact > 0) proutCmdBlk[1] = (unsigned char)(rq_servact & 0x1f); proutCmdBlk[2] = (((rq_scope & 0xf) << 4) | (rq_type & 0xf)); proutCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); proutCmdBlk[8] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Persistent Reservation Out cmd: "); for (k = 0; k < PERSISTENT_RESERVE_OUT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", proutCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if (verbose > 1) { fprintf(sg_warnings_strm, " Persistent Reservation Out " "parameters:\n"); dStrHexErr((const char *)paramp, param_len, 0); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "persistent reserve out: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, proutCmdBlk, sizeof(proutCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "persistent reserve out", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } static int has_blk_ili(unsigned char * sensep, int sb_len) { int resp_code; const unsigned char * cup; if (sb_len < 8) return 0; resp_code = (0x7f & sensep[0]); if (resp_code >= 0x72) { /* descriptor format */ /* find block command descriptor */ if ((cup = sg_scsi_sense_desc_find(sensep, sb_len, 0x5))) return ((cup[3] & 0x20) ? 1 : 0); } else /* fixed */ return ((sensep[2] & 0x20) ? 1 : 0); return 0; } /* Invokes a SCSI READ LONG (10) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_long10(int sg_fd, int pblock, int correct, unsigned int lba, void * resp, int xfer_len, int * offsetp, int noisy, int verbose) { int k, res, sense_cat, ret; unsigned char readLongCmdBlk[READ_LONG10_CMDLEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; memset(readLongCmdBlk, 0, READ_LONG10_CMDLEN); readLongCmdBlk[0] = READ_LONG10_CMD; if (pblock) readLongCmdBlk[1] |= 0x4; if (correct) readLongCmdBlk[1] |= 0x2; readLongCmdBlk[2] = (lba >> 24) & 0xff; readLongCmdBlk[3] = (lba >> 16) & 0xff; readLongCmdBlk[4] = (lba >> 8) & 0xff; readLongCmdBlk[5] = lba & 0xff; readLongCmdBlk[7] = (xfer_len >> 8) & 0xff; readLongCmdBlk[8] = xfer_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Read Long (10) cmd: "); for (k = 0; k < READ_LONG10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", readLongCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read long (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, readLongCmdBlk, sizeof(readLongCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read long (10)", res, xfer_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { int valid, slen, ili; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); ili = has_blk_ili(sense_b, slen); if (valid && ili) { if (offsetp) *offsetp = (int)(int64_t)ull; ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO; } else { if (verbose > 1) fprintf(sg_warnings_strm, " info field: 0x%" PRIx64 ", valid: %d, ili: %d\n", ull, valid, ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read long(10): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ LONG (16) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_long16(int sg_fd, int pblock, int correct, uint64_t llba, void * resp, int xfer_len, int * offsetp, int noisy, int verbose) { int k, res, sense_cat, ret; unsigned char readLongCmdBlk[SERVICE_ACTION_IN_16_CMDLEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; memset(readLongCmdBlk, 0, sizeof(readLongCmdBlk)); readLongCmdBlk[0] = SERVICE_ACTION_IN_16_CMD; readLongCmdBlk[1] = READ_LONG_16_SA; if (pblock) readLongCmdBlk[14] |= 0x2; if (correct) readLongCmdBlk[14] |= 0x1; readLongCmdBlk[2] = (llba >> 56) & 0xff; readLongCmdBlk[3] = (llba >> 48) & 0xff; readLongCmdBlk[4] = (llba >> 40) & 0xff; readLongCmdBlk[5] = (llba >> 32) & 0xff; readLongCmdBlk[6] = (llba >> 24) & 0xff; readLongCmdBlk[7] = (llba >> 16) & 0xff; readLongCmdBlk[8] = (llba >> 8) & 0xff; readLongCmdBlk[9] = llba & 0xff; readLongCmdBlk[12] = (xfer_len >> 8) & 0xff; readLongCmdBlk[13] = xfer_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Read Long (16) cmd: "); for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", readLongCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read long (16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, readLongCmdBlk, sizeof(readLongCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read long (16)", res, xfer_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { int valid, slen, ili; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); ili = has_blk_ili(sense_b, slen); if (valid && ili) { if (offsetp) *offsetp = (int)(int64_t)ull; ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO; } else { if (verbose > 1) fprintf(sg_warnings_strm, " info field: 0x%" PRIx64 ", valid: %d, ili: %d\n", ull, valid, ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read long(16): response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_write_long10(int sg_fd, int cor_dis, int wr_uncor, int pblock, unsigned int lba, void * data_out, int xfer_len, int * offsetp, int noisy, int verbose) { int k, res, sense_cat, ret; unsigned char writeLongCmdBlk[WRITE_LONG10_CMDLEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; memset(writeLongCmdBlk, 0, WRITE_LONG10_CMDLEN); writeLongCmdBlk[0] = WRITE_LONG10_CMD; if (cor_dis) writeLongCmdBlk[1] |= 0x80; if (wr_uncor) writeLongCmdBlk[1] |= 0x40; if (pblock) writeLongCmdBlk[1] |= 0x20; writeLongCmdBlk[2] = (lba >> 24) & 0xff; writeLongCmdBlk[3] = (lba >> 16) & 0xff; writeLongCmdBlk[4] = (lba >> 8) & 0xff; writeLongCmdBlk[5] = lba & 0xff; writeLongCmdBlk[7] = (xfer_len >> 8) & 0xff; writeLongCmdBlk[8] = xfer_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Write Long (10) cmd: "); for (k = 0; k < (int)sizeof(writeLongCmdBlk); ++k) fprintf(sg_warnings_strm, "%02x ", writeLongCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "write long(10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, writeLongCmdBlk, sizeof(writeLongCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "write long(10)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { int valid, slen, ili; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); ili = has_blk_ili(sense_b, slen); if (valid && ili) { if (offsetp) *offsetp = (int)(int64_t)ull; ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO; } else { if (verbose > 1) fprintf(sg_warnings_strm, " info field: 0x%" PRIx64 ", valid: %d, ili: %d\n", ull, valid, ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI WRITE LONG (16) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_write_long16(int sg_fd, int cor_dis, int wr_uncor, int pblock, uint64_t llba, void * data_out, int xfer_len, int * offsetp, int noisy, int verbose) { int k, res, sense_cat, ret; unsigned char writeLongCmdBlk[SERVICE_ACTION_OUT_16_CMDLEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; memset(writeLongCmdBlk, 0, sizeof(writeLongCmdBlk)); writeLongCmdBlk[0] = SERVICE_ACTION_OUT_16_CMD; writeLongCmdBlk[1] = WRITE_LONG_16_SA; if (cor_dis) writeLongCmdBlk[1] |= 0x80; if (wr_uncor) writeLongCmdBlk[1] |= 0x40; if (pblock) writeLongCmdBlk[1] |= 0x20; writeLongCmdBlk[2] = (llba >> 56) & 0xff; writeLongCmdBlk[3] = (llba >> 48) & 0xff; writeLongCmdBlk[4] = (llba >> 40) & 0xff; writeLongCmdBlk[5] = (llba >> 32) & 0xff; writeLongCmdBlk[6] = (llba >> 24) & 0xff; writeLongCmdBlk[7] = (llba >> 16) & 0xff; writeLongCmdBlk[8] = (llba >> 8) & 0xff; writeLongCmdBlk[9] = llba & 0xff; writeLongCmdBlk[12] = (xfer_len >> 8) & 0xff; writeLongCmdBlk[13] = xfer_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Write Long (16) cmd: "); for (k = 0; k < SERVICE_ACTION_OUT_16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", writeLongCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "write long(16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, writeLongCmdBlk, sizeof(writeLongCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, xfer_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "write long(16)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_ILLEGAL_REQ: { int valid, slen, ili; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); ili = has_blk_ili(sense_b, slen); if (valid && ili) { if (offsetp) *offsetp = (int)(int64_t)ull; ret = SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO; } else { if (verbose > 1) fprintf(sg_warnings_strm, " info field: 0x%" PRIx64 ", valid: %d, ili: %d\n", ull, valid, ili); ret = SG_LIB_CAT_ILLEGAL_REQ; } } break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI VERIFY (10) command (SBC and MMC). * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes. * Returns of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_verify10(int sg_fd, int vrprotect, int dpo, int bytchk, unsigned int lba, int veri_len, void * data_out, int data_out_len, unsigned int * infop, int noisy, int verbose) { int k, res, ret, sense_cat, slen; unsigned char vCmdBlk[VERIFY10_CMDLEN] = {VERIFY10_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */ vCmdBlk[1] = ((vrprotect & 0x7) << 5) | ((dpo & 0x1) << 4) | ((bytchk & 0x3) << 1) ; vCmdBlk[2] = (unsigned char)((lba >> 24) & 0xff); vCmdBlk[3] = (unsigned char)((lba >> 16) & 0xff); vCmdBlk[4] = (unsigned char)((lba >> 8) & 0xff); vCmdBlk[5] = (unsigned char)(lba & 0xff); vCmdBlk[7] = (unsigned char)((veri_len >> 8) & 0xff); vCmdBlk[8] = (unsigned char)(veri_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose > 1) { fprintf(sg_warnings_strm, " Verify(10) cdb: "); for (k = 0; k < VERIFY10_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", vCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) { k = data_out_len > 4104 ? 4104 : data_out_len; fprintf(sg_warnings_strm, " data_out buffer%s\n", (data_out_len > 4104 ? ", first 4104 bytes" : "")); dStrHexErr((const char *)data_out, k, verbose < 5); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "verify (10): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, vCmdBlk, sizeof(vCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (data_out_len > 0) set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "verify (10)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { int valid; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) { if (infop) *infop = (unsigned int)ull; ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; } else ret = SG_LIB_CAT_MEDIUM_HARD; } break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI VERIFY (16) command (SBC and MMC). * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes. * Returns of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_verify16(int sg_fd, int vrprotect, int dpo, int bytchk, uint64_t llba, int veri_len, int group_num, void * data_out, int data_out_len, uint64_t * infop, int noisy, int verbose) { int k, res, ret, sense_cat, slen; unsigned char vCmdBlk[VERIFY16_CMDLEN] = {VERIFY16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; /* N.B. BYTCHK field expanded to 2 bits sbc3r34 */ vCmdBlk[1] = ((vrprotect & 0x7) << 5) | ((dpo & 0x1) << 4) | ((bytchk & 0x3) << 1) ; vCmdBlk[2] = (llba >> 56) & 0xff; vCmdBlk[3] = (llba >> 48) & 0xff; vCmdBlk[4] = (llba >> 40) & 0xff; vCmdBlk[5] = (llba >> 32) & 0xff; vCmdBlk[6] = (llba >> 24) & 0xff; vCmdBlk[7] = (llba >> 16) & 0xff; vCmdBlk[8] = (llba >> 8) & 0xff; vCmdBlk[9] = llba & 0xff; vCmdBlk[10] = (veri_len >> 24) & 0xff; vCmdBlk[11] = (veri_len >> 16) & 0xff; vCmdBlk[12] = (veri_len >> 8) & 0xff; vCmdBlk[13] = veri_len & 0xff; vCmdBlk[14] = group_num & 0x1f; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose > 1) { fprintf(sg_warnings_strm, " Verify(16) cdb: "); for (k = 0; k < VERIFY16_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", vCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 3) && bytchk && data_out && (data_out_len > 0)) { k = data_out_len > 4104 ? 4104 : data_out_len; fprintf(sg_warnings_strm, " data_out buffer%s\n", (data_out_len > 4104 ? ", first 4104 bytes" : "")); dStrHexErr((const char *)data_out, k, verbose < 5); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "verify (16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, vCmdBlk, sizeof(vCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); if (data_out_len > 0) set_scsi_pt_data_out(ptvp, (unsigned char *)data_out, data_out_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "verify (16)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { int valid; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) { if (infop) *infop = ull; ret = SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; } else ret = SG_LIB_CAT_MEDIUM_HARD; } break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len * is 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16 * then a ATA PASS-THROUGH (16) command is called. If cdb_len is any other * value -1 is returned. After copying from cdbp to an internal buffer, * the first byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is * set to 0x85 if cdb_len is 16. The last byte (offset 11 or offset 15) is * set to 0x0 in the internal buffer. If timeout_secs <= 0 then the timeout * is set to 60 seconds. For data in or out transfers set dinp or doutp, * and dlen to the number of bytes to transfer. If dlen is zero then no data * transfer is assumed. If sense buffer obtained then it is written to * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI * status value (>= 0) or -1 if other error. Users are expected to check the * sense buffer themselves. If available the data in resid is written to * residp. Note in SAT-2 and later, fixed format sense data may be placed in * *sensep in which case sensep[0]==0x70 . */ int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len, int timeout_secs, void * dinp, void * doutp, int dlen, unsigned char * sensep, int max_sense_len, unsigned char * ata_return_dp, int max_ata_return_len, int * residp, int verbose) { int k, res, slen, duration; unsigned char aptCmdBlk[ATA_PT_16_CMDLEN] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; unsigned char * sp; const unsigned char * ucp; struct sg_pt_base * ptvp; const char * cnamep; char b[256]; int ret = -1; b[0] = '\0'; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; cnamep = (12 == cdb_len) ? "ATA pass through (12)" : "ATA pass through (16)"; if ((NULL == cdbp) || ((12 != cdb_len) && (16 != cdb_len))) { if (verbose) { if (NULL == cdbp) fprintf(sg_warnings_strm, "%s NULL cdb pointer\n", cnamep); else fprintf(sg_warnings_strm, "cdb_len must be 12 or 16\n"); } return -1; } aptCmdBlk[0] = (12 == cdb_len) ? ATA_PT_12_CMD : ATA_PT_16_CMD; if (sensep && (max_sense_len >= (int)sizeof(sense_b))) { sp = sensep; slen = max_sense_len; } else { sp = sense_b; slen = sizeof(sense_b); } if (12 == cdb_len) memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 11) ? 10 : (cdb_len - 1))); else memcpy(aptCmdBlk + 1, cdbp + 1, ((cdb_len > 15) ? 14 : (cdb_len - 1))); if (verbose) { fprintf(sg_warnings_strm, " %s cdb: ", cnamep); for (k = 0; k < cdb_len; ++k) fprintf(sg_warnings_strm, "%02x ", aptCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "%s: out of memory\n", cnamep); return -1; } set_scsi_pt_cdb(ptvp, aptCmdBlk, cdb_len); set_scsi_pt_sense(ptvp, sp, slen); if (dlen > 0) { if (dinp) set_scsi_pt_data_in(ptvp, (unsigned char *)dinp, dlen); else if (doutp) set_scsi_pt_data_out(ptvp, (unsigned char *)doutp, dlen); } res = do_scsi_pt(ptvp, sg_fd, ((timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT), verbose); if (SCSI_PT_DO_BAD_PARAMS == res) { if (verbose) fprintf(sg_warnings_strm, "%s: bad parameters\n", cnamep); goto out; } else if (SCSI_PT_DO_TIMEOUT == res) { if (verbose) fprintf(sg_warnings_strm, "%s: timeout\n", cnamep); goto out; } else if (res > 2) { if (verbose) fprintf(sg_warnings_strm, "%s: do_scsi_pt: errno=%d\n", cnamep, -res); } if ((verbose > 2) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) fprintf(sg_warnings_strm, " duration=%d ms\n", duration); switch (get_scsi_pt_result_category(ptvp)) { case SCSI_PT_RESULT_GOOD: if ((sensep) && (max_sense_len > 0)) *sensep = 0; if ((ata_return_dp) && (max_ata_return_len > 0)) *ata_return_dp = 0; if (residp && (dlen > 0)) *residp = get_scsi_pt_resid(ptvp); ret = 0; break; case SCSI_PT_RESULT_STATUS: /* other than GOOD + CHECK CONDITION */ if ((sensep) && (max_sense_len > 0)) *sensep = 0; if ((ata_return_dp) && (max_ata_return_len > 0)) *ata_return_dp = 0; ret = get_scsi_pt_status_response(ptvp); break; case SCSI_PT_RESULT_SENSE: if (sensep && (sp != sensep)) { k = get_scsi_pt_sense_len(ptvp); k = (k > max_sense_len) ? max_sense_len : k; memcpy(sensep, sp, k); } if (ata_return_dp && (max_ata_return_len > 0)) { /* search for ATA return descriptor */ ucp = sg_scsi_sense_desc_find(sp, slen, 0x9); if (ucp) { k = ucp[1] + 2; k = (k > max_ata_return_len) ? max_ata_return_len : k; memcpy(ata_return_dp, ucp, k); } else ata_return_dp[0] = 0x0; } if (residp && (dlen > 0)) *residp = get_scsi_pt_resid(ptvp); ret = get_scsi_pt_status_response(ptvp); break; case SCSI_PT_RESULT_TRANSPORT_ERR: if (verbose) fprintf(sg_warnings_strm, "%s: transport error: %s\n", cnamep, get_scsi_pt_transport_err_str(ptvp, sizeof(b) , b)); break; case SCSI_PT_RESULT_OS_ERR: if (verbose) fprintf(sg_warnings_strm, "%s: os error: %s\n", cnamep, get_scsi_pt_os_err_str(ptvp, sizeof(b) , b)); break; default: if (verbose) fprintf(sg_warnings_strm, "%s: unknown pt_result_category=%d\n", cnamep, get_scsi_pt_result_category(ptvp)); break; } out: destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ BUFFER command (SPC). Return of 0 -> success * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset, void * resp, int mx_resp_len, int noisy, int verbose) { int res, k, ret, sense_cat; unsigned char rbufCmdBlk[READ_BUFFER_CMDLEN] = {READ_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; rbufCmdBlk[1] = (unsigned char)(mode & 0x1f); rbufCmdBlk[2] = (unsigned char)(buffer_id & 0xff); rbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff); rbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff); rbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff); rbufCmdBlk[6] = (unsigned char)((mx_resp_len >> 16) & 0xff); rbufCmdBlk[7] = (unsigned char)((mx_resp_len >> 8) & 0xff); rbufCmdBlk[8] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " read buffer cdb: "); for (k = 0; k < READ_BUFFER_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rbufCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read buffer: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rbufCmdBlk, sizeof(rbufCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read buffer", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read buffer: response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 -> success * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char wbufCmdBlk[WRITE_BUFFER_CMDLEN] = {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; wbufCmdBlk[1] = (unsigned char)(mode & 0x1f); wbufCmdBlk[2] = (unsigned char)(buffer_id & 0xff); wbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff); wbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff); wbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff); wbufCmdBlk[6] = (unsigned char)((param_len >> 16) & 0xff); wbufCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); wbufCmdBlk[8] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " Write buffer cmd: "); for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", wbufCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " Write buffer parameter list%s:\n", ((param_len > 256) ? " (first 256 bytes)" : "")); dStrHexErr((const char *)paramp, ((param_len > 256) ? 256 : param_len), -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "write buffer: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, wbufCmdBlk, sizeof(wbufCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "write buffer", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI UNMAP command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_unmap(int sg_fd, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose) { return sg_ll_unmap_v2(sg_fd, 0, group_num, timeout_secs, paramp, param_len, noisy, verbose); } /* Invokes a SCSI UNMAP (SBC-3) command. Version 2 adds anchor field * (sbc3r22). Otherwise same as sg_ll_unmap() . */ int sg_ll_unmap_v2(int sg_fd, int anchor, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat, tmout; unsigned char uCmdBlk[UNMAP_CMDLEN] = {UNMAP_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (anchor) uCmdBlk[1] |= 0x1; tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; uCmdBlk[6] = group_num & 0x1f; uCmdBlk[7] = (param_len >> 8) & 0xff; uCmdBlk[8] = param_len & 0xff; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " unmap cdb: "); for (k = 0; k < UNMAP_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", uCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " unmap parameter list:\n"); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "unmap: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, uCmdBlk, sizeof(uCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, verbose); ret = sg_cmds_process_resp(ptvp, "unmap", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI READ BLOCK LIMITS command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rlCmdBlk[READ_BLOCK_LIMITS_CMDLEN] = {READ_BLOCK_LIMITS_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " read block limits cdb: "); for (k = 0; k < READ_BLOCK_LIMITS_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rlCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "read block limits: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rlCmdBlk, sizeof(rlCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "read block limits", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else { if ((verbose > 2) && (ret > 0)) { fprintf(sg_warnings_strm, " read block limits: response%s\n", (ret > 256 ? ", first 256 bytes" : "")); dStrHexErr((const char *)resp, (ret > 256 ? 256 : ret), -1); } ret = 0; } destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI RECEIVE COPY RESULTS command. Actually cover all current * uses of opcode 0x84 (Third-party copy IN). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_receive_copy_results(int sg_fd, int sa, int list_id, void * resp, int mx_resp_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char rcvcopyresCmdBlk[THIRD_PARTY_COPY_IN_CMDLEN] = {THIRD_PARTY_COPY_IN_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; char b[64]; sg_get_opcode_sa_name(THIRD_PARTY_COPY_IN_CMD, sa, 0, (int)sizeof(b), b); rcvcopyresCmdBlk[1] = (unsigned char)(sa & 0x1f); if (sa <= 4) /* LID1 variants */ rcvcopyresCmdBlk[2] = (unsigned char)(list_id); else if ((sa >= 5) && (sa <= 7)) { /* LID4 variants */ rcvcopyresCmdBlk[2] = (unsigned char)((list_id >> 24) & 0xff); rcvcopyresCmdBlk[3] = (unsigned char)((list_id >> 16) & 0xff); rcvcopyresCmdBlk[4] = (unsigned char)((list_id >> 8) & 0xff); rcvcopyresCmdBlk[5] = (unsigned char)(list_id & 0xff); } rcvcopyresCmdBlk[10] = (unsigned char)((mx_resp_len >> 24) & 0xff); rcvcopyresCmdBlk[11] = (unsigned char)((mx_resp_len >> 16) & 0xff); rcvcopyresCmdBlk[12] = (unsigned char)((mx_resp_len >> 8) & 0xff); rcvcopyresCmdBlk[13] = (unsigned char)(mx_resp_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " %s cmd: ", b); for (k = 0; k < THIRD_PARTY_COPY_IN_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", rcvcopyresCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "%s: out of memory\n", b); return -1; } set_scsi_pt_cdb(ptvp, rcvcopyresCmdBlk, sizeof(rcvcopyresCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, b, res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* SPC-4 rev 35 and later calls this opcode (0x83) "Third-party copy OUT" * The original EXTENDED COPY command (now called EXTENDED COPY (LID1)) * is the only one supported by sg_ll_extended_copy(). See function * sg_ll_3party_copy_out() for the other service actions ( > 0 ). */ /* Invokes a SCSI EXTENDED COPY (LID1) command. Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_extended_copy(int sg_fd, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char xcopyCmdBlk[THIRD_PARTY_COPY_OUT_CMDLEN] = {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; const char * opcode_name = "Extended copy (LID1)"; xcopyCmdBlk[1] = (unsigned char)(EXTENDED_COPY_LID1_SA & 0x1f); xcopyCmdBlk[10] = (unsigned char)((param_len >> 24) & 0xff); xcopyCmdBlk[11] = (unsigned char)((param_len >> 16) & 0xff); xcopyCmdBlk[12] = (unsigned char)((param_len >> 8) & 0xff); xcopyCmdBlk[13] = (unsigned char)(param_len & 0xff); if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; if (verbose) { fprintf(sg_warnings_strm, " %s cmd: ", opcode_name); for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", xcopyCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " %s parameter list:\n", opcode_name); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "%s: out of memory\n", opcode_name); return -1; } set_scsi_pt_cdb(ptvp, xcopyCmdBlk, sizeof(xcopyCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, opcode_name, res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Handles various service actions associated with opcode 0x83 which is * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID1 and * LID4), POPULATE TOKEN and WRITE USING TOKEN commands. * Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ int sg_ll_3party_copy_out(int sg_fd, int sa, unsigned int list_id, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat, tmout; unsigned char xcopyCmdBlk[THIRD_PARTY_COPY_OUT_CMDLEN] = {THIRD_PARTY_COPY_OUT_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; char cname[80]; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; sg_get_opcode_sa_name(THIRD_PARTY_COPY_OUT_CMD, sa, 0, sizeof(cname), cname); xcopyCmdBlk[1] = (unsigned char)(sa & 0x1f); switch (sa) { case 0x0: /* XCOPY(LID1) */ case 0x1: /* XCOPY(LID4) */ xcopyCmdBlk[10] = (unsigned char)((param_len >> 24) & 0xff); xcopyCmdBlk[11] = (unsigned char)((param_len >> 16) & 0xff); xcopyCmdBlk[12] = (unsigned char)((param_len >> 8) & 0xff); xcopyCmdBlk[13] = (unsigned char)(param_len & 0xff); break; case 0x10: /* POPULATE TOKEN (SBC-3) */ case 0x11: /* WRITE USING TOKEN (SBC-3) */ xcopyCmdBlk[6] = (unsigned char)((list_id >> 24) & 0xff); xcopyCmdBlk[7] = (unsigned char)((list_id >> 16) & 0xff); xcopyCmdBlk[8] = (unsigned char)((list_id >> 8) & 0xff); xcopyCmdBlk[9] = (unsigned char)(list_id & 0xff); xcopyCmdBlk[10] = (unsigned char)((param_len >> 24) & 0xff); xcopyCmdBlk[11] = (unsigned char)((param_len >> 16) & 0xff); xcopyCmdBlk[12] = (unsigned char)((param_len >> 8) & 0xff); xcopyCmdBlk[13] = (unsigned char)(param_len & 0xff); xcopyCmdBlk[14] = (unsigned char)(group_num & 0x1f); break; case 0x1c: /* COPY OPERATION ABORT */ xcopyCmdBlk[2] = (unsigned char)((list_id >> 24) & 0xff); xcopyCmdBlk[3] = (unsigned char)((list_id >> 16) & 0xff); xcopyCmdBlk[4] = (unsigned char)((list_id >> 8) & 0xff); xcopyCmdBlk[5] = (unsigned char)(list_id & 0xff); break; default: fprintf(sg_warnings_strm, "sg_ll_3party_copy_out: unknown service " "action 0x%x\n", sa); return -1; } tmout = (timeout_secs > 0) ? timeout_secs : DEF_PT_TIMEOUT; if (verbose) { fprintf(sg_warnings_strm, " %s cmd: ", cname); for (k = 0; k < THIRD_PARTY_COPY_OUT_CMDLEN; ++k) fprintf(sg_warnings_strm, "%02x ", xcopyCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); if ((verbose > 1) && paramp && param_len) { fprintf(sg_warnings_strm, " %s parameter list:\n", cname); dStrHexErr((const char *)paramp, param_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "%s: out of memory\n", cname); return -1; } set_scsi_pt_cdb(ptvp, xcopyCmdBlk, sizeof(xcopyCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, tmout, verbose); ret = sg_cmds_process_resp(ptvp, cname, res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.40/lib/sg_io_linux.c0000664000175000017500000001672112024633456015615 0ustar douggdougg/* * Copyright (c) 1999-2012 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include // need to include the file in the build when sg_scan is built for Win32. // Hence the following guard ... // #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SG_LIB_LINUX #include "sg_io_linux.h" /* Version 1.04 20120914 */ void sg_print_masked_status(int masked_status) { int scsi_status = (masked_status << 1) & 0x7e; sg_print_scsi_status(scsi_status); } static const char * linux_host_bytes[] = { "DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", "DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", "DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", "DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE", "DID_NEXUS_FAILURE", }; #define LINUX_HOST_BYTES_SZ \ (int)(sizeof(linux_host_bytes) / sizeof(linux_host_bytes[0])) void sg_print_host_status(int host_status) { if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "Host_status=0x%02x ", host_status); if ((host_status < 0) || (host_status >= LINUX_HOST_BYTES_SZ)) fprintf(sg_warnings_strm, "is invalid "); else fprintf(sg_warnings_strm, "[%s] ", linux_host_bytes[host_status]); } static const char * linux_driver_bytes[] = { "DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", "DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE" }; #define LINUX_DRIVER_BYTES_SZ \ (int)(sizeof(linux_driver_bytes) / sizeof(linux_driver_bytes[0])) static const char * linux_driver_suggests[] = { "SUGGEST_OK", "SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE", "UNKNOWN","UNKNOWN","UNKNOWN", "SUGGEST_SENSE" }; #define LINUX_DRIVER_SUGGESTS_SZ \ (int)(sizeof(linux_driver_suggests) / sizeof(linux_driver_suggests[0])) void sg_print_driver_status(int driver_status) { int driv, sugg; const char * driv_cp = "invalid"; const char * sugg_cp = "invalid"; driv = driver_status & SG_LIB_DRIVER_MASK; if (driv < LINUX_DRIVER_BYTES_SZ) driv_cp = linux_driver_bytes[driv]; sugg = (driver_status & SG_LIB_SUGGEST_MASK) >> 4; if (sugg < LINUX_DRIVER_SUGGESTS_SZ) sugg_cp = linux_driver_suggests[sugg]; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; fprintf(sg_warnings_strm, "Driver_status=0x%02x", driver_status); fprintf(sg_warnings_strm, " [%s, %s] ", driv_cp, sugg_cp); } /* Returns 1 if no errors found and thus nothing printed; otherwise prints error/warning (prefix by 'leadin') and returns 0. */ static int sg_linux_sense_print(const char * leadin, int scsi_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len, int raw_sinfo) { int done_leadin = 0; int done_sense = 0; if (NULL == sg_warnings_strm) sg_warnings_strm = stderr; scsi_status &= 0x7e; /*sanity */ if ((0 == scsi_status) && (0 == host_status) && (0 == driver_status)) return 1; /* No problems */ if (0 != scsi_status) { if (leadin) fprintf(sg_warnings_strm, "%s: ", leadin); done_leadin = 1; fprintf(sg_warnings_strm, "SCSI status: "); sg_print_scsi_status(scsi_status); fprintf(sg_warnings_strm, "\n"); if (sense_buffer && ((scsi_status == SAM_STAT_CHECK_CONDITION) || (scsi_status == SAM_STAT_COMMAND_TERMINATED))) { /* SAM_STAT_COMMAND_TERMINATED is obsolete */ sg_print_sense(0, sense_buffer, sb_len, raw_sinfo); done_sense = 1; } } if (0 != host_status) { if (leadin && (! done_leadin)) fprintf(sg_warnings_strm, "%s: ", leadin); if (done_leadin) fprintf(sg_warnings_strm, "plus...: "); else done_leadin = 1; sg_print_host_status(host_status); fprintf(sg_warnings_strm, "\n"); } if (0 != driver_status) { if (done_sense && (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status))) return 0; if (leadin && (! done_leadin)) fprintf(sg_warnings_strm, "%s: ", leadin); if (done_leadin) fprintf(sg_warnings_strm, "plus...: "); else done_leadin = 1; sg_print_driver_status(driver_status); fprintf(sg_warnings_strm, "\n"); if (sense_buffer && (! done_sense) && (SG_LIB_DRIVER_SENSE == (SG_LIB_DRIVER_MASK & driver_status))) sg_print_sense(0, sense_buffer, sb_len, raw_sinfo); } return 0; } #ifdef SG_IO int sg_normalize_sense(const struct sg_io_hdr * hp, struct sg_scsi_sense_hdr * sshp) { if ((NULL == hp) || (0 == hp->sb_len_wr)) { if (sshp) memset(sshp, 0, sizeof(struct sg_scsi_sense_hdr)); return 0; } return sg_scsi_normalize_sense(hp->sbp, hp->sb_len_wr, sshp); } /* Returns 1 if no errors found and thus nothing printed; otherwise returns 0. */ int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, int raw_sinfo) { return sg_linux_sense_print(leadin, hp->status, hp->host_status, hp->driver_status, hp->sbp, hp->sb_len_wr, raw_sinfo); } #endif /* Returns 1 if no errors found and thus nothing printed; otherwise returns 0. */ int sg_chk_n_print(const char * leadin, int masked_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len, int raw_sinfo) { int scsi_status = (masked_status << 1) & 0x7e; return sg_linux_sense_print(leadin, scsi_status, host_status, driver_status, sense_buffer, sb_len, raw_sinfo); } #ifdef SG_IO int sg_err_category3(struct sg_io_hdr * hp) { return sg_err_category_new(hp->status, hp->host_status, hp->driver_status, hp->sbp, hp->sb_len_wr); } #endif int sg_err_category(int masked_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len) { int scsi_status = (masked_status << 1) & 0x7e; return sg_err_category_new(scsi_status, host_status, driver_status, sense_buffer, sb_len); } int sg_err_category_new(int scsi_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len) { int masked_driver_status = (SG_LIB_DRIVER_MASK & driver_status); scsi_status &= 0x7e; if ((0 == scsi_status) && (0 == host_status) && (0 == masked_driver_status)) return SG_LIB_CAT_CLEAN; if ((SAM_STAT_CHECK_CONDITION == scsi_status) || (SAM_STAT_COMMAND_TERMINATED == scsi_status) || (SG_LIB_DRIVER_SENSE == masked_driver_status)) return sg_err_category_sense(sense_buffer, sb_len); if (0 != host_status) { if ((SG_LIB_DID_NO_CONNECT == host_status) || (SG_LIB_DID_BUS_BUSY == host_status) || (SG_LIB_DID_TIME_OUT == host_status)) return SG_LIB_CAT_TIMEOUT; } if (SG_LIB_DRIVER_TIMEOUT == masked_driver_status) return SG_LIB_CAT_TIMEOUT; return SG_LIB_CAT_OTHER; } #endif sg3_utils-1.40/getopt_long/0000755000175000017500000000000012431015530014661 5ustar douggdouggsg3_utils-1.40/getopt_long/getopt_long.c0000664000175000017500000002750010640353624017365 0ustar douggdougg/* $NetBSD: getopt_long.c,v 1.17 2004/06/20 22:20:15 jmc Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * modified May 12, 2005 by Jim Basney * * removed #include of non-POSIX * removed #include of "namespace.h" * use local "port_getopt.h" instead of * removed REPLACE_GETOPT and HAVE_NBTOOL_CONFIG_H sections * removed __P() from function declarations * use ANSI C function parameter lists * removed optreset support * replace _DIAGASSERT() with assert() * replace non-POSIX warnx(...) with fprintf(stderr, ...) * added extern declarations for optarg, optind, opterr, and optopt */ #if defined(LIBC_SCCS) && !defined(lint) __RCSID("$NetBSD: getopt_long.c,v 1.17 2004/06/20 22:20:15 jmc Exp $"); #endif /* LIBC_SCCS and not lint */ #include #include #include "getopt.h" #include #include #include #ifdef __weak_alias __weak_alias(getopt_long,_getopt_long) #endif #if !HAVE_GETOPT_LONG #define IGNORE_FIRST (*options == '-' || *options == '+') #define PRINT_ERROR ((opterr) && ((*options != ':') \ || (IGNORE_FIRST && options[1] != ':'))) #define IS_POSIXLY_CORRECT (getenv("POSIXLY_CORRECT") != NULL) #define PERMUTE (!IS_POSIXLY_CORRECT && !IGNORE_FIRST) /* XXX: GNU ignores PC if *options == '-' */ #define IN_ORDER (!IS_POSIXLY_CORRECT && *options == '-') /* return values */ #define BADCH (int)'?' #define BADARG ((IGNORE_FIRST && options[1] == ':') \ || (*options == ':') ? (int)':' : (int)'?') #define INORDER (int)1 #define EMSG "" extern char *optarg; extern int optind, opterr, optopt; static int getopt_internal (int, char * const *, const char *); static int gcd (int, int); static void permute_args (int, int, int, char * const *); static char *place = EMSG; /* option letter processing */ static int nonopt_start = -1; /* first non option argument (for permute) */ static int nonopt_end = -1; /* first option after non options (for permute) */ /* Error messages */ static const char recargchar[] = "option requires an argument -- %c"; static const char recargstring[] = "option requires an argument -- %s"; static const char ambig[] = "ambiguous option -- %.*s"; static const char noarg[] = "option doesn't take an argument -- %.*s"; static const char illoptchar[] = "unknown option -- %c"; static const char illoptstring[] = "unknown option -- %s"; /* * Compute the greatest common divisor of a and b. */ static int gcd(int a, int b) { int c; c = a % b; while (c != 0) { a = b; b = c; c = a % b; } return b; } /* * Exchange the block from nonopt_start to nonopt_end with the block * from nonopt_end to opt_end (keeping the same order of arguments * in each block). */ static void permute_args(int panonopt_start, int panonopt_end, int opt_end, char * const *nargv) { int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; char *swap; assert(nargv != NULL); /* * compute lengths of blocks and number and size of cycles */ nnonopts = panonopt_end - panonopt_start; nopts = opt_end - panonopt_end; ncycle = gcd(nnonopts, nopts); cyclelen = (opt_end - panonopt_start) / ncycle; for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { if (pos >= panonopt_end) pos -= nnonopts; else pos += nopts; swap = nargv[pos]; /* LINTED const cast */ ((char **) nargv)[pos] = nargv[cstart]; /* LINTED const cast */ ((char **)nargv)[cstart] = swap; } } } /* * getopt_internal -- * Parse argc/argv argument vector. Called by user level routines. * Returns -2 if -- is found (can be long option or end of options marker). */ static int getopt_internal(int nargc, char * const *nargv, const char *options) { char *oli; /* option letter list index */ int optchar; assert(nargv != NULL); assert(options != NULL); optarg = NULL; /* * XXX Some programs (like rsyncd) expect to be able to * XXX re-initialize optind to 0 and have getopt_long(3) * XXX properly function again. Work around this braindamage. */ if (optind == 0) optind = 1; start: if (!*place) { /* update scanning pointer */ if (optind >= nargc) { /* end of argument vector */ place = EMSG; if (nonopt_end != -1) { /* do permutation, if we have to */ permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } else if (nonopt_start != -1) { /* * If we skipped non-options, set optind * to the first of them. */ optind = nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((*(place = nargv[optind]) != '-') || (place[1] == '\0')) { /* found non-option */ place = EMSG; if (IN_ORDER) { /* * GNU extension: * return non-option as argument to option 1 */ optarg = nargv[optind++]; return INORDER; } if (!PERMUTE) { /* * if no permutation wanted, stop parsing * at first non-option */ return -1; } /* do permutation */ if (nonopt_start == -1) nonopt_start = optind; else if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); nonopt_start = optind - (nonopt_end - nonopt_start); nonopt_end = -1; } optind++; /* process next argument */ goto start; } if (nonopt_start != -1 && nonopt_end == -1) nonopt_end = optind; if (place[1] && *++place == '-') { /* found "--" */ place++; return -2; } } if ((optchar = (int)*place++) == (int)':' || (oli = strchr(options + (IGNORE_FIRST ? 1 : 0), optchar)) == NULL) { /* option letter unknown or ':' */ if (!*place) ++optind; if (PRINT_ERROR) fprintf(stderr, illoptchar, optchar); optopt = optchar; return BADCH; } if (optchar == 'W' && oli[1] == ';') { /* -W long-option */ /* XXX: what if no long options provided (called by getopt)? */ if (*place) return -2; if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) fprintf(stderr, recargchar, optchar); optopt = optchar; return BADARG; } else /* white space */ place = nargv[optind]; /* * Handle -W arg the same as --arg (which causes getopt to * stop parsing). */ return -2; } if (*++oli != ':') { /* doesn't take argument */ if (!*place) ++optind; } else { /* takes (optional) argument */ optarg = NULL; if (*place) /* no white space */ optarg = place; /* XXX: disable test for :: if PC? (GNU doesn't) */ else if (oli[1] != ':') { /* arg not optional */ if (++optind >= nargc) { /* no arg */ place = EMSG; if (PRINT_ERROR) fprintf(stderr, recargchar, optchar); optopt = optchar; return BADARG; } else optarg = nargv[optind]; } place = EMSG; ++optind; } /* dump back option letter */ return optchar; } /* * getopt_long -- * Parse argc/argv argument vector. */ int getopt_long(int nargc, char * const *nargv, const char *options, const struct option *long_options, int *idx) { int retval; assert(nargv != NULL); assert(options != NULL); assert(long_options != NULL); /* idx may be NULL */ if ((retval = getopt_internal(nargc, nargv, options)) == -2) { char *current_argv, *has_equal; size_t current_argv_len; int i, match; current_argv = place; match = -1; optind++; place = EMSG; if (*current_argv == '\0') { /* found "--" */ /* * We found an option (--), so if we skipped * non-options, we have to permute. */ if (nonopt_end != -1) { permute_args(nonopt_start, nonopt_end, optind, nargv); optind -= nonopt_end - nonopt_start; } nonopt_start = nonopt_end = -1; return -1; } if ((has_equal = strchr(current_argv, '=')) != NULL) { /* argument found (--option=arg) */ current_argv_len = has_equal - current_argv; has_equal++; } else current_argv_len = strlen(current_argv); for (i = 0; long_options[i].name; i++) { /* find matching long option */ if (strncmp(current_argv, long_options[i].name, current_argv_len)) continue; if (strlen(long_options[i].name) == (unsigned)current_argv_len) { /* exact match */ match = i; break; } if (match == -1) /* partial match */ match = i; else { /* ambiguous abbreviation */ if (PRINT_ERROR) fprintf(stderr, ambig, (int)current_argv_len, current_argv); optopt = 0; return BADCH; } } if (match != -1) { /* option found */ if (long_options[match].has_arg == no_argument && has_equal) { if (PRINT_ERROR) fprintf(stderr, noarg, (int)current_argv_len, current_argv); /* * XXX: GNU sets optopt to val regardless of * flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; return BADARG; } if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument) { if (has_equal) optarg = has_equal; else if (long_options[match].has_arg == required_argument) { /* * optional argument doesn't use * next nargv */ optarg = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument) && (optarg == NULL)) { /* * Missing argument; leading ':' * indicates no error should be generated */ if (PRINT_ERROR) fprintf(stderr, recargstring, current_argv); /* * XXX: GNU sets optopt to val regardless * of flag */ if (long_options[match].flag == NULL) optopt = long_options[match].val; else optopt = 0; --optind; return BADARG; } } else { /* unknown option */ if (PRINT_ERROR) fprintf(stderr, illoptstring, current_argv); optopt = 0; return BADCH; } if (long_options[match].flag) { *long_options[match].flag = long_options[match].val; retval = 0; } else retval = long_options[match].val; if (idx) *idx = match; } return retval; } #endif /* !GETOPT_LONG */ sg3_utils-1.40/getopt_long/getopt.h0000664000175000017500000000607310640353624016355 0ustar douggdougg/* $NetBSD: getopt.h,v 1.7 2005/02/03 04:39:32 perry Exp $ */ /*- * Copyright (c) 2000 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Dieter Baron and Thomas Klausner. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the NetBSD * Foundation, Inc. and its contributors. * 4. Neither the name of The NetBSD Foundation nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * modified May 12, 2005 by Jim Basney * * removed #include of non-POSIX and * removed references to _NETBSD_SOURCE and HAVE_NBTOOL_CONFIG_H * added #if !HAVE_GETOPT_LONG * removed __BEGIN_DECLS and __END_DECLS */ #ifndef _MYPROXY_GETOPT_H_ #define _MYPROXY_GETOPT_H_ #if !HAVE_GETOPT_LONG #include /* * Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions */ #define no_argument 0 #define required_argument 1 #define optional_argument 2 extern char *optarg; extern int optind; extern int optopt; extern int opterr; struct option { /* name of long option */ const char *name; /* * one of no_argument, required_argument, and optional_argument: * whether option takes an argument */ int has_arg; /* if not NULL, set *flag to val when option found */ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; }; int getopt_long(int, char * const *, const char *, const struct option *, int *); #endif /* !HAVE_GETOPT_LONG */ #endif /* !_MYPROXY_GETOPT_H_ */ sg3_utils-1.40/NEWS0000664000175000017500000000003010646136472013051 0ustar douggdouggSee the ChangeLog file. sg3_utils-1.40/doc/0000755000175000017500000000000012431015530013105 5ustar douggdouggsg3_utils-1.40/doc/scsi_satl.80000664000175000017500000000276712144707462015215 0ustar douggdougg.TH SCSI_SATL "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_satl \- check SCSI to ATA Translation (SAT) device support .SH SYNOPSIS .B scsi_satl [\fI\-\-help\fR] [\fI\-\-log\fR] [\fI\-\-quiet\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls several SCSI commands on the given \fIDEVICE\fR that is assumed to be an ATA device behind a SCSI to ATA Translation (SAT) layer (SATL). The results of each test and a pass/fail count are output. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-L\fR, \fB\-\-log\fR the output to stderr (from each SCSI command executed) is appended to a file called 'scsi_satl.err' in the current working directory. .TP \fB\-q\fR, \fB\-\-quiet\fR the amount of output is reduced and typically only the pass/fail count is output. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .SH EXIT STATUS The exit status of this script is the number of "bad" errors found. So an exit status of 0 means all mandatory SCSI commands worked as expected. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2011\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_luns, sg_turs, sg_requests, sg_vpd, sg_senddiag, sg_modes, .B sg_sat_identify (sg3_utils) sg3_utils-1.40/doc/sg_get_config.80000664000175000017500000001457712065221552016021 0ustar douggdougg.TH SG_GET_CONFIG "8" "December 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_get_config \- send SCSI GET CONFIGURATION command (MMC\-4 +) .SH SYNOPSIS .B sg_get_config [\fI\-\-brief\fR] [\fI\-\-current\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-inner\-hex\fR] [\fI\-\-list\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-rt=RT\fR] [\fI\-\-starting=FC\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends a SCSI GET CONFIGURATION command to \fIDEVICE\fR and decodes the response. The response includes the features and profiles of the device. Typically these devices are CD, DVD, HD\-DVD and BD players that may (but not necessarily) have media in them. These devices may well be connected via ATAPI, USB or IEEE 1394 transports. In such cases they are "SCSI" devices only in the sense that they use the "Multi\-Media command" set (MMC). MMC is a specialized SCSI command set whose definition can be found at http://www.t10.org . .PP This utility is based on the MMC\-4 and later draft standards. See section 5 on "Features and Profile for Multi_Media devices" for more information on specific feature parameters and profiles. The manufacturer's product manual may also be useful. .PP Since modern DVD and BD writers support many features and profiles, the decoded output from this utility can be large. There are various ways to cut down the output. If the \fI\-\-brief\fR option is used only the feature names are shown and the feature parameters are not decoded. Alternatively if only one feature is of interest then this combination of options is appropriate: "\-\-rt=2 \-\-starting=\fIFC\fR". Another possibility is to show only the features that are relevant to the media in the drive (i.e. "current") with the "\-\-rt=1" option. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR show the feature names but don't decode the parameters of those features. When used with \fI\-\-list\fR outputs known feature names but not known profile names. .TP \fB\-c\fR, \fB\-\-current\fR output features marked as current. This option is equivalent to '\-\-rt=1'. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the response in hex (don't decode response). .TP \fB\-i\fR, \fB\-\-inner\-hex\fR decode to the feature name level then output each feature's data in hex. .TP \fB\-l\fR, \fB\-\-list\fR list all known feature and profile names. Ignore the device name (if given). Simply lists the feature names and profiles (followed by their hex values) that this utility knows about. If \fI\-\-brief\fR is also given then only feature names are listed. .TP \fB\-q\fR, \fB\-\-readonly\fR opens the DEVICE read\-only rather than read\-write which is the default. The Linux sg driver needs read\-write access for the SCSI GET CONFIGURATION command but other access methods may require read\-only access. .TP \fB\-r\fR, \fB\-\-rt\fR=\fIRT\fR where \fIRT\fR is the field of that name in the GET CONFIGURATION cdb. Allowable values are 0, 1, 2, or 3 . The command's action also depends on the value given to the \fI\-\-starting=FC\fR option. The default value is 0. When \fIRT\fR is 0 then all features, regardless of currency, are returned (whose feature code is greater than or equal to \fIFC\fR given to \fI\-\-starting=\fR). When \fIRT\fR is 1 then all current features are returned (whose feature code is greater than or equal to \fIFC\fR). When \fIRT\fR is 2 then the feature whose feature code is equal to \fIFC\fR, if any, is returned. When \fIRT\fR is 3 the response is reserved (probably yields an "illegal field in cdb" error). To simplify the meanings of the \fIRT\fR values are: .br \fB0\fR : all features, current on not .br \fB1\fR : only current features .br \fB2\fR : only feature whose code is \fIFC\fR .br \fB3\fR : reserved .br .TP \fB\-R\fR, \fB\-\-raw\fR output response in binary (to stdout). Note that the short form is \fI\-R\fR unlike most other utilities in this package that use \fI\-r\fR for this action. .TP \fB\-s\fR, \fB\-\-starting\fR=\fIFC\fR where \fIFC\fR is the feature code value. This option works closely with the \fI\-\-rt=RT\fR option. The \fIFC\fR value is in the range 0 to 65535 (0xffff) inclusive. Its default value is 0. A value prefixed with "0x" (or a trailing 'h') is interpreted as hexadecimal. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES There are multiple versions of the MMC (draft) standards: MMC [1997], MMC\-2 [2000], MMC\-3 [2002], MMC\-4 and MMC\-5. The first three are now ANSI INCITS standards with the year they became standards shown in brackets. The draft immediately prior to standardization can be found at http://www.t10.org . In the initial MMC standard there was no GET CONFIGURATION command and the relevant information was obtained from the "CD capabilities and mechanical status mode page" (mode page 0x2a). It was later renamed the "MM capabilities and mechanical status mode page" and has been made obsolete in MMC\-4 and MMC\-5. The GET CONFIGURATION command was introduced in MMC\-2 and has become a replacement for that mode page. New features such as support for "BD" (blue ray) media type can only be found by using the GET CONFIGURATION command. Hence older CD players may not support the GET CONFIGURATION command in which case the "MM capabilities ..." mode page can be checked with sdparm(8), sginfo(8) or sg_modes(8). .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices can also be specified. For example "sg_get_config /dev/hdc" will work in the 2.6 series kernels as long as /dev/hdc is an ATAPI device. In the 2.6 series external DVD writers attached via USB could be queried with "sg_get_config /dev/scd1" for example. .SH EXIT STATUS The exit status of sg_get_config is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sginfo(8), sg_modes(8), sg_inq(8), sg_prevent(8), .B sg_start(8) [all in sg3_utils], .B sdparm(8) sg3_utils-1.40/doc/sg_rmsn.80000664000175000017500000000462612054252214014663 0ustar douggdougg.TH SG_RMSN "8" "November 2012" "sg3_utils\-1.31" SG3_UTILS .SH NAME sg_rmsn \- send SCSI READ MEDIA SERIAL NUMBER command .SH SYNOPSIS .B sg_rmsn [\fI\-\-help\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI READ MEDIA SERIAL NUMBER command to \fIDEVICE\fR and outputs the response. .PP This command is described in SPC\-3 found at www.t10.org . It was originally added to SPC\-3 in revision 11 (2003/2/12). It is not an mandatory command and the author has not seen any SCSI devices that support it. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-r\fR, \fB\-\-raw\fR sends the serial number (if found) to stdout. This output may contain non\-printable characters (e.g. the serial number is padded with NULLs at the end so its length is a multiple of 4). The default action is to print the serial number out in ASCII\-HEX with ASCII characters to the right. All error messages are sent to stderr. .TP \fB\-R\fR, \fB\-\-readonly\fR opens the DEVICE read\-only rather than read\-write which is the default. The Linux sg driver needs read\-write access for the SCSI READ MEDIA SERIAL NUMBER command but other access methods may require read\-only access. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES Device identification information is also found in a standard INQUIRY response and its VPD pages (see sg_vpd). The relevant VPD pages are the "device identification page" (VPD page 0x83) and the "unit serial number" page (VPD page 0x80). .PP The MMC\-4 command set for CD/DVD/HD-DVD/BD drives has a "media serial number" feature (0x109) [and a "logical unit serial number" feature]. These can be viewed with sg_get_config. .SH EXIT STATUS The exit status of sg_rmsn is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd(sg3_utils), sg_get_config(sg3_utils) sg3_utils-1.40/doc/sg_vpd.80000664000175000017500000003121112372451340014467 0ustar douggdougg.TH SG_VPD "8" "August 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_vpd \- fetch SCSI VPD page and/or decode its response .SH SYNOPSIS .B sg_vpd [\fI\-\-all\fR] [\fI\-\-enumerate\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ident\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-long\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-vendor=VP\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here .PP This utility, when \fIDEVICE\fR is given, fetches a Vital Product Data (VPD) page and decodes it or outputs it in ASCII hexadecimal or binary. VPD pages are fetched with a SCSI INQUIRY command. .PP Alternatively the \fI\-\-inhex=FN\fR option can be given. In this case \fIFN\fR is assumed to be a file name ('\-' for stdin) containing ASCII hexadecimal representing a VPD page response. If the \fI\-\-raw\fR option is also given then binary input is assumed (rather than ASCII hexadecimal). .PP Probably the most important page is the Device Identification VPD page (page number: 0x83). Since SPC\-3, support for this page has been flagged as mandatory. This page can be fetched by using the \fI\-\-ident\fR option. .PP The reference document used for interpreting VPD pages (and the INQUIRY standard response) is T10/1713\-D Revision 37 (SPC\-4, 17 May 2014) found at http://www.t10.org . .PP When no options are given, other than a \fIDEVICE\fR, then the "Supported VPD pages" (0x0) VPD page is fetched and decoded. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-a\fR, \fB\-\-all\fR decode all VPD pages. When used with \fIDEVICE\fR the pages to be decoded are found in the "Supported VPD pages" VPD page. .br If this option is used with the \fI\-\-inhex=FN\fR option then the file \fIFN\fR is assumed to contain 1 or more VPD pages (in ASCII hex or binary). Decoding continues until the file is exhausted (or an error occurs). Sanity checks are aplied on each VPD page's length and the ascending order of VPD page numbers (required by SPC\-4) so bad data may be detected. .br If the \fI\-\-page=PG\fR option is also given then no VPD page whose page number is greater than \fIPG\fR (or its numeric equivalent) is decoded. .TP \fB\-e\fR, \fB\-\-enumerate\fR list the names of the known VPD pages, first the standard pages (i.e. those defined by T10), then the vendor specific pages. Each group is sorted in abbreviation order. The \fIDEVICE\fR and most other options are ignored and this utility exits after listing the VPD page names. May be used together with \fI\-\-page=PG\fR where \fIPG\fR is numeric. If so, it searches for the summary lines of all VPD pages whose number matches \fIPG\fR. May be used with \fI\-\-vendor=VP\fR to restrict output to known vendor specific pages for vendor/product \fIVP\fR. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-H\fR, \fB\-\-hex\fR outputs the requested VPD page in ASCII hexadecimal. Can be used multiple times, see section on the ATA information vpd page. .br To generate output suitable for placing in a file that can be used by a later invocation with the \fI\-\-inhex=FN\fR option, use the '\-HHHH' option (e.g. 'sg_vpd \-p di \-HHHH /dev/sg3 > dev_id.hex'). The reason '\-HHHH' is used is to flag that unadorned hexadecimal (without other text or address offsets) is sent to stdout. .TP \fB\-i\fR, \fB\-\-ident\fR decode the device identification (0x83) VPD page. When used once this option has the same effect as '\-\-page=di'. When use twice then the short form of the device identification VPD page's logical unit designator is decoded. In the latter case this option has the same effect as '\-\-quiet \-\-page=di_lu'. .TP \fB\-I\fR, \fB\-\-inhex\fR=\fIFN\fR \fIFN\fR is expected to be a file name (or '\-' for stdin) which contains ASCII hexadecimal or binary representing a VPD page (or a standard INQUIRY) response. This utility will then decode that response. It is preferable to also supply the \fI\-\-page=PG\fR option, if not this utility will attempt to guess which VPD page (or standard INQUIRY) the response is associated with. The hexadecimal should be arranged as 1 or 2 digits representing a byte each of which is whitespace or comma separated. Anything from and including a hash mark to the end of line is ignored. If the \fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary. .TP \fB\-l\fR, \fB\-\-long\fR when decoding some VPD pages, give a little more output. For example the ATA Information VPD page only shows the signature (in hex) and the IDENTIFY (PACKET) DEVICE (in hex) when this option is given. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given (or \fILEN\fR is zero) then 252 is used (apart from the ATA Information VPD page which defaults to 572) and, if the response indicates this value is insufficient, another INQUIRY command is sent with a larger value in the cdb's "allocation length" field. If this option is given and \fILEN\fR is greater than 0 then only one INQUIRY command is sent. Since many simple devices implement the INQUIRY command badly (and do not support VPD pages) then the safest value to use for \fILEN\fR is 36. See the sg_inq man page for the more information. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR where \fIPG\fR is the VPD page to be decoded or output. The \fIPG\fR argument can either be an abbreviation, a number or a pair or numbers/abbreviations separated by a comma. The VPD page abbreviations can be seen by using the \fI\-\-enumerate\fR option. If a number is given it is assumed to be decimal unless it has a hexadecimal indicator which is either a leading '0x' or a trailing 'h'. If one number is given then it is assumed to be a VPD page number. If two numbers (or abbreviations) are given then the second one is the same as \fIVP\fR (see the \fI\-\-vendor=VP\fR option). If this option is not given (nor '\-i', '\-l' nor '\-V') then the "Supported VPD pages" (0x0) VPD page is fetched and decoded. If \fIPG\fR is '\-1' or 'sinq' then the standard INQUIRY response is output. This option may also be used with the \fI\-\-enumerate\fR (see its description). .TP \fB\-q\fR, \fB\-\-quiet\fR suppress the amount of decoding output. .TP \fB\-r\fR, \fB\-\-raw\fR if not used with \fI\-\-inhex=FN\fR then output requested VPD page in binary. The output should be piped to a file or another utility when this option is used. The binary is sent to stdout, and errors are sent to stderr. .br if used with \fI\-\-inhex=FN\fR then the contents of \fIFN\fR is treated as binary. .TP \fB\-M\fR, \fB\-\-vendor\fR=\fIVP\fR where \fIVP\fR is a vendor (e.g. "sea" for Seagate) or vendor/product acronym (e.g. "hp3par" for the 3PAR array from HP). Many vendors have re-used the numbers at the beginning of the vendor specific VPD page range (e.g. page 0xc0) and this option is a way of selecting only those which are of interest. Using a \fIVP\fR of "xxx" will list the available acronyms. .br If this option is used with \fI\-\-page=PG\fR and \fIPG\fR is an acronym then this option is ignored. If \fIPG\fR is a number (e.g. 0xc0) then \fIVP\fR is used to choose the which vendor specific page (e.g. sharing page number 0xc0) to decode. .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH ATA INFORMATION VPD PAGE This VPD page (0x89 or 'ai') is defined by the SCSI to ATA Translation standard. It contains information about the SAT layer, the "signature" of the ATA device and the response to the ATA IDENTIFY (PACKET) DEVICE command. The latter part has 512 bytes of identity, capability and settings data which the hdparm utility is capable of decoding (so this utility doesn't decode it). .PP To unclutter the output for this page, the signature and the IDENTIFY (PACKET) DEVICE response are not output unless the \fI\-\-long\fR option (or \fI\-\-hex\fR or \fI\-\-raw\fR) are given. When the \fI\-\-long\fR option is given the IDENTIFY (PACKET) DEVICE response is output as 256 (16 bit) words as is the fashion for ATA devices. To see that response as a string of bytes use the '\-HH' option. To format the output suitable for hdparm to decode use either the '\-HHH' or '\-rr' option. For example if 'dev/sdb' is a SATA disk behind a SAT layer then this command: 'sg_vpd \-p ai \-HHH /dev/sdb | hdparm \-\-Istdin' should decode the ATA IDENTIFY (PACKET) DEVICE response. .SH NOTES Since some VPD pages (e.g. the Extended INQUIRY page) depend on settings in the standard INQUIRY response, then the standard INQUIRY response is output as a pseudo VPD page when \fIPG\fR is set to '\-1' or 'sinq'. Also the decoding of some fields (e.g. the Extended INQUIRY page's SPT field) is expanded when the '\-\-long' option is given using the standard INQUIRY response information (e.g. the PDT and the PROTECT fields). .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda" will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char" device names may be used as well (e.g. "/dev/st0m"). .PP The \fIDEVICE\fR is opened with a read\-only flag (e.g. in Unix with the O_RDONLY flag). .SH EXIT STATUS The exit status of sg_vpd is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH EXAMPLES The examples in this page use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP To see the VPD pages that a device supports, use with no options. The command line invocation is shown first followed by a typical response: .PP # sg_vpd /dev/sdb .br Supported VPD pages VPD page: .br Supported VPD pages [sv] .br Unit serial number [sn] .br Device identification [di] .br Extended inquiry data [ei] .br Block limits (SBC) [bl] .PP To see the VPD page numbers associated with each supported page then add the '\-\-long' option to the above command line. To view a VPD page either its number or abbreviation can be given to the '\-\-page=' option. The page name abbreviations are shown within square brackets above. In the next example the Extended inquiry data VPD page is listed: .PP # sg_vpd \-\-page=ei /dev/sdb .br extended INQUIRY data VPD page: .br ACTIVATE_MICROCODE=0 SPT=0 GRD_CHK=0 APP_CHK=0 REF_CHK=0 .br UASK_SUP=0 GROUP_SUP=0 PRIOR_SUP=0 HEADSUP=1 ORDSUP=1 SIMPSUP=1 .br WU_SUP=0 CRD_SUP=0 NV_SUP=0 V_SUP=0 .br P_I_I_SUP=0 LUICLR=0 R_SUP=0 CBCS=0 .br Multi I_T nexus microcode download=0 .br Extended self\-test completion minutes=0 .br POA_SUP=0 HRA_SUP=0 VSA_SUP=0 .PP To check if any protection types are supported by a disk use the '\-\-long' option on the Extended inquiry data VPD page: .PP # sg_vpd \-\-page=ei \-\-long /dev/sdb .br extended INQUIRY data VPD page: .br ACTIVATE_MICROCODE=0 .br SPT=1 [protection types 1 and 2 supported] .br GRD_CHK=1 .br .... .PP Search for the name (and acronym) of all pages that share VPD page number 0xb0 . .PP # sg_vpd \-\-page=0xb0 \-\-enumerate .br Matching standard VPD pages: .br bl 0xb0 Block limits (SBC) .br oi 0xb0 OSD information .br sad 0xb0 Sequential access device capabilities (SSC) .PP Some examples follow using the "\-\-all" option. Send an ASCII hexadecimal representation of all VPD pages to a file: .PP # sg_vpd \-\-all \-HHHH /dev/sg3 > all_vpds.hex .PP At some later time that file could be decoded with: .PP # sg_vpd \-\-all \-\-inhex=all_vpds.hex .PP To do the equivalent as the previous example but use a file containing binary: .PP # sg_vpd \-\-all \-\-raw /dev/sg3 > all_vpds.bin .br # sg_vpd \-\-all \-\-raw \-\-inhex=all_vpds.bin .PP Notice that "\-\-raw" must be given with the second (\-\-inhex) invocation to alert the utility that all_vpds.bin contains binary as it assumes ASCII hexadecimal by default. Next we only decode T10 specified VPD pages excluding vendor specific VPD pages that start at page number 0xc0: .PP # sg_vpd \-\-all \-\-page=0xbf \-\-raw \-\-inhex=all_vpds.bin .PP Further examples can be found on the http://sg.danny.cz/sg/sg3_utils.html web page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(sg3_utils), sg3_utils(sg3_utils), sdparm(sdparm), hdparm(hdparm) sg3_utils-1.40/doc/Makefile.am0000664000175000017500000001324412430315266015157 0ustar douggdougg if OS_LINUX # sg_dd, sg_emc_trespass(?), sginfo, sg_map26, sg_map, sgm_dd, sgp_dd, # sg_rbuf, sg_read, sg_reset, sg_test_rwbuf # are Linux only utilities # # sg_scan is shared by Linux and Win32 man_MANS = \ rescan-scsi-bus.sh.8 \ sg3_utils.8 sg_decode_sense.8 scsi_logging_level.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_copy_results.8 sg_dd.8 sg_emc_trespass.8 \ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 sginfo.8 \ sg_inq.8 sg_logs.8 sg_luns.8 sg_map26.8 sg_map.8 sgm_dd.8 \ sg_modes.8 sg_opcodes.8 sgp_dd.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rbuf.8 sg_rdac.8 sg_read.8 sg_readcap.8 sg_read_block_limits.8 \ sg_read_buffer.8 sg_read_long.8 sg_reassign.8 sg_referrals.8 \ sg_rep_zones.8 sg_requests.8 sg_reset.8 sg_reset_wp.8 sg_rmsn.8 \ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \ sg_sat_phy_event.8 sg_sat_read_gplog.8 sg_sat_set_features.8 \ sg_scan.8 sg_senddiag.8 sg_ses.8 sg_ses_microcode.8 sg_start.8 \ sg_stpg.8 sg_sync.8 sg_test_rwbuf.8 sg_turs.8 sg_unmap.8 sg_verify.8 \ sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \ sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8 distclean-local: rm -f sg_scan.8 sg_scan.8 : sg_scan.8.linux cp -p sg_scan.8.linux sg_scan.8 endif if OS_WIN32_MINGW man_MANS = \ sg3_utils.8 sg_decode_sense.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 distclean-local: rm -f sg_scan.8 sg_scan.8 : sg_scan.8.win32 cp -p sg_scan.8.win32 sg_scan.8 endif if OS_WIN32_CYGWIN man_MANS = \ sg3_utils.8 sg_decode_sense.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 distclean-local: rm -f sg_scan.8 sg_scan.8 : sg_scan.8.win32 cp -p sg_scan.8.win32 sg_scan.8 endif if OS_FREEBSD man_MANS = \ sg3_utils.8 sg_decode_sense.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 endif if OS_SOLARIS man_MANS = \ sg3_utils.8 sg_decode_sense.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 endif if OS_OSF man_MANS = \ sg3_utils.8 sg_decode_sense.8 \ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 endif sg3_utils-1.40/doc/sg_logs.80000664000175000017500000004264412333156560014661 0ustar douggdougg.TH SG_LOGS "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_logs \- access log pages with SCSI LOG SENSE command .SH SYNOPSIS .B sg_logs [\fI\-\-all\fR] [\fI\-\-brief\fR] [\fI\-\-control=PC\fR] [\fI\-\-filter=PARC\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-in=FN\fR] [\fI\-\-list\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-name\fR] [\fI\-\-no_inq\fR] [\fI\-\-page=PG[,SPG]\fR] [\fI\-\-paramp=PP\fR] [\fI\-\-pcb\fR] [\fI\-\-ppc\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-reset\fR] [\fI\-\-select\fR] [\fI\-\-sp\fR] [\fI\-\-temperature\fR] [\fI\-\-transport\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_logs [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-c=PC\fR] [\fI\-f=PARC\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i=FN\fR] [\fI\-l\fR] [\fI\-L\fR] [\fI\-m=LEN\fR] [\fI\-n\fR] [\fI\-p=PG[,SPG]\fR] [\fI\-paramp=PP\fR] [\fI\-pcb\fR] [\fI\-ppc\fR] [\fI\-r\fR] [\fI\-R\fR] [\fI\-select\fR] [\fI\-sp\fR] [\fI\-t\fR] [\fI\-T\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] [\fI\-x\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends a SCSI LOG SENSE command to the \fIDEVICE\fR and then outputs the response. The LOG SENSE command is used to fetch log pages. Known log pages are decoded by default. When the \fI\-\-reset\fR and/or \fI\-\-select\fR option is given then a SCSI LOG SELECT command is issued. .PP In SPC\-4 revision 5 a subpage code was introduced to both the LOG SENSE and LOG SELECT command. At the same time a page code field was introduced to the to the LOG SELECT command. The log subpage code can range from 0 to 255 (0xff) inclusive. The subpage code value 255 can be thought of as a wildcard. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-all\fR outputs all the log pages supported by the device. This requires a two stage process: first the "supported log pages" log page is fetched, then for each entry in the response, the corresponding log page is fetched and displayed. When used twice (e.g. '\-aa') all log pages and subpages are fetched. .TP \fB\-b\fR, \fB\-\-brief\fR shorten the amount of output for some log pages. For example the Tape Alert log page only outputs parameters whose flags are set when \fI\-\-brief\fR is given. .TP \fB\-c\fR, \fB\-\-control\fR=\fIPC\fR accepts 0, 1, 2 or 3 for the \fIPC\fR argument: .br \fB0\fR : current threshold values .br \fB1\fR : current cumulative values .br \fB2\fR : default threshold values .br \fB3\fR : default cumulative values .br The default value is 1 (i.e. current cumulative values). .TP \fB\-f\fR, \fB\-\-filter\fR=\fIPARC\fR only output the log parameter whose parameter code (a number between 0 and 65535) matches \fIPARC\fR. \fIPARC\fR is assumed to be decimal unless a hexadecimal indication is given (e.g. a leading '0x' or a trailing 'h'). The \fB\-\-hex\fR option outputs log parameter in hexadecimal rather than decoding it. If the \fB\-\-hex\fR option is used twice then the leading address on each kine of hex is removed. If the \fB\-\-raw\fR option is given then the log parameter is output in binary. .br Most log pages contain one or more log parameters. Examples of those that don't are those pages that list supported log pages. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR The default action is to decode known mode page numbers (and subpage numbers) into text. When this option is used once, the response is output in hexadecimal. .TP \fB\-i\fR, \fB\-\-in\fR=\fIFN\fR \fIFN\fR is treated as a file name (or '\-' for stdin) which contains ASCII hexadecimal or binary representing a log page that will be sent as parameter data of a LOG SELECT command. The hexadecimal should be arranged as 1 or 2 digits representing a byte each of which is whitespace or comma separated. Anything from and including a hash mark to the end of line is ignored. If the \fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary. See the LOG SELECT section. .TP \fB\-l\fR, \fB\-\-list\fR lists the names of all logs sense pages supported by this device. This is done by reading the "supported log pages" log page. When used twice (e.g. '\-ll') lists the names of all logs sense pages and subpages supported by this device. There is a list of common log page codes below. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR sets the "allocation length" field in the LOG SENSE cdb. The is the maximum length in bytes that the response will be. Without this option (or \fILEN\fR equal to 0) this utility first fetches the 4 byte response then does a second access with the length indicated in the first (4 byte) response. Negative values and 1 for \fILEN\fR are not accepted. \fILEN\fR cannot exceed 65535 (0xffff). Responses can be quite large (e.g. the background scan results log page) and this option can be used to limit the amount of information returned. .TP \fB\-n\fR, \fB\-\-name\fR decode some log pages into 'name=value' entries, one per line. The name contains no space and may be abbreviated and the value is decimal unless prefixed by '0x'. Nesting is indicated by leading spaces. This form is meant to be relatively easy to parse. .TP \fB\-x\fR, \fB\-\-no_inq\fR suppresses the output of information obtained from an initial call to the INQUIRY command for the standard response. The default (assuming some other options that suppress this output are also not given) is to output several device identification strings. .br If this option is given twice (or more) then no INQUIRY command is sent hence there will be no device identification string output either. Also the peripheral device type (PDT) field will not be obtained so this utility will not be able to differentiate between some log pages that are device dependent. It will assume a PDT of 0 (i.e. a disk). .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG[,SPG]\fR log page code to access. \fIPG\fR is expected to be a decimal number between 0 and 63 inclusive. A hexadecimal number can be specified by a leading "0x" or a trailing "h" so the valid range is 0x to 0x3f. Common log page codes are listed below. Optionally \fISPG\fR, a subpage code, can be given. \fISPG\fR is expected to be a decimal or hex number between 0 and 255 inclusive. .TP \fB\-P\fR, \fB\-\-paramp\fR=\fIPP\fR \fIPP\fR is the parameter pointer value to place in a field of that name in the LOG SENSE cdb. A decimal number in the range 0 to 65535 (0xffff) is expected. When a value greater than 0 is given the \fI\-\-ppc\fR option should be selected. The default value is 0. .TP \fB\-q\fR, \fB\-\-pcb\fR show Parameter Control Byte settings (only relevant when log parameters being output in ASCII). .TP \fB\-Q\fR, \fB\-\-ppc\fR sets the Parameter Pointer Control (PPC) bit in the LOG SENSE cdb. Default is 0 (i.e. cleared). This bit was made obsolete in SPC\-4 revision 18. .TP \fB\-r\fR, \fB\-\-raw\fR output the response in binary to stdout. Error messages and warnings are output to stderr. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default action is to try and open \fIDEVICE\fR read\-write then if that fails try to open again with read\-only. However when a read\-write open succeeds there may still be unwanted actions on the close (e.g. some OSes try to do a SYNCHRONIZE CACHE command). So this option forces a read\-only open on \fIDEVICE\fR and if it fails, this utility will exit. Note that options like \fI\-\-select\fR most likely need a read\-write open. .TP \fB\-R\fR, \fB\-\-reset\fR use SCSI LOG SELECT command (PCR bit set) to reset the all log pages (or the given page). Exactly what is reset depends on the accompanying SP bit (i.e. \fI\-\-sp\fR option which defaults to 0) and the \fIPC\fR ("page control") value (which defaults to 1). Supplying this option implies the \fI\-\-select\fR option as well. This option seems to clear error counter log pages but leaves pages like self\-test results, start\-stop cycle counter and temperature log pages unaffected. This option may be required to clear log pages if a counter reaches its maximum value since the log page in which the counter is found will remain "stuck" until something is done. .TP \fB\-S\fR, \fB\-\-select\fR use a LOG SELECT command. The default action (i.e. when neither this option nor \fI\-\-reset\fR is given) is to do a LOG SENSE command. See the LOG SELECT section. .TP \fB\-s\fR, \fB\-\-sp\fR sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared). When set this instructs the device to store the current log page parameters (as indicated by the DS and TSD parameter codes) in some non\-volatile location. Hence the log parameters will be preserved across power cycles. This option is typically not needed, especially if the GLTSD flag is clear in the control mode page as this instructs the device to periodically save all saveable log parameters to non\-volatile locations. .TP \fB\-t\fR, \fB\-\-temperature\fR outputs the temperature. First looks in the temperature log page and if that is not available tries the Informational Exceptions log page which may also have the current temperature (especially on older disks). .TP \fB\-T\fR, \fB\-\-transport\fR outputs the transport ('Protocol specific port') log page. Equivalent to setting '\-\-page=18h'. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH LOG SELECT The LOG SELECT command can be used to reset certain parameters to vendor specific defaults, save them to non-volatile storage (i.e. the media), or supply new page contents. This command has changed between SPC\-3 and SPC\-4 with the addition of the Page and Subpage Code fields which can only be non zero when the Parameter list length is zero. .PP The \fI\-\-select\fR option is required to issue a LOG SELECT command. If the \fI\-\-in=FN\fR option is not given (or \fIFN\fR is effectively empty) then the Parameter list length field is set to zero. If the \fI\-\-in=FN\fR option is is given then its decoded data is placed in the data-out buffer and its length in bytes is placed in the Parameter list length field. .PP Other options that are active with the LOG SELECT command are \fI\-\-control=PC\fR, \fI\-\-reset\fR (which sets the PCR bit) and \fI\-\-sp\fR. .SH APPLICATION CLIENT This is the name of a log page that acts as a container for data provided by the user. An application client is a SCSI term for the program that issues commands to a SCSI initiator (often known as a Host Bus Adapter (HBA)). So, for example, this utility is a SCSI application client. .PP The Application Client log page has 64 log parameters with parameters codes 0 to 63. Each can hold 252 bytes of user binary data. That 252 bytes (or less) of user data, with a 4 byte prefix (for a total of 256 bytes) can be provided with the \fI\-\-in=FN\fR option. A typical prefix would be '0,n,83,fc'. The "n" is the parameter code in hex so the last log parameter would be '0,3f,83,fc'. That log parameter could be read back at some later time with '\-\-page=0xf \-\-filter=0x'. .SH NOTES This utility will usually do a double fetch of log pages with the SCSI LOG SENSE command. The first fetch requests a 4 byte response (i.e. place 4 in the "allocation length" field in the cdb). From that response it can calculate the actual length of the response which is what it asks for on the second fetch. This is typical practice in SCSI and guaranteed to work in the standards. However some older devices don't comply. For those devices using the \fI\-\-maxlen=LEN\fR option will do a single fetch. A value of 252 should be a safe starting point. .PP Various log pages hold information error rates, device temperature, start stop cycles since device produced and the results of the last 20 self tests. Self tests can be initiated by the sg_senddiag(8) utility. The smartmontools package provides much of the information found with sg_logs in a form suitable for monitoring the health of SCSI disks and tape drives. .PP Here is a list of log pages that are decoded by this utility. [The code values can be given to '\-\-page=' as is, with a trailing "h" instead of the leading "0x", or as their decimal equivalents.]: .PP 0x0 Supported log pages .br 0x0,0xff Supported log pages and subpages .br 0x1 Buffer over\-run/under\-run .br 0x2 Write error counter .br 0x3 Read error counter .br 0x4 Read reverse error counter .br 0x5 Verify error counter .br 0x6 Non\-medium error .br 0x7 Last n error events .br 0x8 Format status (sbc\-2) .br 0xb Last n deferred errors or asynchronous events .br 0xc Logical block provisioning (sbc\-3) or .br Sequential access device (ssc\-2) .br 0xd Temperature .br 0xe Start\-stop cycle counter .br 0xf Application client .br 0x10 Self\-test results .br 0x11 Solid state media .br 0x15 Background scan results (sbc\-3) .br 0x16 ATA pass\-through results (sat\-3) .br 0x17 Non\-volatile cache (sbc\-3) .br 0x18 Protocol specific port (SAS transport) .br 0x19 General statistics and performance .br 0x1a Power condition transitions .br 0x2f Informational exceptions .br 0x37 Seagate cache (vendor, disk) .br 0x3e Seagate factory (vendor, disk) .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_logs \-a /dev/sda" will work in the 2.6 series kernels. .SH EXIT STATUS The exit status of sg_logs is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .PP Options with arguments or with two or more letters can have an extra '\-' prepended. For example: both '\-pcb' and '\-\-pcb' are acceptable. .TP \fB\-a\fR outputs all the log pages supported by the device. Equivalent to \fI\-\-all\fR in the main description. .TP \fB\-A\fR outputs all the log pages and subpages supported by the device. Equivalent to '\-\-all \-\-all' in the main description. .TP \fB\-c\fR=\fIPC\fR Equivalent to \fI\-\-control=PC\fR in the main description. .TP \fB\-h\fR suppresses decoding of known log sense pages and prints out the response in hex instead. .TP \fB\-i\fR=\fIFN\fR \fIFN\fR is treated as a file name (or '\-' for stdin) which contains ASCII hexadecimal representing a log page that will be sent as parameter data of a LOG SELECT command. See the LOG SELECT section. .TP \fB\-H\fR same action as '\-h' in this section and equivalent to \fI\-\-hex\fR in the main description. .TP \fB\-l\fR lists the names of all logs sense pages supported by this device. Equivalent to \fI\-\-list\fR in the main description. .TP \fB\-L\fR lists the names of all logs sense pages and subpages supported by this device. Equivalent to '\-\-list \-\-list' in the main description. .TP \fB\-m\fR=\fILEN\fR request only \fILEN\fR bytes of response data. Default is 0 which is interpreted as all that is available. \fILEN\fR is decimal unless it has a leading '0x' or trailing 'h'. Equivalent to \fI\-\-maxlen=LEN\fR in the main description. .TP \fB\-n\fR Equivalent to \fI\-\-name\fR in the main description. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-p\fR=\fIPG[,SPG]\fR \fIPG\fR is the log page code to access. Should be a hexadecimal number between 0 and 3f inclusive. If given \fISPG\fR is the log subpage code. \fISPG\fR should be a hexadecimal number between 0 and ff inclusive. The subpage code of 'ff' can be thought of as a wildcard. .TP \fB\-paramp\fR=\fIPP\fR \fIPP\fR is the parameter pointer value (in hex) to place in command. Should be a number between 0 and ffff inclusive. .TP \fB\-pcb\fR show Parameter Control Byte settings (only relevant when log parameters being output in ASCII). .TP \fB\-ppc\fR sets the Parameter Pointer Control (PPC) bit. Default is 0 (i.e. cleared). .TP \fB\-r\fR use SCSI LOG SELECT command (PCR bit set) to reset the all log pages (or the given page). Equivalent to \fI\-\-reset\fR in the main description. .TP \fB\-R\fR Equivalent to \fI\-\-readonly\fR in the main description. .TP \fB\-select\fR use a LOG SELECT command. Equivalent to \fI\-\-select\fR in the main description. .TP \fB\-sp\fR sets the Saving Parameters (SP) bit. Default is 0 (i.e. cleared). Equivalent to \fI\-\-sp\fR in the main description. .TP \fB\-t\fR outputs the temperature. Equivalent to \fI\-\-temperature\fR in the main description. .TP \fB\-T\fR outputs the transport ('Protocol specific port') log page. Equivalent to \fI\-\-transport\fR in the main description. .TP \fB\-v\fR increase level of verbosity. .TP \fB\-V\fR print out version string then exit. .TP \fB\-x\fR suppress the INQUIRY command. Equivalent to \fI\-\-no_inq\fR in the main description. .TP \fB\-?\fR output usage message then exit. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2002\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B smartctl(smartmontools), sg_senddiag(8) sg3_utils-1.40/doc/sg_raw.80000664000175000017500000001421112422552302014464 0ustar douggdougg.TH SG_RAW "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_raw \- send arbitrary SCSI command to a device .SH SYNOPSIS .B sg_raw [\fIOPTIONS\fR] \fIDEVICE\fR CDB0 CDB1 ... .SH DESCRIPTION This utility sends an arbitrary SCSI command (between 6 and 256 bytes) to the \fIDEVICE\fR. There may be no associated data transfer; or data may be read from a file and sent to the \fIDEVICE\fR; or data may be received from the \fIDEVICE\fR and then displayed or written to a file. If supported by the pass through, bidirectional commands may be sent (i.e. containing both data to be sent to the \fIDEVICE\fR and received from the \fIDEVICE\fR). .PP The SCSI command may be between 6 and 256 bytes long. Each command byte is specified in plain hex format (00..FF) without a prefix or suffix. See EXAMPLES section below. .PP The commands pass through a generic SCSI interface which is implemented for several operating systems including Linux, FreeBSD and Windows. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-binary\fR Dump data in binary form, even when writing to stdout. .TP \fB\-h\fR, \fB\-\-help\fR Display usage information and exit. .TP \fB\-i\fR, \fB\-\-infile\fR=\fIIFILE\fR Read data from \fIIFILE\fR instead of stdin. This option is ignored if \fB\-\-send\fR is not specified. .TP \fB\-k\fR, \fB\-\-skip\fR=\fILEN\fR Skip the first \fILEN\fR bytes of the input file or stream. This option is ignored if \fB\-\-send\fR is not specified. .TP \fB\-n\fR, \fB\-\-nosense\fR Don't display SCSI Sense information. .TP \fB\-o\fR, \fB\-\-outfile\fR=\fIOFILE\fR Write data received from the \fIDEVICE\fR to \fIOFILE\fR. The data is written in binary. By default, data is dumped in hex format to stdout. If \fIOFILE\fR is '\-' then data is dumped in binary to stdout. This option is ignored if \fB\-\-request\fR is not specified. .TP \fB\-r\fR, \fB\-\-request\fR=\fIRLEN\fR Expect to receive up to \fIRLEN\fR bytes of data from the \fIDEVICE\fR. \fIRLEN\fR may be suffixed with 'k' to use kilobytes (1024 bytes) instead of bytes. .TP \fB\-R\fR, \fB\-\-readonly\fR Open \fIDEVICE\fR read\-only. The default (without this option) is to open it read\-write. .TP \fB\-s\fR, \fB\-\-send\fR=\fISLEN\fR Read \fISLEN\fR bytes of data, either from stdin or from a file, and send them to the \fIDEVICE\fR. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISEC\fR Wait up to \fISEC\fR seconds for command completion (default: 20). Note that if a command times out the operating system may start by aborting the command and if that is unsuccessful it may attempt to reset the device. .TP \fB\-v\fR, \fB\-\-verbose\fR Increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR Display version and license information and exit. .SH NOTES The sg_inq utility can be used to send an INQUIRY command to a device to determine its peripheral device type (e.g. '1' for a streaming device (tape drive)) which determines which SCSI command sets a device should support (e.g. SPC and SSC). The sg_vpd utility probes the Vital Product Pages of a devices which may contain useful information. .PP The ability to send more than a 16 byte CDB (in some cases 12 byte CDB) may be restricted by the pass\-through interface, the low level driver or the transport. In the Linux series 3 kernels, the bsg driver can handle longer CDBs, block devices (e.g. /dev/sdc) accessed via the SG_IO ioctl cannot handle CDBs longer than 16 bytes, and the sg driver can handle longer CDBs from lk 3.17 . .PP The CDB command name defined by T10 for the given CDB is shown if the '\-vvv' option is given. The command line syntax still needs to be correct, so /dev/null may be used for the \fIDEVICE\fR since the CDB command name decoding is done before the \fIDEVICE\fR is checked. .SH EXAMPLES These examples, apart from the last one, use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .TP sg_raw /dev/scd0 1b 00 00 00 02 00 Eject the medium in CD drive /dev/scd0. .TP sg_raw \-r 1k /dev/sg0 12 00 00 00 60 00 Perform an INQUIRY on /dev/sg0 and dump the response data (up to 1024 bytes) to stdout. .TP sg_raw \-s 512 \-i i512.bin /dev/sda 3b 02 00 00 00 00 00 02 00 00 Showing an example of writing 512 bytes to a sector on a disk is a little dangerous. Instead this example will read i512.bin (assumed to be 512 bytes long) and use the SCSI WRITE BUFFER command to send it to the "data" buffer (that is mode 2). This is a safe operation. .TP sg_raw \-r 512 \-o o512.bin /dev/sda 3c 02 00 00 00 00 00 02 00 00 This will use the SCSI READ BUFFER command to read 512 bytes from the "data" buffer (i.e. mode 2) then write it to the o512.bin file. When used in conjunction with the previous example, if both commands work then 'cmp i512.bin o512.bin' should show a match. .TP sg_raw \-\-infile=urandom.bin \-\-send=512 \-\-request=512 \-\-outfile=out.bin "/dev/bsg/7:0:0:0" 53 00 00 00 00 00 00 00 01 00 This is a bidirectional XDWRITEREAD(10) command being sent via a Linux bsg device. Note that data is being read from "urandom.bin" and sent to the device (data\-out) while resulting data (data\-in) is placed in the "out.bin" file. Also note the length of both is 512 bytes which corresponds to the transfer length of 1 (block) in the cdb (i.e. the second last byte). .TP sg_raw.exe PhysicalDrive1 a1 0c 0e 00 00 00 00 00 00 e0 00 00 This example is from Windows and shows a ATA STANDBY IMMEDIATE command being sent to PhysicalDrive1. That ATA command is contained within the SCSI ATA PASS\-THROUGH(12) command (see the SAT or SAT\-2 standard at http://www.t10.org). Notice that the STANDBY IMMEDIATE command does not send or receive any additional data, however if it fails sense data should be returned and displayed. .SH EXIT STATUS The exit status of sg_raw is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Ingo van Lil .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2001\-2014 Ingo van Lil .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_vpd, sg3_utils (sg3_utils), plscsi sg3_utils-1.40/doc/scsi_logging_level.80000664000175000017500000001050512333156560017051 0ustar douggdougg.TH SCSI_LOGGING_LEVEL "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME scsi_logging_level \- access Linux SCSI logging level information .SH SYNOPSIS .B scsi_logging_level [\fI\-\-all=LEV\fR] [\fI\-\-create\fR] [\fI\-\-error=LEV\fR] [\fI\-\-get\fR] [\fI\-\-help\fR] [\fI\-\-highlevel=LEV\fR] [\fI\-\-hlcomplete=LEV\fR] [\fI\-\-hlqueue=LEV\fR] [\fI\-\-ioctl=LEV\fR] [\fI\-\-llcomplete=LEV\fR] [\fI\-\-llqueue=LEV\fR] [\fI\-\-lowlevel=LEV\fR] [\fI\-\-midlevel=LEV\fR] [\fI\-\-mlcomplete=LEV\fR] [\fI\-\-mlqueue=LEV\fR] [\fI\-\-scan=LEV\fR] [\fI\-\-set\fR] [\fI\-\-timeout=LEV\fR] [\fI\-\-version\fR] .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script accesses the Linux SCSI subsystem logging level. The current values can be shown (e.g. with \fI\-\-get\fR) or changed (e.g. with \fI\-\-set\fR). Superuser permissions will typically be required to set the logging level. .PP One of these options: \fI\-\-create\fR, \fI\-\-get\fR or \fI\-\-set\fR is required. Only one can be given. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-all\fR=\fILEV\fR \fILEV\fR is used for all SCSI_LOG fields. .TP \fB\-c\fR, \fB\-\-create\fR Options are parsed and placed in internal fields that are displayed but no logging levels are changed within the Linux kernel. .TP \fB\-E\fR, \fB\-\-error\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_ERROR field. .TP \fB\-g\fR, \fB\-\-get\fR Fetches the current SCSI logging levels from the Linux kernel and displays them. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-H\fR, \fB\-\-highlevel\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_HLQUEUE and SCSI_LOG_HLCOMPLETE fields. .TP \fB\-\-hlcomplete\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_HLCOMPLETE field. .TP \fB\-\-hlqueue\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_HLQUEUE field. .TP \fB\-I\fR, \fB\-\-ioctl\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_IOCTL field. .TP \fB\-\-llcomplete\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_LLCOMPLETE field. .TP \fB\-\-llqueue\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_LLQUEUE field. .TP \fB\-L\fR, \fB\-\-lowlevel\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_LLQUEUE and SCSI_LOG_LLCOMPLETE fields. .TP \fB\-M\fR, \fB\-\-midlevel\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_MLQUEUE and SCSI_LOG_MLCOMPLETE fields. .TP \fB\-\-mlcomplete\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_MLCOMPLETE field. .TP \fB\-\-mlqueue\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_MLQUEUE field. .TP \fB\-S\fR, \fB\-\-scan\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_SCAN field. .TP \fB\-s\fR, \fB\-\-set\fR Uses the fields specified in this command's options and attempts to apply them to the Linux SCSI subsystem logging levels. Typically superuser permissions will be required to do this. .TP \fB\-T\fR, \fB\-\-timeout\fR=\fILEV\fR \fILEV\fR is placed in the SCSI_LOG_TIMEOUT field. .TP \fB\-v\fR, \fB\-\-version\fR Outputs the version information and then exits. .SH NOTES The \fI\-\-get\fR and \fI\-\-set\fR options access the /proc/sys/dev/scsi/logging_level pseudo file. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Any other exit status indicates that an error has occurred. .SH EXAMPLES The following will set SCSI_LOG_ERROR to level 5 in the Linux kernel. It requires root permissions: .PP scsi_logging_level \-s \-E 5 .PP So as to not interfere with other SCSI subsystem upper level drivers (ULDs) which most likely will be active at the same time, the Linux sg driver uses SCSI_LOG_TIMEOUT. To see full debugging and trace from the sg driver use: .PP scsi_logging_level \-s \-T 7 .PP The output from the sg driver caused by this will go to the system logs (e.g. /var/log/syslog). To reduce the amount of output use a number lower than 7. Using 0 will turn off the tracing and debug. .SH AUTHORS Written by IBM. Small alterations by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co IBM Corp. 2006 .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .PP The software was obtained from an IBM package called s390\-tools\-1.6.2 found on that company's "developerworks" site. The most recent version of that package at this time is 1.8.3 . sg3_utils-1.40/doc/sg_map26.80000664000175000017500000001331312142450532014623 0ustar douggdougg.TH SG_MAP26 "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_map26 \- map SCSI generic (sg) device to corresponding device names .SH SYNOPSIS .B sg_map26 [\fI\-\-dev_dir=DIR\fR] [\fI\-\-given_is=\fR0|1] [\fI\-\-help\fR] [\fI\-\-result=\fR0|1|2|3] [\fI\-\-symlink\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Maps a special file (block or char) associated with a SCSI device to the corresponding SCSI generic (sg) device, or vice versa. Can also be given a sysfs file, for example '/sys/block/sda' or '/sys/block/sda/dev'. .PP Rather than map to or from a sg device, the sysfs file name matching a given device special file (or vice versa) can be requested. This is done with '\-\-result=2' and '\-\-result=3'. This feature works on ATA devices (e.g. 'dev/hdc') as well as SCSI devices. .PP In this utility, "mapped" refers to finding the relationship between a SCSI generic (sg) node and the higher level SCSI device name; or vice versa. For example '/dev/sg0' may "map" to '/dev/sda'. Mappings may not exist, if a relevant module is not loaded, for example. Also there are SCSI devices that can only be accessed via a sg node (e.g. SAF\-TE and some SES devices). .PP In this utility, "matching" refers to different representations of the same device accessed via the same driver. For example, '/dev/hdc' and '/sys/block/hdc' usually refer to the same device and thus would be considered matching. A related example is that '/dev/cdrom' and '/dev/hdc' are also considered matching if '/dev/cdrom' is a symlink to '/dev/hdc'. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-dev_dir\fR=\fIDIR\fR where \fIDIR\fR is the directory to search for resultant device special files in (or symlinks to same). Only active when '\-\-result=0' (the default) or '\-\-result=2'. If this option is not given and \fIDEVICE\fR is a device special file then the directory part of \fIDEVICE\fR is assumed. If this option is not given and \fIDEVICE\fR is a sysfs name, then if necessary '/dev' is assumed as the directory. .TP \fB\-g\fR, \fB\-\-given_is\fR=0 | 1 specifies the \fIDEVICE\fR is either a device special file (when the argument is 0), or a sysfs 'dev' file (when the argument is 1). The parent directory of a sysfs 'dev' file is also accepted (e.g. either '/sys/block/sda/dev' or '/sys/block/sda' are accepted). Usually there is no need to give this option since this utility first checks for special files (or symlinks to special files) and if not, assumes it has been given a sysfs 'dev' file (or its parent). Generates an error if given and disagrees with variety of \fIDEVICE\fR. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-r\fR, \fB\-\-result\fR=0 | 1 | 2 | 3 specifies what variety of file (or files) that this utility tries to find. The default is a "mapped" device special file, when the argument is 0. When the argument is 1, this utility tries to find the "mapped" sysfs node name. When the argument is 2, this utility tries to find the "matching" device special file. When the argument is 3, this utility tries to find the "matching" sysfs node name. .TP \fB\-s\fR, \fB\-\-symlink\fR when a device special file is being sought (i.e. when '\-\-result=0' (the default) or '\-\-result=2') then also look for symlinks to that device special file in the same directory. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES This utility is designed for the Linux 2.6 (and later) kernel series. It uses special file major and minor numbers (and whether the special is block or character) together with sysfs to do its mapping or matching. In the absence of any other information, device special files are assumed to be in the '/dev' directory while sysfs is assumed to be mounted at '/sys'. Device names in sysfs are predictable, given the corresponding major and minor number of the device. However, due to udev rules, the name of device special files can be anything the user desires (e.g. '/dev/sda' could be named '/dev/my_boot_disk'). When trying to find a resultant device special file, this utility uses the major and minor numbers (and whether a block or char device is sought) to search the device directory. .PP This utility only shows one relationship at a time. To get an overview of all SCSI devices, with special file names and optionally the "mapped" sg device name, see the lsscsi utility. .SH EXAMPLES Assume sg2 maps to sdb while dvd, cdrom and hdc are all matching. .PP # sg_map26 /dev/sg2 .br /dev/sdb .PP # sg_map26 /dev/sdb .br /dev/sg2 .PP # sg_map26 \-\-result=0 /dev/sdb .br /dev/sg2 .PP # sg_map26 \-\-result=3 /dev/sdb .br /sys/block/sda .PP # sg_map26 \-\-result=1 /dev/sdb .br /sys/class/scsi_generic/sg0 .PP Now look at '/dev/hdc' and friends .PP # sg_map26 /dev/hdc .br .PP # sg_map26 \-\-result=3 /dev/hdc .br /sys/block/hdc .PP # sg_map26 \-\-result=2 /dev/hdc .br /dev/hdc .PP # sg_map26 \-\-result=2 \-\-symlink /dev/hdc .br /dev/cdrom .br /dev/dvd .br /dev/hdc .PP # sg_map26 \-\-result=2 \-\-symlink /sys/block/hdc .br /dev/cdrom .br /dev/dvd .br /dev/hdc .SH EXIT STATUS The exit status of sg_map26 is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B udev(7), lsscsi(lsscsi) sg3_utils-1.40/doc/README0000664000175000017500000000225111715321645014002 0ustar douggdouggVarious html files used to be included in this directory but they were beginning to bloat the size of the source tarball so they have been removed in version 1.24 . Here are the urls of the files that were previously here plus a brief summary: http://sg.danny.cz/sg/sg3_utils.html - overview and examples of this package http://sg.danny.cz/sg/sg_dd.html - discussion and examples of the sg_dd utility which is a dd variant (also discusses the sgm_dd, sgp_dd and sg_read utilities) http://sg.danny.cz/sg/sg_ses.html - discussion and examples of the sg_ses utility. SCSI Enclosure Services (SES) devices may contain a lot of information, structured in a non-trivial way. http://sg.danny.cz/sg/sg_io.html - discussion of Linux SG_IO ioctl (SCSI pass-through) http://sg.danny.cz/sg/tools.html - overview of around 25 storage and SCSI tools There are two versions of sg_scan: one for Linux and the other for Windows. They have different man pages: sg_scan.8.linux and sg_scan.8.win32 with the Makefile logic (rule in Makefile.am) copying the appropriate one to sg_scan.8 . sg_scan is not supported for other ports. Douglas Gilbert 10th February 2010 sg3_utils-1.40/doc/Makefile.in0000664000175000017500000005355012430315266015174 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = doc DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } man8dir = $(mandir)/man8 am__installdirs = "$(DESTDIR)$(man8dir)" NROFF = nroff MANS = $(man_MANS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @OS_FREEBSD_TRUE@man_MANS = \ @OS_FREEBSD_TRUE@ sg3_utils.8 sg_decode_sense.8 \ @OS_FREEBSD_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_FREEBSD_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_FREEBSD_TRUE@ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ @OS_FREEBSD_TRUE@ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ @OS_FREEBSD_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_FREEBSD_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ @OS_FREEBSD_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ @OS_FREEBSD_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ @OS_FREEBSD_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ @OS_FREEBSD_TRUE@ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ @OS_FREEBSD_TRUE@ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ @OS_FREEBSD_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ @OS_FREEBSD_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 # sg_dd, sg_emc_trespass(?), sginfo, sg_map26, sg_map, sgm_dd, sgp_dd, # sg_rbuf, sg_read, sg_reset, sg_test_rwbuf # are Linux only utilities # # sg_scan is shared by Linux and Win32 @OS_LINUX_TRUE@man_MANS = \ @OS_LINUX_TRUE@ rescan-scsi-bus.sh.8 \ @OS_LINUX_TRUE@ sg3_utils.8 sg_decode_sense.8 scsi_logging_level.8 \ @OS_LINUX_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_LINUX_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_LINUX_TRUE@ sg_compare_and_write.8 sg_copy_results.8 sg_dd.8 sg_emc_trespass.8 \ @OS_LINUX_TRUE@ sg_format.8 sg_get_config.8 sg_get_lba_status.8 sg_ident.8 sginfo.8 \ @OS_LINUX_TRUE@ sg_inq.8 sg_logs.8 sg_luns.8 sg_map26.8 sg_map.8 sgm_dd.8 \ @OS_LINUX_TRUE@ sg_modes.8 sg_opcodes.8 sgp_dd.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_LINUX_TRUE@ sg_rbuf.8 sg_rdac.8 sg_read.8 sg_readcap.8 sg_read_block_limits.8 \ @OS_LINUX_TRUE@ sg_read_buffer.8 sg_read_long.8 sg_reassign.8 sg_referrals.8 \ @OS_LINUX_TRUE@ sg_rep_zones.8 sg_requests.8 sg_reset.8 sg_reset_wp.8 sg_rmsn.8 \ @OS_LINUX_TRUE@ sg_rtpg.8 sg_safte.8 sg_sanitize.8 sg_sat_identify.8 \ @OS_LINUX_TRUE@ sg_sat_phy_event.8 sg_sat_read_gplog.8 sg_sat_set_features.8 \ @OS_LINUX_TRUE@ sg_scan.8 sg_senddiag.8 sg_ses.8 sg_ses_microcode.8 sg_start.8 \ @OS_LINUX_TRUE@ sg_stpg.8 sg_sync.8 sg_test_rwbuf.8 sg_turs.8 sg_unmap.8 sg_verify.8 \ @OS_LINUX_TRUE@ sg_vpd.8 sg_write_buffer.8 sg_write_long.8 sg_write_same.8 \ @OS_LINUX_TRUE@ sg_write_verify.8 sg_wr_mode.8 sg_xcopy.8 @OS_OSF_TRUE@man_MANS = \ @OS_OSF_TRUE@ sg3_utils.8 sg_decode_sense.8 \ @OS_OSF_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_OSF_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_OSF_TRUE@ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ @OS_OSF_TRUE@ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ @OS_OSF_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_OSF_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ @OS_OSF_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ @OS_OSF_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ @OS_OSF_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ @OS_OSF_TRUE@ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ @OS_OSF_TRUE@ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ @OS_OSF_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ @OS_OSF_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 @OS_SOLARIS_TRUE@man_MANS = \ @OS_SOLARIS_TRUE@ sg3_utils.8 sg_decode_sense.8 \ @OS_SOLARIS_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_SOLARIS_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_SOLARIS_TRUE@ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ @OS_SOLARIS_TRUE@ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ @OS_SOLARIS_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_SOLARIS_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ @OS_SOLARIS_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ @OS_SOLARIS_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ @OS_SOLARIS_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ @OS_SOLARIS_TRUE@ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_senddiag.8 sg_ses.8 \ @OS_SOLARIS_TRUE@ sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 sg_turs.8 \ @OS_SOLARIS_TRUE@ sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 sg_write_long.8 \ @OS_SOLARIS_TRUE@ sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 @OS_WIN32_CYGWIN_TRUE@man_MANS = \ @OS_WIN32_CYGWIN_TRUE@ sg3_utils.8 sg_decode_sense.8 \ @OS_WIN32_CYGWIN_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_WIN32_CYGWIN_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \ @OS_WIN32_CYGWIN_TRUE@ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 @OS_WIN32_MINGW_TRUE@man_MANS = \ @OS_WIN32_MINGW_TRUE@ sg3_utils.8 sg_decode_sense.8 \ @OS_WIN32_MINGW_TRUE@ scsi_mandat.8 scsi_readcap.8 scsi_ready.8 scsi_satl.8 \ @OS_WIN32_MINGW_TRUE@ scsi_start.8 scsi_stop.8 scsi_temperature.8 \ @OS_WIN32_MINGW_TRUE@ sg_compare_and_write.8 sg_format.8 sg_get_config.8 \ @OS_WIN32_MINGW_TRUE@ sg_get_lba_status.8 sg_ident.8 sg_inq.8 sg_logs.8 sg_luns.8 \ @OS_WIN32_MINGW_TRUE@ sg_modes.8 sg_opcodes.8 sg_persist.8 sg_prevent.8 sg_raw.8 \ @OS_WIN32_MINGW_TRUE@ sg_rdac.8 sg_readcap.8 sg_read_block_limits.8 sg_read_buffer.8 \ @OS_WIN32_MINGW_TRUE@ sg_read_long.8 sg_reassign.8 sg_referrals.8 sg_rep_zones.8 \ @OS_WIN32_MINGW_TRUE@ sg_requests.8 sg_reset_wp.8 sg_rmsn.8 sg_rtpg.8 sg_safte.8 \ @OS_WIN32_MINGW_TRUE@ sg_sanitize.8 sg_sat_identify.8 sg_sat_phy_event.8 \ @OS_WIN32_MINGW_TRUE@ sg_sat_read_gplog.8 sg_sat_set_features.8 sg_scan.8 sg_senddiag.8 \ @OS_WIN32_MINGW_TRUE@ sg_ses.8 sg_ses_microcode.8 sg_start.8 sg_stpg.8 sg_sync.8 \ @OS_WIN32_MINGW_TRUE@ sg_turs.8 sg_unmap.8 sg_verify.8 sg_vpd.8 sg_write_buffer.8 \ @OS_WIN32_MINGW_TRUE@ sg_write_long.8 sg_write_same.8 sg_write_verify.8 sg_wr_mode.8 all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu doc/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu doc/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-man8: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man8dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.8[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(MANS) installdirs: for dir in "$(DESTDIR)$(man8dir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @OS_LINUX_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_FALSE@distclean-local: clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-local dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-man uninstall-man: uninstall-man8 .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distclean-local distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man8 install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-man uninstall-man8 @OS_LINUX_TRUE@distclean-local: @OS_LINUX_TRUE@ rm -f sg_scan.8 @OS_LINUX_TRUE@sg_scan.8 : sg_scan.8.linux @OS_LINUX_TRUE@ cp -p sg_scan.8.linux sg_scan.8 @OS_WIN32_MINGW_TRUE@distclean-local: @OS_WIN32_MINGW_TRUE@ rm -f sg_scan.8 @OS_WIN32_MINGW_TRUE@sg_scan.8 : sg_scan.8.win32 @OS_WIN32_MINGW_TRUE@ cp -p sg_scan.8.win32 sg_scan.8 @OS_WIN32_CYGWIN_TRUE@distclean-local: @OS_WIN32_CYGWIN_TRUE@ rm -f sg_scan.8 @OS_WIN32_CYGWIN_TRUE@sg_scan.8 : sg_scan.8.win32 @OS_WIN32_CYGWIN_TRUE@ cp -p sg_scan.8.win32 sg_scan.8 # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/doc/sg_persist.80000664000175000017500000004747512415077207015416 0ustar douggdougg.TH SG_PERSIST "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_persist \- use SCSI PERSISTENT RESERVE command to access registrations and reservations .SH SYNOPSIS .B sg_persist [\fIOPTIONS\fR] \fIDEVICE\fR .PP .B sg_persist [\fIOPTIONS\fR] \fI\-\-device=DEVICE\fR .PP .B sg_persist \fI\-\-help\fR | \fI\-\-version\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility allows Persistent reservations and registrations to be queried and changed. Persistent reservations and registrations are queried by sub\-commands (called "service actions" in SPC\-4) of the SCSI PERSISTENT RESERVE IN (PRIN) command. Persistent reservations and registrations are changed by sub\-commands of the SCSI PERSISTENT RESERVE OUT (PROUT) command. .PP There is a two stage process to obtain a persistent reservation. First an application (an I_T nexus in standard's jargon) must register a reservation key. If that is accepted (and it should be unless some other I_T nexus has registered that key) then the application can try and reserve the device. The reserve operation must specify the reservation key and a "type" (see the \fI\-\-prout\-type=TYPE\fR option). .PP It is relatively safe to query the state of Persistent reservations and registrations. With no options this utility defaults to the READ KEYS sub\-command of the PRIN command. Other PRIN sub\-commands are READ RESERVATION, REPORT CAPABILITIES and READ FULL STATUS. .PP Before trying to change Persistent reservations and registrations users should be aware of what they are doing. The relevant sections of the SCSI Primary Commands document (i.e. SPC\-4 whose most recent draft is revision 37 dated 17 May 2014) are sections 5.12 (titled "Reservations"), 6.15 (for the PRIN command) and 6.16 (for the PROUT command). To safeguard against accidental use, the \fI\-\-out\fR option must be given when a PROUT sub\-command (e.g. \fI\-\-register\fR) is used. .PP The older SCSI RESERVE and RELEASE commands (both 6 and 10 byte variants) are not supported by this utility. In SPC\-3, RESERVE and RELEASE are deprecated, replaced by Persistent Reservations. RESERVE and RELEASE have been removed from SPC\-4 and Annex B is provided showing how to convert to persistent reservation commands. See a utility called 'scsires' for support of the SCSI RESERVE and RELEASE commands. .PP The \fIDEVICE\fR is required by all variants of this utility apart from \fI\-\-help\fR. The \fIDEVICE\fR can be given either as an argument (typically but not necessarily the last one) or via the \fI\-\-device=DEVICE\fR option. .PP SPC\-4 does not use the term "sub\-command". It uses the term "service action" for this and for part of a field's name in the parameter block associated with the PROUT command (i.e. "service action reservation key"). To lessen the potential confusion the term "sub\-command" has been introduced. .SH OPTIONS Arguments to long options are mandatory for short options as well. The following options are sorted in alphabetical order, based on their long option name. .TP \fB\-l\fR, \fB\-\-alloc-length\fR=\fILEN\fR specify the allocation length of the PRIN command. \fILEN\fR is a hex value. By default this value is set to the size of the data\-in buffer (8192). This parameter is of use for verification that response to PRIN commands with various allocation lengths is per section 4.3.5.6 of SPC\-4 revision 18. Valid \fILEN\fR values are 0\-8192. .TP \fB\-C\fR, \fB\-\-clear\fR Clear is a sub\-command of the PROUT command. It releases the persistent reservation (if any) and clears all registrations from the device. It is required to supply a reservation key that is registered for this I_T_L nexus (identified by \fI\-\-param\-rk=RK\fR). .TP \fB\-d\fR, \fB\-\-device\fR=\fIDEVICE\fR \fIDEVICE\fR to send SCSI commands to. The \fIDEVICE\fR can either be provided via this option or via a freestanding argument. For example, these two: 'sg_persist \-\-device=/dev/sg2' and 'sg_persist /dev/sg2' are equivalent. .TP \fB\-h\fR, \fB\-\-help\fR output a usage message showing main options. Use twice (e.g. '\-hh') for the other option and more help. .TP \fB\-H\fR, \fB\-\-hex\fR the response to a valid PRIN sub\-command will be output in hexadecimal. By default (i.e. without this option) if the PRIN sub\-command is recognised then the response will be decoded as per SPC\-4. May be used more than once for more hex and less text. .TP \fB\-i\fR, \fB\-\-in\fR specify that a SCSI PERSISTENT RESERVE IN command is required. This is the default. .TP \fB\-n\fR, \fB\-\-no\-inquiry\fR the default action is to do a standard SCSI INQUIRY command and output make, product and revision strings plus the peripheral device type prior to executing a PRIN or PROUT command. With this option the INQUIRY command is skipped. .TP \fB\-o\fR, \fB\-\-out\fR specify that a SCSI PERSISTENT RESERVE OUT command is required. .TP \fB\-Y\fR, \fB\-\-param\-alltgpt\fR set the 'all target ports' (ALL_TG_PT) flag in the parameter block of the PROUT command. Only relevant for 'register' and 'register and ignore existing key' sub\-commands. .TP \fB\-Z\fR, \fB\-\-param\-aptpl\fR set the 'activate persist through power loss' (APTPL) flag in the parameter block of the PROUT command. Relevant for 'register', 'register and ignore existing key' and 'register and move' sub\-commands. .TP \fB\-K\fR, \fB\-\-param\-rk\fR=\fIRK\fR specify the reservation key found in the parameter block of the PROUT command. \fIRK\fR is assumed to be hex (up to 8 bytes long). Default value is 0. This option is needed by most PROUT sub\-commands. .TP \fB\-S\fR, \fB\-\-param\-sark\fR=\fISARK\fR specify the service action reservation key found in the parameter block of the PROUT command. \fISARK\fR is assumed to be hex (up to 8 bytes long). Default value is 0. This option is needed by some PROUT sub\-commands. .TP \fB\-P\fR, \fB\-\-preempt\fR Preempt is a sub\-command of the PROUT command. Preempts the existing persistent reservation (identified by \fI\-\-param\-sark=SARK\fR) with the registration key that is registered for this I_T_L nexus (identified by \fI\-\-param\-rk=RK\fR). If a new reservation is established as a result of the preemption then the supplied \fI\-\-prout\-type=TYPE\fR is used as the type for this new reservation. .TP \fB\-A\fR, \fB\-\-preempt\-abort\fR Preempt and Abort is a sub\-command of the PROUT command. Preempts the existing persistent reservation (identified by \fI\-\-param\-sark=SARK\fR) with the registration key that is registered for this I_T_L nexus (identified by \fI\-\-param\-rk=RK\fR). If a new reservation is established as a result of the preemption then the supplied \fI\-\-prout\-type=TYPE\fR is used as the type for this new reservation. ACA and other pending tasks are aborted. .TP \fB\-T\fR, \fB\-\-prout\-type\fR=\fITYPE\fR specify the PROUT command's 'type' argument. Required by the 'register\-move', 'reserve', 'release' and 'preempt (and abort)' sub\-commands. Valid \fITYPE\fR values: 1\-> write exclusive, 3\-> exclusive access, 5\-> write exclusive \- registrants only, 6\-> exclusive access \- registrants only, 7\-> write exclusive \- all registrants, 8\-> exclusive access \- all registrants. Default value is 0 (which is an invalid type). Each "persistent reservation type" is explained in more detail in a subsection of that name in the read reservation section of the PRIN command (section 6.15.3.3 of SPC\-4 revision 37). .TP \fB\-s\fR, \fB\-\-read\-full\-status\fR Read Full Status is a sub\-command of the PRIN command. For each registration with the given SCSI device, it lists the reservation key and associated information. TransportIDs, if supplied in the response, are decoded. .TP \fB\-k\fR, \fB\-\-read\-keys\fR Read Keys is a sub\-command of the PRIN command. Lists all the reservation keys registered (i.e. registrations) with the given SCSI device. This is the default sub\-command for the SCSI PRIN command. .TP \fB\-y\fR, \fB\-\-readonly\fR Open \fIDEVICE\fR read\-only. May be useful with PRIN commands if there are unwanted side effects with the default read\-write open. When given twice is interpreted as forcing a read\-write open thus overriding the SG_PERSIST_IN_RDONLY environment variable if present. .TP \fB\-r\fR, \fB\-\-read\-reservation\fR Read Reservation is a sub\-command of the PRIN command. List information about the current holder of the reservation on the \fIDEVICE\fR. If there is no current reservation this will be noted. Information about the current holder of the reservation includes its reservation key, scope and type. .TP \fB\-s\fR, \fB\-\-read\-status\fR same as \fI\-\-read\-full\-status\fR. .TP \fB\-G\fR, \fB\-\-register\fR Register is a sub\-command of the PROUT command. It has 3 different actions depending on associated parameters. a) add a new registration with '\-\-param\-rk=0' and '\-\-param\-sark='; b) Change an existing registration with '\-\-param\-rk=' and '\-\-param\-sark='; or c) Delete an existing registration with '\-\-param\-rk=' and '\-\-param\-sark=0'. .TP \fB\-I\fR, \fB\-\-register\-ignore\fR Register and Ignore Existing Key is a sub\-command of the PROUT command. Similar to \fI\-\-register\fR except that when changing a reservation key the old key is not specified. The '\-\-param\-sark=' option should also be given. .TP \fB\-M\fR, \fB\-\-register\-move\fR register (another initiator) and move (the reservation held by the current initiator to that other initiator) is a sub\-command of the PROUT command. It requires the transportID of the other initiator. [The standard uses the term I_T nexus but the point to stress is that there are two initiators (the one sending this command and another one) but only one logical unit.] The \fI\-\-prout\-type=TYPE\fR and \fI\-\-param\-rk=RK\fR options need to match that of the existing reservation while \fI\-\-param\-sark=SARK\fR option specifies the reservation key of the new (i.e. destination) registration. .TP \fB\-Q\fR, \fB\-\-relative\-target\-port\fR=\fIRTPI\fR relative target port identifier that reservation is to be moved to by PROUT 'register and move' sub\-command. \fIRTPI\fR is assumed to be hex in the range 0 to ffff inclusive. Defaults to 0 . .TP \fB\-L\fR, \fB\-\-release\fR Release is a sub\-command of the PROUT command. It releases the current persistent reservation. The \fI\-\-prout\-type=TYPE\fR and \fI\-\-param\-rk=RK\fR options, matching the reservation, must also be specified. .TP \fB\-z\fR, \fB\-\-replace\-lost\fR Replace Lost Reservation is a sub\-command of the PROUT command. It "begins a recovery process for the lost persistent reservation that is managed by application clients". It also stops the device server terminating commands due to a lost persistent reservation. Options should be be '\-\-param\-rk=0' (or not given), '\-\-param\-sark=' and \fI\-\-prout\-type=TYPE\fR. .TP \fB\-c\fR, \fB\-\-report\-capabilities\fR Report Capabilities is a sub\-command of the PRIN command. It lists information about the aspects of persistent reservations that the \fIDEVICE\fR supports. .TP \fB\-R\fR, \fB\-\-reserve\fR Reserve is a sub\-command of the PROUT command. It creates a new persistent reservation (if permitted). The \fI\-\-prout\-type=TYPE\fR and \fI\-\-param\-rk=RK\fR options must also be specified. .TP \fB\-X\fR, \fB\-\-transport\-id\fR=\fITIDS\fR The \fITIDS\fR argument can take one of several forms. It can be a comma (or single space) separated list of ASCII hex bytes representing a single TransportID as defined in SPC\-4. They are usually 24 bytes long apart from in iSCSI. The \fITIDS\fR argument may be a transport specific form (e.g. "sas,5000c50005b32001" is clearer than and equivalent to the hex byte form: "6,0,0,0,5,0,c5,0,5,b3,20,1"). The \fITIDS\fR argument may be "\-" in which case one or more TransportIDs can be read from stdin. The \fITIDS\fR argument may be of the form "file=" in which case one or more TransportIDs can be read from a file called . See the "TRANSPORT IDs" section below for more information. .TP \fB\-U\fR, \fB\-\-unreg\fR optional when the PROUT register and move sub\-command is invoked. If given it will unregister the current initiator (I_T nexus) after the other initiator has been registered and the reservation moved to it. When not given the initiator (I_T nexus) that sent the PROUT command remains registered. .TP \fB\-v\fR, \fB\-\-verbose\fR print out cdb of issued commands prior to execution. If used twice prints out the parameter block associated with the PROUT command prior to its execution as well. If used thrice decodes given transportID(s) as well. To see the response to a PRIN command in low level form use the \fI\-\-hex\fR option. .TP \fB\-V\fR, \fB\-\-version\fR print out version string. Ignore all other parameters. .TP \fB\-?\fR output usage message. Ignore all other parameters. .SH TRANSPORT IDs TransportIDs are used in persistent reservations to identify initiators. The format of a TransportID differs depending on the type of transport being used. Their format is described in SPC\-4 (in draft revision 37 see section 7.6.4). .PP A TransportID is required for the PROUT 'register and move' sub\-command and the PROUT 'register' sub\-command can have zero, one or more TransportIDs. .PP When the \fI\-\-transport\-id=TIDS\fR option is given then the \fITIDS\fR argument may be a comma (or single space) separated list of ASCII hex bytes that represent a single TransportID as defined in SPC\-4. Alternatively the \fITIDS\fR argument may be a transport specific string starting with either "fcp,", "spi,", "sbp,", "srp,", "iqn", "sas," or "sop,". The "iqn" form is an iSCSI qualified name. Apart from "iqn" the other transport specific leadin string may be given in upper case (e.g. "FCP,"). .PP The "fcp," form should be followed by 16 ASCII hex digits that represent an initiator's N_PORT_NAME (e.g. "fcp,10000000C9F3A571"). The "spi," form should be followed by "," (both decimal numbers). The "sbp," form should be followed by 16 ASCII hex digits that represent an initiator's EUI\-64 name. The "srp," form should be followed by 32 ASCII hex digits that represent an initiator port identifier. The "sas," form should be followed by 16 ASCII hex digits that represent an initiator's port SAS address (e.g. "sas,5000c50005b32001"). The "sop," form takes a hex number that represents a routing id. .PP There are two iSCSI qualified name forms. The shorter form contains the iSCSI name of the initiator port (e.g. "iqn.5886.com.acme.diskarrays\-sn\-a8675309"). The longer form adds the initiator session id (ISID in hex) separated by ",i,0x". For example "iqn.5886.com.acme.diskarrays\-sn\-a8675309,i,0x1234567890ab". On the command line to stop punctuation in an iSCSI name being (mis)\-interpreted by the shell, putting the option argument containing the iSCSI name in double quotes is advised. iSCSI names are encoded in UTF\-8 so if non (7 bit) ASCII characters appear in the iSCSI name on the command line, there will be difficulties if they are not encoded in UTF\-8. The locale can be changed temporarily by prefixing the command line invocation of sg_persist with "LANG=en_US.utf\-8" for example. .PP Alternatively the \fITIDS\fR argument may specify a file (or pipe) from which one or more TransportIDs may be read. If the \fITIDS\fR argument is "\-" then stdin (standard input) is read. If the \fITIDS\fR argument is of the form "file=" than a file called is read. A valid SPC\-4 TransportID is built from the transport specific string outlined in the previous paragraphs. The parsing of the data read is relatively simple. Empty lines are ignored. Everything from and including a "#" on a line is ignored. Leading spaces and tabs are ignored. There can be one transportID per line. The transportID can either be a comma, space or tab separated list of ASCII hex bytes that represent a TransportID as defined in SPC\-4. Padding with zero bytes to a minimum length of 24 bytes is performed if necessary. The transportID may also be transport specific string type discussed above. .PP In SPC\-3 the SPEC_I_PT bit set to one and TransportIDs were allowed for the PROUT register and ignore existing key sub\-command. In SPC\-4 that is disallowed yielding a CHECK CONDITION status with and ILLEGAL REQUEST sense key and an additional sense code set to INVALID FIELD IN PARAMETER LIST. .SH ENVIRONMENT VARIABLES Currently there is one recognised environment variable: SG_PERSIST_IN_RDONLY. If present and only if a PRIN command has been selected then the given \fIDEVICE\fR is opened read\-only (e.g. in Unix that is with the O_RDONLY flag). See the \fI\-\-readonly\fR option. .SH NOTES In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series any SCSI device name (e.g. /dev/sdc, /dev/st1m or /dev/sg3) can be specified. For example "sg_persist \-\-read\-keys /dev/sdb" will work in the 2.6 series kernels. .PP The only scope for PROUT commands supported in the current draft of SPC\-4 is "LU_SCOPE". Hence there seems to be no point in offering an option to set scope to another value. .PP Most errors with the PROUT sub\-commands (e.g. missing or mismatched \fI\-\-prout\-type=TYPE\fR) will result in a RESERVATION CONFLICT status. This can be a bit confusing when you know there is only one (active) initiator: the "conflict" is with the SPC standard, not another initiator. .PP Some recent disks accept some PRIN and PROUT sub\-commands when the media is stopped. One exception was setting the APTPL flag (with the \fI\-\-param\-aptpl\fR option) during a key register operation, it complained if the disk one stopped. The error indicated it wanted the disk spun up and when that happened, the registration was successful. .SH EXAMPLES These examples use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP Due to the various option defaults the simplest example executes the 'read keys' sub\-command of the PRIN command: .PP sg_persist /dev/sdb .PP This is the same as the following (long\-winded) command: .PP sg_persist \-\-in \-\-read\-keys \-\-device=/dev/sdb .PP To read the current reservation either the '\-\-read\-reservation' form or the shorter '\-r' can be used: .PP sg_persist \-r /dev/sdb .PP To .B register the new reservation key 0x123abc the following could be used: .PP sg_persist \-\-out \-\-register \-\-param\-sark=123abc /dev/sdb .PP Given the above registration succeeds, to .B reserve the \fIDEVICE\fR (with type 'write exclusive') the following could be used: .PP sg_persist \-\-out \-\-reserve \-\-param\-rk=123abc .br \-\-prout\-type=1 /dev/sdb .PP To .B release the reservation the following can be given (note that the \-\-param\-rk and \-\-prout\-type arguments must match those of the reservation): .PP sg_persist \-\-out \-\-release \-\-param\-rk=123abc .br \-\-prout\-type=1 /dev/sdb .PP Finally to .B unregister a reservation key (and not effect other registrations which is what '\-\-clear' would do) the command is a little surprising: .PP sg_persist \-\-out \-\-register \-\-param\-rk=123abc /dev/sdb .PP Now have a close look at the difference between the register and unregister examples above. .PP An example file that is suitably formatted to pass transportIDs via a '\-\-transport\-id=file=transport_ids.txt' option can be found in the examples sub\-directory of the sg3_utils package. There is also a simple test script called sg_persist_tst.sh in the same directory. .PP The above sequence of commands was tested successfully on a Seagate Savvio 10K.3 disk and a 1200 SSD both of which have SAS interfaces. .SH EXIT STATUS The exit status of sg_persist is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg3_utils(sg3_utils), scsires(internet) sg3_utils-1.40/doc/sg_compare_and_write.80000664000175000017500000001771312363426266017404 0ustar douggdougg.TH "COMPARE AND WRITE" "8" "March 2014" "sg3_utils\-1.38" SG3_UTILS .SH NAME sg_compare_and_write \- send the SCSI COMPARE AND WRITE command .SH SYNOPSIS .B sg_compare_and_write [\fI\-\-dpo\fR] [\fI\-\-fua\fR] [\fI\-\-fua_nv\fR] [\fI\-\-help\fR] \fI\-\-in=IF\fR [\fI\-\-inw=WF\fR] \fI\-\-lba=LBA\fR [\fI\-\-num=NUM\fR] [\fI\-\-quiet\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wrprotect=WP\fR] [\fI\-\-xferlen=LEN\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Send the SCSI COMPARE AND WRITE command to \fIDEVICE\fR. This utility reads a compare buffer and a write buffer from either one or two files. If the \fI\-\-inw=WF\fR option is not given then the concatenated compare and write buffers are read from the file indicated by the \fI\-\-in=IF\fR option. If the \fI\-\-inw=WF\fR option is given then the compare buffer is read from the file indicated by the \fI\-\-in=IF\fR while the write buffer is read from the file indicated by the \fI\-\-inw=WF\fR. .PP Those buffers are expected to each contain \fINUM\fR blocks of data. The compare starts at at logical block address \fILBA\fR on the \fIDEVICE\fR and if the comparison fails (i.e. the provided compare buffer does not equal at \fILBA\fR on the \fIDEVICE\fR) then the COMPARE AND WRITE command finishes with a sense key of MISCOMPARE. In this case this utility will completes and set an exit status of 14 (which happens to be the sense key value of MISCOMPARE). .PP If the comparison succeeds then the provided write buffer is written to starting at \fILBA\fR for \fINUM\fR blocks on the \fIDEVICE\fR. .PP The actual number of bytes transferred in the data\-out buffer of the COMPARE AND WRITE command may need to be given by the user with the \fI\-\-xferlen=LEN\fR option. \fILEN\fR defaults to (2 * \fINUM\fR * 512) which is 1024 for the default \fINUM\fR of 1. If the block size is other than 512 then the user will need to use \fI\-\-xferlen=LEN\fR option. If protection information is given (indicated by a value of \fIWP\fR other than 0 (the default)) then for a \fINUM\fR of 1 \fILEN\fR should be 1040 . Note that the SCSI READ CAPACITY command is not checked by this utility (e.g. to find the block size). .PP The definition of the SCSI COMPARE AND WRITE command requires that the \fIDEVICE\fR implement the compare and optional write as an uninterrupted series of actions. Depending on some other \fIDEVICE\fR settings a verify operation may occur prior to the compare. .PP When a mismatch occurs between the compare buffer and the blocks starting at \fILBA\fR read from the \fIDEVICE\fR the sense buffer containing the MISCOMPARE sense key causes several messages to be sent to stderr (including the offset of the first byte mismatch). To suppress these messages use the \fI\-\-quiet\fR option. With or without the \fI\-\-quiet\fR option the exit status will be set to 14. .PP This command is defined in SBC\-3 whose most recent revision is 36. SBC\-3 and other SCSI documents can be found at http://www.t10.org . .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-d\fR, \fB\-\-dpo\fR Set the DPO bit in the COMPARE AND WRITE CDB .TP \fB\-f\fR, \fB\-\-fua\fR Set the FUA bit in the COMPARE AND WRITE CDB .TP \fB\-F\fR, \fB\-\-fua_nv\fR Set the FUA_NV bit in the COMPARE AND WRITE CDB. This bit was removed in SBC\-3 revision 35d and its position marked as "reserved". .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR read data (binary) from file named \fIIF\fR. This will either be the combined compare and write buffers (when the \fI\-\-inw=WF\fR option is not given) or just the compare buffer (when the \fI\-\-inw=WF\fR option is given). If \fIIF\fR is '\-' then stdin (e.g. a pipe) is read. .TP \fB\-D\fR, \fB\-\-inw\fR=\fIWF\fR read data (binary) from file named \fIWF\fR. This will the write buffer that will become the second half of the data-out buffer sent to the \fIDEVICE\fR associated with the COMPARE AND WRITE command. Note that when this option is given then the \fI\-\-in=IF\fR is expected to hold the associated compare buffer. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the logical block address to start the COMPARE AND WRITE command. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'. .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM\fR where \fINUM\fR is the number of blocks, starting at \fILBA\fR, to read and compare with the verify instance. And given a match, the \fINUM\fR of blocks to write starting \fILBA\fR. The default value for \fINUM\fR is 1. .TP \fB\-q\fR, \fB\-\-quiet\fR suppress the sense buffer messages associated with a MISCOMPARE sense key that would otherwise be sent to stderr. Still set the exit status to 14 which is the sense key value indicating a MISCOMPARE. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fITO\fR where \fITO\fR is the command timeout value in seconds. The default value is 60 seconds. If \fINUM\fR is large (or zero) a WRITE SAME command may require considerably more time than 60 seconds to complete. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-wrprotect\fR=\fIWP\fR set the WRPROTECT field in the cdb to \fIWP\fR. The default value is 0 which implies no protection information is sent (along with the user data) by this utility. .TP \fB\-x\fR, \fB\-\-xferlen\fR=\fILEN\fR where \fILEN\fR is the data out buffer length in byte. It defaults to (2 * \fINUM\fR * 512) bytes. If the \fIDEVICE\fR block size is other than 512 bytes or \fIWP\fR is non-zero (implying additional protection information) then this default will be incorrect; the use must supply the correct value for \fILEN\fR .SH NOTES Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .SH EXIT STATUS The exit status of sg_compare_and_write is 0 when it is successful. If the compare step fails then the exit status is 14. For other exit status values see the EXIT STATUS section in the sg3_utils(8) man page. .PP Earlier versions of this utility set an exit status of 98 when there was a MISCOMPARE. .SH AUTHORS Written by Shahar Salzman. Maintained by Douglas Gilbert. Additions by Eric Seppanen. .SH "REPORTING BUGS" Report bugs to shahar.salzman@kaminario.com or dgilbert@interlog.com .SH COPYRIGHT Copyright \(co 2012\-2014 Kaminario Technologies LTD .br Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: .br * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. .br * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. .br * Neither the name of the nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. .br THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Kaminario Technologies LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .SH "SEE ALSO" .B sg_xcopy, sg_receive_copy_results(sg3_utils) sg3_utils-1.40/doc/sg_read.80000664000175000017500000001744612053021257014623 0ustar douggdougg.TH SG_READ "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_read \- read multiple blocks of data, optionally with SCSI READ commands .SH SYNOPSIS .B sg_read [\fIblk_sgio=\fR0|1] [\fIbpt=BPT\fR] [\fIbs=BS\fR] [\fIcdbsz=\fR6|10|12|16] \fIcount=COUNT\fR [\fIdio=\fR0|1] [\fIdpo=\fR0|1] [\fIfua=\fR0|1] \fIif=IFILE\fR [\fImmap=\fR0|1] [\fIno_dxfer=\fR0|1] [\fIodir=\fR0|1] [\fIskip=SKIP\fR] [\fItime=TI\fR] [\fIverbose=VERB\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .SH DESCRIPTION .\" Add any additional description here .PP Read data from a Linux SCSI generic (sg) device, a block device or a normal file with each read command issued to the same offset or logical block address (lba). This can be used to test (or time) disk caching, SCSI (or some other) transport throughput, and/or SCSI command overhead. .PP When the \fICOUNT\fR value is positive, then up to \fIBPT\fR blocks are read at a time, until the \fICOUNT\fR is exhausted. Each read operation starts at the same lba which, if \fISKIP\fR is not given, is the beginning of the file or device. .PP The \fICOUNT\fR value may be negative when \fIIFILE\fR is a sg device or is a block device with 'blk_sgio=1' set. Alternatively 'bpt=0' may be given. In these cases |\fICOUNT\fR| "zero block" SCSI READ commands are issued. "Zero block" means "do nothing" for SCSI READ 10, 12 and 16 byte commands (but not for the 6 byte variant). In practice "zero block" SCSI READ commands have low latency and so are one way to measure SCSI command overhead. .SH OPTIONS .TP \fBblk_sgio\fR=0 | 1 The default action of this utility is to use the Unix read() command when the \fIIFILE\fR is a block device. In lk 2.6 many block devices can handle SCSI commands issued via the SG_IO ioctl. So when this option is set the SG_IO ioctl sends SCSI READ commands to \fIIFILE\fR if it is a block device. .TP \fBbpt\fR=\fIBPT\fR where \fIBPT\fR is the maximum number of blocks each read operation fetches. Fewer blocks will be fetched when the remaining \fICOUNT\fR is less than \fIBPT\fR. The default value for \fIBPT\fR is 128. Note that each read operation starts at the same lba (as given by \fIskip=SKIP\fR or 0). If 'bpt=0' then the \fICOUNT\fR is interpreted as the number of zero block SCSI READ commands to issue. .TP \fBbs\fR=\fIBS\fR where \fIBS\fR is the size (in bytes) of each block read. This .B must be the block size of the physical device (defaults to 512) if SCSI commands are being issued to \fIIFILE\fR. .TP \fBcdbsz\fR=6 | 10 | 12 | 16 size of SCSI READ commands issued on sg device names, or block devices if 'blk_sgio=1' is given. Default is 10 byte SCSI READ cdbs. .TP \fBcount\fR=\fICOUNT\fR when \fICOUNT\fR is a positive number, read that number of blocks, typically with multiple read operations. When \fICOUNT\fR is negative then |\fICOUNT\fR| SCSI READ commands are performed requesting zero blocks to be transferred. This option is mandatory. .TP \fBdio\fR=0 | 1 default is 0 which selects indirect IO. Value of 1 attempts direct IO which, if not available, falls back to indirect IO and notes this at completion. This option is only active if \fIIFILE\fR is an sg device. If direct IO is selected and /proc/scsi/sg/allow_dio has the value of 0 then a warning is issued (and indirect IO is performed) .TP \fBdpo\fR=0 | 1 when set the disable page out (DPO) bit in SCSI READ commands is set. Otherwise the DPO bit is cleared (default). .TP \fBfua\fR=0 | 1 when set the force unit access (FUA) bit in SCSI READ commands is set. Otherwise the FUA bit is cleared (default). .TP \fBif\fR=\fIIFILE\fR read from this \fIIFILE\fR. This argument must be given. If the \fIIFILE\fR is a normal file then it must be seekable (if (\fICOUNT\fR > \fIBPT\fR) or \fIskip=SKIP\fR is given). Hence stdin is not acceptable (and giving "\-" as the \fIIFILE\fR argument is reported as an error). .TP \fBmmap\fR=0 | 1 default is 0 which selects indirect IO. Value of 1 causes memory mapped IO to be performed. Selecting both dio and mmap is an error. This option is only active if \fIIFILE\fR is an sg device. .TP \fBno_dxfer\fR=0 | 1 when set then DMA transfers from the device are made into kernel buffers but no further (i.e. there is no second copy into the user space). The default value is 0 in which case transfers are made into the user space. When neither mmap nor dio is set then data transfer are copied via kernel buffers (i.e. a double copy). Mainly for testing. .TP \fBodir\fR=0 | 1 when set opens an \fIIFILE\fR which is a block device with an additional O_DIRECT flag. The default value is 0 (i.e. don't open block devices O_DIRECT). .TP \fBskip\fR=\fISKIP\fR all read operations will start offset by \fISKIP\fR bs\-sized blocks from the start of the input file (or device). .TP \fBtime\fR=\fITI\fR When \fITI\fR is 0 (default) doesn't perform timing. When 1, times transfer and does throughput calculation, starting at the first issued command until completion. When 2, times transfer and does throughput calculation, starting at the second issued command until completion. When 3 times from third command, etc. An average number of commands (SCSI READs or Unix read()s) executed per second is also output. .TP \fBverbose\fR=\fIVERB\fR as \fIVERB\fR increases so does the amount of debug output sent to stderr. Default value is zero which yields the minimum amount of debug output. A value of 1 reports extra information that is not repetitive. .TP \fB\-\-help\fR Output the usage message then exit. .TP \fB\-\-version\fR Output the version string then exit. .SH NOTES Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP Data usually gets to the user space in a 2 stage process: first the SCSI adapter DMAs into kernel buffers and then the sg driver copies this data into user memory. This is called "indirect IO" and there is a "dio" option to select "direct IO" which will DMA directly into user memory. Due to some issues "direct IO" is disabled in the sg driver and needs a configuration change to activate it. This is typically done with "echo 1 > /proc/scsi/sg/allow_dio". An alternate way to avoid the 2 stage copy is to select memory mapped IO with 'mmap=1'. .SH SIGNALS The signal handling has been borrowed from dd: SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred; then they have their default action. SIGUSR1 causes the same information to be output yet the copy continues. All output caused by signals is sent to stderr. .SH EXAMPLES .PP Let us assume that /dev/sg0 is a disk and we wish to time the disk's cache performance. .PP sg_read if=/dev/sg0 bs=512 count=1MB mmap=1 time=2 .PP This command will continually read 128 512 byte blocks from block 0. The "128" is the default value for 'bpt' while "block 0" is chosen because the 'skip' argument was not given. This will continue until 1,000,000 blocks are read. The idea behind using 'time=2' is that the first 64 KiB read operation will involve reading the magnetic media while the remaining read operations will "hit" the disk's cache. The output of third command will look like this: .PP time from second command to end was 4.50 secs, 113.70 MB/sec .br Average number of READ commands per second was 1735.27 .br 1000000+0 records in, SCSI commands issued: 7813 .SH EXIT STATUS The exit status of sg_read is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2012 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" To time streaming media read or write time see .B sg_dd is in the sg3_utils package. The lmbench package contains .B lmdd which is also interesting. .B raw(8), dd(1) sg3_utils-1.40/doc/sg_scan.8.win320000664000175000017500000001645412371000322015564 0ustar douggdougg.TH SG_SCAN "8" "August 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_scan \- scan storage devices and map to volume names .SH SYNOPSIS .B sg_scan [\fI\-\-bus\fR] [\fI\-\-help\fR] [\fI\-\-letter=VL\fR] [\fI\-\-scsi\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] .SH DESCRIPTION .\" Add any additional description here .PP This utility scans for physical drives (a.k.a. "hard drives"), cd/dvd drives and tape drives and maps them to the corresponding volumes. There may be many, one or no corresponding volumes. There is one line output per device with identification strings to the right. Its purpose is to list the storage device names that can be used by other utilities in this package. .PP In later versions of Windows this utility may need to be "run as Administrator" for disks and other devices to be seen. If not those devices will simply not appear as calls to query them fail with access permission problems. .PP There is an optional SCSI adapter scan which may find additional storage devices other than the ones listed above. An example is a SCSI Enclosure Services (SES) device typically found in disk arrays. .PP Storage and related devices can have several device names in Windows. Probably the most common in the volume name (e.g. "D:"). There is also a "class" device name, and this utility scans for three of them: "PhysicalDrive", "CDROM" and "TAPE". is an integer starting at 0 allocated in ascending order as devices are discovered (and sometimes rediscovered). .PP Some storage devices have a SCSI lower level device name which starts with a SCSI (pseudo) adapter name of the form "SCSI:". To this is added sub\-addressing in the form of a "bus" number, a "target" identifier and a LUN (Logical Unit Number). The "bus" number is also known as a "PathId". These components are combined by the utility to make a device name of the form: "SCSI:,,". This utility allows the trailing "," to be omitted in which case a LUN of zero is assumed. This lower level device name cannot often be used directly since Windows blocks attempts to use it if a class driver has "claimed" the device. There are SCSI device types (e.g. Automation/Drive interface type) for which there is no class driver. At least two transports ("bus types" in Windows jargin): USB and IEEE 1394 do not have a "scsi" device names of this form. .PP In keeping with DOS file system conventions, the various device names can be given in upper, lower or mixed case. Since "PhysicalDrive" is tedious to write, a shortened form of "PD" is permitted by all utilities in this package. .PP A single device (e.g. a disk) can have many device names! For example: "PDO" can also be "C:", "D:" and "SCSI0:0,1,0". The two volume names reflect that the disk has two partitions on it. Disk partitions that are not recognised by Windows are not usually given a volume name. However Vista does show a volume name for a disk which has no partitions recognised by it and when selected invites the user to format it (which is rather unfriendly to other OSes). .PP The scanning logic and output of this command changed significantly in sg3_utils version 1.27 . The SCSI adapter based scanned is now an optional extra. .PP For more information see the NOTES section below. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-bus\fR show the bus type (or transport) by which the device is attached to the operating systems. Two or more transports may be involved. For example, a SATA disk may be in the external enclosure connected to the computer via USB in which case the bus type is USB. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. .TP \fB\-l\fR, \fB\-\-letter\fR=\fIVL\fR normally a device that has multiple volume names has up to four listed. If there are more than that a "+" is added after the fourth. When this option is given the \fIVL\fR argument is assumed to be a volume name (i.e. 'C' to 'Z') and if found in the scan, only that volume name appears in the output. If there are novolume names in the output then \fIVL\fR was not found. .TP \fB\-s\fR, \fB\-\-scsi\fR do a SCSI adapter based scan after the normal storage device based scan. There is a blank line between the normal scan and the SCSI adapter based scan. If this option is given twice then only the SCSI adapter based scan is done. .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. Can be used multiple times to display more of the internal data, both in normal and error processing. .TP \fB\-V\fR, \fB\-\-version\fR print out version string .SH NOTES This utility does not support Windows 95, 98 and ME (and earlier Windows operating systems). The target Windows operating systems are currently Windows 2000, 2003, XP and Vista (and their variants). .PP When the \fI\-\-scsi\fR option is given the SCSI adapter tuple is followed by a list of two or three fields. First is "claimed=0|1" indicating whether a class driver has claimed the device. The next field is "pdt=" where is the "peripheral device type" as defined in the SCSI INQUIRY command (see SPC\-4 at http://www.t10.org). The has a trailing "h" to indicate that it is hexadecimal. Sometimes a third field with the word "dubious" appears. This flags that what is supposed to be a SCSI INQUIRY command response has a badly formed "additional length" field. Thus the corresponding device is unlikely to be a native SCSI device. .PP The DOS device names given the the CreateFile() call all start with a "\\\\.\\" string. That can be given but if not will be supplied automatically. .PP Scanning devices that are hot unplugged and replugged often can be problematic, especially with the class device names. Each time a device is removed and re\-added it gets a larger class device name (e.g. "PD3" becomes "PD4" leaving "PD3" unused). This utility stops scanning class devices after it find 8 consecutive "holes". .SH EXAMPLES The following examples are from a laptop with an internal drive (SATA), a CD/DVD drive and a USB attached SATA disk. The latter disk has two volumes recognised by Windows. .PP # sg_scan .br PD0 [C] FUJITSU MHY2160BH 0000 .br PD1 [DF] WD 2500BEV External 1.05 WD\-WXE90 .br CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 .PP Now request bus types as well. BTW That is a SATA disk holding volume C: and there is a "Sata" bus type. .PP # sg_scan \-b .br PD0 [C] FUJITSU MHY2160BH 0000 .br PD1 [DF] WD 2500BEV External 1.05 WD\-WXE90 .br CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 .PP Now request a SCSI adapter scan as well. .PP # sg_scan \-b \-s .br PD0 [C] FUJITSU MHY2160BH 0000 .br PD1 [DF] WD 2500BEV External 1.05 WD\-WXE90 .br CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 .br .br SCSI0:0,0,0 claimed=1 pdt=0h FUJITSU MHY2160BH 0000 .br SCSI1:0,0,0 claimed=1 pdt=5h MATSHITA DVD/CDRW UJDA775 CB03 .PP .SH EXIT STATUS The exit status of sg_scan is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2006\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. sg3_utils-1.40/doc/sg_sanitize.80000664000175000017500000002556612410305510015532 0ustar douggdougg.TH SG_SANITIZE "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_sanitize \- remove all user data from disk with SCSI SANITIZE command .SH SYNOPSIS .B sg_sanitize [\fI\-\-ause\fR] [\fI\-\-block\fR] [\fI\-\-count=OC\fR] [\fI\-\-crypto\fR] [\fI\-\-desc\fR] [\fI\-\-early\fR] [\fI\-\-fail\fR] [\fI\-\-help\fR] [\fI\-\-invert\fR] [\fI\-\-ipl=LEN\fR] [\fI\-\-overwrite\fR] [\fI\-\-pattern=PF\fR] [\fI\-\-quick\fR] [\fI\-\-test=TE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wait\fR] [\fI\-\-zero\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility invokes the SCSI SANITIZE command. This command was first introduced in the SBC\-3 revision 27 draft. The purpose of the sanitize operation is to alter the information in the cache and on the medium of a logical unit (e.g. a disk) so that the recovery of user data is not possible. If that user data cannot be erased, or is in the process of being erased, then the sanitize operation prevents access to that user data. .PP Once a SCSI SANITIZE command has successfully started, then user data from that disk is no longer available. Even if the disk is power cycled, the sanitize operation will continue after power is re\-instated until it is complete. .PP This utility requires either the \fI\-\-block\fR, \fI\-\-crypto\fR, \fI\-\-fail\fR or \fI\-\-overwrite\fR option. With the \fI\-\-block\fR, \fI\-\-crypto\fR or \fI\-\-overwrite\fR option the user is given 15 seconds to reconsider whether they wish to erase all the data on a disk, unless the \fI\-\-quick\fR option is given in which case the sanitize operation starts immediately. The disk's INQUIRY response strings are printed out just in case the wrong \fIDEVICE\fR has been given. .PP If the \fI\-\-early\fR option is given then this utility will exit soon after starting the SANITIZE command with the IMMED bit set. The user can monitor the progress of the sanitize operation with the "sg_request \-\-num=9999 \-\-progress" which sends a REQUEST SENSE command every 30 seconds. Otherwise if the \fI\-\-wait\fR option is given then this utility will wait until the SANITIZE command completes (or fails) and that can be many hours. .PP If neither the \fI\-\-early\fR nor \fI\-\-wait\fR option is given then the SANITIZE command is started with the IMMED bit set. After that this utility sends a REQUEST SENSE command every 60 seconds until there are no more progress indications. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-A\fR, \fB\-\-ause\fR sets the AUSE bit in the cdb. AUSE is an acronym for "allow unrestricted sanitize exit". The default action is to leave the AUSE bit cleared. .TP \fB\-B\fR, \fB\-\-block\fR perform a "block erase" sanitize operation. .TP \fB\-c\fR, \fB\-\-count\fR=\fIOC\fR where \fIOC\fR is the "overwrite count" associated with the "overwrite" sanitize operation. \fIOC\fR can be a value between 1 and 31 and 1 is the default. .TP \fB\-C\fR, \fB\-\-crypto\fR perform a "cryptographic erase" sanitize operation. .TP \fB\-d\fR, \fB\-\-desc\fR sets the DESC field in the REQUEST SENSE command used for polling. By default this field is set to zero. A REQUEST SENSE polling loop is used after the SANITIZE command is issued (assuming that neither the \fI\-\-early\fR nor the \fI\-\-wait\fR option have been given) to check on the progress of this command as it can take some time. .TP \fB\-e\fR, \fB\-\-early\fR the default action of this utility is to poll the disk every 60 seconds to fetch the progress indication until the sanitize is finished. When this option is given this utility will exit "early" as soon as the SANITIZE command with the IMMED bit set to 1 has been acknowledged. This option and \fI\-\-wait\fR cannot both be given. .TP \fB\-F\fR, \fB\-\-fail\fR perform an "exit failure mode" sanitize operation. Typically requires the preceding SANITIZE command to have set the AUSE bit. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage information then exit. .TP \fB\-i\fR, \fB\-\-ipl\fR=\fILEN\fR set the initialization pattern length to \fILEN\fR bytes. By default it is set to the length of the pattern file (\fIPF\fR) or 4 if the \fI\-\-zero\fR option is given. Only active when the \fI\-\-overwrite\fR option is also given. It is the number of bytes from the \fIPF\fR file that will be used as the initialization pattern (if the \fI\-\-zero\fR option is not given). The minimum size is 1 byte and the maximum is the logical block size of the \fIDEVICE\fR (and not to exceed 65535). If \fILEN\fR exceeds the \fIPF\fR file size then the initialization pattern is padded with zeros. .TP \fB\-I\fR, \fB\-\-invert\fR set the INVERT bit in the overwrite service action parameter list. This only affects the "overwrite" sanitize operation. The default is a clear INVERT bit. When the INVERT bit is set then the initialization pattern is inverted between consecutive overwrite passes. .TP \fB\-O\fR, \fB\-\-overwrite\fR perform an "overwrite" sanitize operation. When this option is given then the \fI\-\-pattern=PF\fR or the \fI\-\-zero\fR option is required. .TP \fB\-p\fR, \fB\-\-pattern\fR=\fIPF\fR where \fIPF\fR is the filename of a file containing the initialization pattern required by an "overwrite" sanitize operation. The length of this file will be used as the length of the initialization pattern unless the \fI\-\-ipl=LEN\fR option is given. The length of the initialization pattern must be from 1 to the logical block size of the \fIDEVICE\fR. .TP \fB\-Q\fR, \fB\-\-quick\fR the default action (i.e. when the option is not given) is to give the user 15 seconds to reconsider doing a sanitize operation on the \fIDEVICE\fR. When this option is given that step (i.e. the 15 second warning period) is skipped. .TP \fB\-T\fR, \fB\-\-test\fR=\fITE\fR set the TEST field in the overwrite service action parameter list. This only affects the "overwrite" sanitize operation. The default is to place 0 in that field. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-w\fR, \fB\-\-wait\fR the default action (i.e. without this option and the \fI\-\-early\fR option) is to start the SANITIZE command with the IMMED bit set then poll for the progress indication with the REQUEST SENSE command until the sanitize operation is complete (or fails). When this option is given (and the \fI\-\-early\fR option is not given) then the SANITIZE command is started with the IMMED bit clear. For a large disk this might take hours. [A cryptographic erase operation could potentially be very quick.] .TP \fB\-z\fR, \fB\-\-zero\fR with an "overwrite" sanitize operation this option causes the initialization pattern to be zero (4 zeros are used as the initialization pattern). Cannot be used with the \fI\-\-pattern=PF\fR option. If this option is given twice (e.g. '\-zz') then 0xff is used as the initialization byte. .SH NOTES The SCSI SANITIZE command is closely related to the ATA SANITIZE command, both are relatively new with the ATA command being the first one defined. The SCSI to ATA Translation (SAT) definition for the SCSI SANITIZE command appeared in the SAT\-3 revision 4 draft. .PP When a SAT layer is used to a (S)ATA disk then for OVERWRITE the initialization pattern must be 4 bytes long. So this means either the \fI\-\-zero\fR option may be given, or a pattern file (with the \fI\-\-pattern=PF\fR option) that is 4 bytes long or set to that length with the \fI\-\-ipl=LEN\fR option. .PP The SCSI SANITIZE command is related to the SCSI FORMAT UNIT command. It is likely that a block erase sanitize operation would take a similar amount of time as a format on the same disk (e.g. 9 hours for a 2 Terabyte disk). The primary goal of a format is the configuration of the disk at the end of a format (e.g. different logical block size or protection information added). Removal of user data is only a side effect of a format. With the SCSI SANITIZE command, removal of user data is the primary goal. If a sanitize operation is interrupted (e.g. the disk is power cycled) then after power up any remaining user data will not be available and the sanitize operation will continue. When a format is interrupted (e.g. the disk is power cycled) the drafts say very little about the state of the disk. In practice some of the original user data may remain and the format may need to be restarted. .PP Finding out whether a disk (SCSI or ATA) supports SANITIZE can be a challenge. If the user really needs to find out and no other information is available then try 'sg_sanitize \-\-fail \-vvv ' and observe the sense data returned may be the safest approach. Using the \fI\-\-fail\fR variant of this utility should have no effect unless it follows an already failed sanitize operation. If the SCSI REPORT SUPPORTED OPERATION CODES command (see sg_opcodes) is supported then using it would be a better approach for finding if sanitize is supported. .SH EXAMPLES These examples use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP As a precaution if this utility is called with no options then apart from printing a usage message, nothing happens: .PP sg_sanitize /dev/sdm .PP To do a "block erase" sanitize the \fI\-\-block\fR option is required. The user will be given a 15 second period to reconsider, the SCSI SANITIZE command will be started with the IMMED bit set, then this utility will poll for a progress indication with a REQUEST SENSE command until the sanitize operation is finished: .PP sg_sanitize \-\-block /dev/sdm .PP To start a "block erase" sanitize and return from this utility once it is started (but not yet completed) use the \fI\-\-early\fR option: .PP sg_sanitize \-\-block \-\-early /dev/sdm .PP If the 15 second reconsideration time is not required add the \fI\-\-quick\fR option: .PP sg_sanitize \-\-block \-\-quick \-\-early /dev/sdm .PP To do an "overwrite" sanitize a pattern file may be given: .PP sg_sanitize \-\-overwrite \-\-pattern=rand.img /dev/sdm .PP If the length of that "rand.img" is 512 bytes (a typically logical block size) then to use only the first 17 bytes (repeatedly) in the "overwrite" sanitize operation: .PP sg_sanitize \-\-overwrite \-\-pattern=rand.img \-\-ipl=17 /dev/sdm .PP To overwrite with zeros use: sg_sanitize \-\-overwrite \-\-zero /dev/sdm .SH EXIT STATUS The exit status of sg_sanitize is 0 when it is successful. Otherwise see the sg3_utils(8) man page. Unless the \fI\-\-wait\fR option is given, the exit status may not reflect the success of otherwise of the format. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2011\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_requests(8), sg_format(8) sg3_utils-1.40/doc/sg_sat_phy_event.80000664000175000017500000001177312430315266016562 0ustar douggdougg.TH SG_SAT_PHY_EVENT "8" "November 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_sat_phy_event \- use ATA READ LOG EXT via a SAT pass\-through to fetch SATA phy event counters .SH SYNOPSIS .B sg_sat_phy_event [\fI\-\-ck_cond\fR] [\fI\-\-extend\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-ignore\fR] [\fI\-\-len=\fR{16|12}] [\fI\-\-raw\fR] [\fI\-\-reset\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends an ATA READ LOG EXT with the log page ("address") set to 11h to \fIDEVICE\fR and outputs the response. Log page 11h is defined in the SATA 2.5 standard and contains phy event counters. Rather than send this command directly to the \fIDEVICE\fR, are sent via a SCSI transport which is assumed to contain a SCSI to ATA Translation (SAT) Layer (SATL). The SATL may be in an operating system driver, in host bus adapter firmware or in some external enclosure. .PP The SAT standard (SAT ANSI INCITS 431\-2007, prior draft: sat\-r09.pdf at www.t10.org) defines two SCSI "ATA PASS\-THROUGH" commands: one using a 16 byte "cdb" and the other with a 12 byte cdb. This utility defaults to using the 16 byte cdb variant. SAT\-2 is also a standard: SAT\-2 ANSI INCITS 465\-2010 and the draft prior to that is sat2r09.pdf . The SAT-3 project has started and the most recent draft is sat3r01.pdf . .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-ck_cond\fR sets the CK_COND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set the SATL should yield a sense buffer containing a ATA Result descriptor irrespective of whether the command succeeded or failed. When clear the SATL should only yield a sense buffer containing a ATA Result descriptor if the command failed. .TP \fB\-e\fR, \fB\-\-extend\fR sets the EXTEND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set a 48 bit LBA command is sent to the device. This option has no effect when \fI\-\-len=12\fR. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-H\fR, \fB\-\-hex\fR outputs the ATA READ LOG EXT response in hex. The default action (i.e. without any '\-H' options) is to output the response in hex, grouped in 16 bit words (i.e. the ATA standard's preference). When given once, the response is output in ASCII hex bytes (i.e. the SCSI standard's preference). When given twice (i.e. '\-HH') the output is in hex, grouped in 16 bit words, the same as the default but without a header. .TP \fB\-i\fR, \fB\-\-ignore\fR usually the phy counter identifier names are decoded. When this option is given, the numeric value of the identifier is output, the vendor flag, the data length (in bytes) and the corresponding value. .TP \fB\-l\fR, \fB\-\-len\fR={16|12} this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands. The argument can either be 16 or 12. The default is 16. The larger cdb size is needed for 48 bit LBA addressing of ATA devices. On the other hand some SCSI transports cannot convey SCSI commands longer than 12 bytes. .TP \fB\-r\fR, \fB\-\-raw\fR output the ATA READ LOG EXT response in binary. The output should be piped to a file or another utility when this option is used. The binary is sent to stdout, and errors are sent to stderr. .TP \fB\-R\fR, \fB\-\-reset\fR reset the counters after the current values are returned, decoded and displayed. .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string .SH NOTES The SCSI ATA PASS\-THROUGH (12) command's opcode is 0xa1 and it clashes with the MMC set's BLANK command used by cd/dvd writers. So a SATL in front of an ATAPI device that uses MMC (i.e. has peripheral device type 5) probably should treat opcode 0xa1 as a BLANK command and send it through to the cd/dvd drive. The ATA PASS\-THROUGH (16) command's opcode (0x85) does not clash with anything so it is a better choice. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda" will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char" device names may be used as well (e.g. "/dev/st0m"). Prior to lk 2.6.29 USB mass storage limited sense data to 18 bytes which made the \fB\-\-ck_cond\fR option yield strange (truncated) results. .SH EXIT STATUS The exit status of sg_sat_identify is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_sat_identify,sg_sat_read_gplog(sg3_utils), .B smp_rep_phy_err_log(smp_utils), sdparm(sdparm), hdparm(hdparm) sg3_utils-1.40/doc/sg_start.80000664000175000017500000002732212053021257015037 0ustar douggdougg.TH SG_START "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_start \- send SCSI START STOP UNIT command: start, stop, load or eject medium .SH SYNOPSIS .B sg_start [\fI0\fR] [\fI1\fR] [\fI\-\-eject\fR] [\fI\-\-help\fR] [\fI\-\-fl=FL\fR] [\fI\-\-immed\fR] [\fI\-\-load\fR] [\fI\-\-loej\fR] [\fI\-\-mod=PC_MOD\fR] [\fI\-\-noflush\fR] [\fI\-\-pc=PC\fR] [\fI\-\-readonly\fR] [\fI\-\-start\fR] [\fI\-\-stop\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_start [\fI\-\-eject\fR] [\fI\-\-fl=FL\fR] [\fI\-i\fR] [\fI\-\-imm=0|1\fR] [\fI\-\-load\fR] [\fI\-\-loej\fR] [\fI\-\-mod=PC_MOD\fR] [\fI\-\-noflush\fR] [\fI\-\-pc=PC\fR] [\fI\-r\fR] [\fI\-\-start\fR] [\fI\-\-stop\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI0|1\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP sg_start sends a SCSI START STOP UNIT command to the \fIDEVICE\fR with the selected options. The most used options are \fI\-\-stop\fR to spin down a disk and \fI\-\-start\fR to spin up a disk. Using \fI\-\-start\fR on a disk that is already spinning is harmless. There is also finer grain control with "power condition": active, idle or standby. This is set with the \fI\-\-pc=PC\fR option. In some contexts the "stop" state can be considered an additional power condition. .PP Devices that contain removable media such as cd/dvds can use the \fI\-\-loej\fR option to load the medium when used in conjunction with \fI\-\-start\fR (i.e. load medium then spin up). Alternatively \fI\-\-loej\fR may be used to eject the medium when used in conjunction with \fI\-\-stop\fR (i.e. spin down then eject medium). More simply, the loading or ejecting of a removable medium can be requested with the \fI\-\-load\fR or \fI\-\-eject\fR' option. .PP If no option or argument is given then a \fI\-\-start\fR is assumed; as the utility's name suggests. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB0\fR same action as \fI\-\-stop\fR. .TP \fB1\fR same action as \fI\-\-start\fR. .TP \fB\-e\fR, \fB\-\-eject\fR stop the medium and eject it from the drive. Only appropriate for a device with removable medium. Might be ignored (prevented), see below. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-f\fR, \fB\-\-fl\fR=\fIFL\fR sets the format layer number for the disc to "jump" to (defined in MMC\-5). Values of \fIFL\fR can be 0 to 3. When this option is chosen, the FL, LoEj and Start bits are set in the cdb as required by MMC\-5; thus the user does not need to set the \fI\-\-start\fR and/or \fI\-\-load\fR options. .TP \fB\-i\fR, \fB\-\-immed\fR sets the IMM bit on the START STOP UNIT command so this utility will return immediately and not wait for the media to complete the requested action. The default is to wait until the media to complete the requested action before returning. .TP \fB\-l\fR, \fB\-\-load\fR load the medium in the drive and start it. Only appropriate for a removable medium. .TP \fB\-L\fR, \fB\-\-loej\fR sets the LOEJ bit on the START STOP UNIT command. This loads the media when the unit is started or eject it when the unit is stopped (i.e. works in conjunction with START bit in cdb). This option is ignored if 'pc > 0'. Default is off (i.e. don't attempt to load or eject media). If a start/start indication is not given (i.e. neither \fI\-\-start\fR nor \fI\-\-stop\fR) and this option is given then a load and start action is assumed. .TP \fB\-m\fR, \fB\-\-mod\fR=\fIPC_MOD\fR where \fIPC_MOD\fR is the 'power condition modifier' value. 0 to 15 (inclusive) are valid and 0 is the default. This 'power condition modifier' field in the cdb was added after sbc3r13. .TP \fB\-n\fR, \fB\-\-noflush\fR do not perform a flush to media (e.g. like SYNCHRONIZE CACHE does) before a variant of this utility that limits access to the media. Using the \fB\-\-stop\fR option is an example of something that limits access to the media. This 'noflush' field in the cdb was added after sbc3r13. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-pc\fR=\fIPC\fR where \fIPC\fR is the 'power conditions' value. 0 to 15 (inclusive) are valid. Default value is 0. When '\-\-pc=0' then \fB\-\-eject\fR, \fB\-\-load\fR, \fB\-\-loej\fR, \fB\-\-start\fR and \fB\-\-stop\fR are active. Some common values are 1 for the "active" power condition (SBC); 2 for the idle power condition; 3 for the standby power condition; 5 for sleep power condition (MMC); 7 for LU_CONTROL (SBC), 0xa (decimal 10) for FORCE_IDLE_0 (SBC) and 0xb (decimal 11) for FORCE_STANDBY_0 (SBC). See recent SBC\-3, MMC\-5 and SAS drafts at www.t10.org for more information. .TP \fB\-r\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR in read\-only mode. Maybe required in Linux to stop a nuisance spin\-up if the \fIDEVICE\fR is an ATA disk. The nuisance spin\-up may occur at the end of this command negating the effect of the \fI\-\-stop\fR option. .TP \fB\-s\fR, \fB\-\-start\fR start (spin\-up) the \fIDEVICE\fR. This sets the START bit in the cdb. Using this option on an already started device is harmless. In the absence of other options, this option defaults (i.e. set the START cdb bit). .TP \fB\-S\fR, \fB\-\-stop\fR stop (spin\-down) the \fIDEVICE\fR. This clears the START bit in the cdb. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH NOTES To avoid confusion, only one of \fI0\fR, \fI1\fR \fI\-\-eject\fR, \fI\-\-load\fR, \fI\-\-start\fR and \fI\-\-stop\fR should be given. .PP There is an associated "power condition" mode page (0x1a) in which timer values can be set for transitioning to either idle or standby state after a period of inactivity. The sdparm utility can be used to view the power condition mode page and if required change it. If a \fIDEVICE\fR is in either idle or standby power condition state then a REQUEST SENSE command (see the sg_requests utility) should yield a sense key of "no sense" and an additional sense code of "Low power condition on" on recent SCSI devices. .PP Ejection of removable media (e.g. 'sg_start \-\-eject /dev/hdd' where the \fIDEVICE\fR is an ATAPI cd/dvd drive) may be prevented by a prior SCSI PREVENT ALLOW MEDIUM REMOVAL command (see sg_prevent). In this case this utility should fail with an error generated by the device: illegal request / medium removal prevented. This can be overridden using sg_prevent or, for example, 'sdparm \-\-command=unlock /dev/hdd'. .PP The SCSI TEST UNIT READY command can be used to find out whether a \fIDEVICE\fR is ready to transfer data. If rotating media is stopped or still coming up to speed, then the TEST UNIT READY command will yield a "not ready" sense key and an more informative additional sense code. See the sg_turs utility. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_start 0 /dev/sda" will work in the 2.6 series kernels. .PP In the Linux 2.6 series, especially with ATA disks, using this utility to stop (spin down) a disk may not be sufficient and other mechanisms will start the disk again some time later. The user might additionally mark the disk as "offline" with 'echo offline > /sys/block/sda/device/state' where sda is the block name of the disk. To restart the disk "offline" can be replaced with "running". Note that once the 'state' is set to offline, no SCSI commands can be sent to the device until it is set back to running. Also stopping a disk via a pass\-through interface (e.g. /dev/sg1 or /dev/bsg/1:0:0:0) may reduce unwanted side effects (such as restarting it again when this utility completes). .SH EXIT STATUS The exit status of sg_start is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .PP Note that the action of \fI\-\-loej\fR is slightly different in the older interface: when neither \fI\-\-start\fR nor \fI\-\-stop\fR (nor proxies for them) are given, \fI\-\-loej\fR performs an eject operation. In the same situation the newer interface will perform a load operation. .PP Earlier versions of sg_start had a '\-s' option to perform a SYNCHRONIZE CACHE command before the START STOP UNIT command was issued. According to recent SBC\-2 drafts this is done implicitly if required. Hence the '\-s' option has been dropped. .PP All options, other than '\-v' and '\-V', can be given with a single "\-". For example: "sg_start \-stop /dev/sda" and "sg_start \-\-stop /dev/sda" are equivalent. The single "\-" form is for backward compatibility. .TP \fB0\fR stop (spin\-down) \fIDEVICE\fR. .TP \fB1\fR start (spin\-up) \fIDEVICE\fR. .TP \fB\-\-eject\fR stop the medium and eject it from the drive. .TP \fB\-\-fl\fR=\fIFL\fR sets the format layer number for the disc to "jump" to (defined in MMC\-5). .TP \fB\-i\fR sets the IMM bit on the START STOP UNIT command so this utility will return immediately and not wait for the media to spin down. Same effect as '\-\-imm=1'. The default action (without this option or a '\-\-imm=1' option) is to wait until the media spins down before returning. .TP \fB\-\-imm\fR=\fI0|1\fR when the immediate bit is 1 then this utility returns immediately after the \fIDEVICE\fR has received the command. When this option is 0 (the default) then the utility returns once the command has completed its action (i.e. it waits until the device is started or stopped). .TP \fB\-\-load\fR load the medium in the drive and start it. .TP \fB\-\-loej\fR sets the LOEJ bit in the START STOP UNIT cdb. When a "start" operation is indicated, then a load and start is performed. When a "stop" operation is indicated, then a stop and eject is performed. When neither a "start" or "stop" operation is indicated does a stop and eject. [Note that the last action differs from the new interface in which the option of this name defaults to load and start.] .TP \fB\-N\fR switch to the newer style options. .TP \fB\-\-mod\fR=\fIPC_MOD\fR where \fIPC_MOD\fR is the 'power condition modifier' value. 0 to 15 (inclusive) are valid and 0 is the default. This field was added after sbc3r13. .TP \fB\-\-noflush\fR do not perform a flush to media (e.g. like SYNCHRONIZE CACHE does) before a variant of this utility that limits access to the media. Using the \fB\-\-stop\fR option is an example of something that limits access to the media. This field was added after sbc3r13. .TP \fB\-\-pc\fR=\fIPC\fR where \fIPC\fR is the 'power condition' value (in hex). 0 to f (inclusive) are valid. Default value is 0. .TP \fB\-r\fR see the \fI\-\-readonly\fR option above. May be useful for ATA disks. .TP \fB\-\-start\fR start (spin\-up) \fIDEVICE\fR. .TP \fB\-\-stop\fR stop (spin\-down) \fIDEVICE\fR. Same meaning as "0" argument. .TP \fB\-v\fR verbose: outputs SCSI command in hex to console before with executing it. '\-vv' and '\-vvv' are also accepted yielding greater verbosity. .TP \fB\-V\fR print out version string then exit. .SH AUTHOR Written by K. Garloff and D. Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2002\-2012 Kurt Garloff, Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_prevent(sg3_utils), sg_requests(sg3_utils), sg_turs(sg3_utils) .B sdparm(sdparm) sg3_utils-1.40/doc/sg_prevent.80000664000175000017500000000504012120516066015360 0ustar douggdougg.TH SG_PREVENT "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_prevent \- send SCSI PREVENT ALLOW MEDIUM REMOVAL command .SH SYNOPSIS .B sg_prevent [\fI\-\-allow\fR] [\fI\-\-help\fR] [\fI\-\-prevent=PC\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends a SCSI PREVENT ALLOW MEDIUM REMOVAL command to \fIDEVICE\fR. The default action of this utility is to prevent the removing or ejecting of the medium from a drive. This is done by ignoring the SCSI START STOP UNIT command (see sg_start) and ignoring the eject button on the drive when the user presses it. Drives that hold removable disks, tape cartridges or cd/dvd media typically implement this command. The definition of the "prevent" codes for this command differ between disks and tapes (covered by SBC\-3 and SSC\-3) and cd/dvd drives (covered by MMC\-5). The "prevent codes" described here are from MMC\-5. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-allow\fR allow medium removal. This is equivalent to setting to '\-\-prevent=2'. Cannot be used with \fI\-\-prevent=PC\fR option (i.e. either use no options (hence prevent removal), this option or \fI\-\-prevent=PC\fR). .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-p\fR, \fB\-\-prevent\fR=\fIPC\fR where \fIPC\fR is a prevent code value. Defined values are: 0 allows removal, 1 prevents removal (default), 2 allows persistent removal while 3 prevents persistent removal. "Persistent" in this context means that the initiator (port) that successfully uses code 3 blocks other initiators (ports) from allowing removal. A "persistent prevent" state can be cleared by the owner allowing persistent removal (code 2) or a power cycle (or anything that resets the device (LU)) or some special commands (e.g. various service actions of Persistent Reserve Out, see SPC\-3). .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH EXIT STATUS The exit status of sg_prevent is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_start(sg3_utils), sg_persist(sg3_utils) sg3_utils-1.40/doc/sg_decode_sense.80000664000175000017500000001301712400160337016315 0ustar douggdougg.TH SG_DECODE_SENSE "8" "August 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_decode_sense \- decode SCSI sense data .SH SYNOPSIS .B sg_decode_sense [\fI\-\-binary=FN\fR] [\fI\-\-file=FN\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-nospace\fR] [\fI\-\-status=SS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-write=WFN\fR] [H1 H2 H3 ...] .SH DESCRIPTION .\" Add any additional description here This utility takes SCSI sense data in binary or as a sequence of ASCII hexadecimal bytes and decodes it. The primary reference for the decoding is SPC\-3 ANSI INCITS 408-2005 and the most recent draft SPC\-4 revision 37 which can be found at http://www.t10.org and other locations on the internet. .PP SCSI sense data is often found in kernel log files as a result of something going wrong but may just be informative. It is often shown as a sequence of hexadecimal bytes, starting with 70, 71, 72, 73, f0 or f1. Sense data could be up to 252 bytes long but typically is much shorter than that, 18 bytes long is often seen and is usually associated with the older "fixed" format sense data. .PP The sense data can be provided on the command line or in a file. If given on the command line the sense data should be a sequence of hexadecimal bytes separated by space. Alternatively a file can be given with the contents in binary or ASCII hexadecimal bytes. The latter form can contain several lines each with none, one or more ASCII hexadecimal bytes separated by space (comma or tab). The hash symbol may appear and it and the rest of the line is ignored making it useful for comments. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-binary\fR=\fIFN\fR the sense data is read in binary from a file called \fIFN\fR. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR this option is used in conjunction with \fI\-\-write=WFN\fR in order to change the output written to \fIWFN\fR to lines of ASCII hex bytes suitable for a C language compiler. Each line contains up to 16 bytes (e.g. a line starting with "0x3b,0x07,0x00,0xff"). .TP \fB\-f\fR, \fB\-\-file\fR=\fIFN\fR the sense data is read in ASCII hexadecimal from a file called \fIFN\fR. The sense data should appear as a sequence of bytes separated by space, comma, tab or newline. Everything from and including a hash symbol to the end of that line is ignored. If \fI\-\-nospace\fR is set then no separator is required between the ASCII hexadecimal digits in \fIFN\fR with bytes decoded from pairs of ASCII hexadecimal digits. .TP \fB\-n\fR, \fB\-\-nospace\fR expect ASCII hexadecimal to be a string of hexadecimal digits with no spaces between them. Bytes are decoded by taking two hexadecimal digits at a time, so an even number of digits is expected. The string of hexadecimal digits may be on the command line (replacing "H1 H2 H3") or spread across multiple lines the \fIFN\fR given to \fI\-\-file=\fR. On the command line, spaces (or other whitespace characters) between sequences of hexadecimal digits are ignored; the maximum command line hex string is 1023 characters long. .TP \fB\-s\fR, \fB\-\-status\fR=\fISS\fR where \fISS\fR is a SCSI status byte value, given in hexadecimal. The SCSI status byte is related to but distinct from sense data. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-write\fR=\fIWFN\fR writes the sense data out to a file called \fIWFN\fR. If necessary \fIWFN\fR is created. If \fIWFN\fR exists then it is truncated prior to writing the sense data to it. If the \fI\-\-hex\fR option is also given then ASCII hex is written to \fIWFN\fR (see the \fI\-\-hex\fR option description); otherwise binary is written to \fIWFN\fR. This option is a convenience and may be helpful in converting the ASCII hexadecimal representation of sense data (or anything else) into the equivalent binary or a compilable ASCII hex form. .SH NOTES Unlike most utilities in this package, this utility does not access a SCSI device (logical unit). This utility accesses a library associated with this package. Amongst other things the library decodes SCSI sense data. .PP T10 defined SCSI command names given a CDB can be decoded using the sg_raw utility with the '\-vvv' option. .SH EXAMPLES Sense data is often printed out in kernel logs and sometimes on the command line when verbose or debug flags are given. It will be at least 8 bytes long, often 18 bytes long but may be longer. A sense data string might look like this: .PP f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 .br 00 00 .PP Cut and paste it after the sg_decode_sense command: .PP sg_decode_sense f0 00 03 00 00 12 34 0a 00 00 00 00 11 00 00 00 00 00 .PP and for this sense data the output should look like this: .PP Fixed format, current; Sense key: Medium Error .br Additional sense: Unrecovered read error .br Info fld=0x1234 [4660] .PP For a medium error the Info field is the logical block address (LBA) of the lowest numbered block that the associated SCSI command was not able to read (verify or write). .SH EXIT STATUS The exit status of sg_decode_sense is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2010\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_requests,sg_raw(sg3_utils) sg3_utils-1.40/doc/sg_modes.80000664000175000017500000002611312333156560015015 0ustar douggdougg.TH SG_MODES "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_modes \- reads mode pages with SCSI MODE SENSE command .SH SYNOPSIS .B sg_modes [\fI\-\-all\fR] [\fI\-\-control=PC\fR] [\fI\-\-dbd\fR] [\fI\-\-dbout\fR] [\fI\-\-examine\fR] [\fI\-\-flexible\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-list\fR] [\fI\-\-llbaa\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG[,SPG]\fR] [\fI\-\-raw\fR] [\fI\-R\fR] [\fI\-\-six\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIDEVICE\fR] .PP .B sg_modes [\fI\-6\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-c=PC\fR] [\fI\-d\fR] [\fI\-D\fR] [\fI\-e\fR] [\fI\-f\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-l\fR] [\fI\-L\fR] [\fI\-m=LEN\fR] [\fI\-p=PG[,SPG]\fR] [\fI\-r\fR] [\fI\-subp=SPG\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] [\fIDEVICE\fR] .SH DESCRIPTION .\" Add any additional description here .PP This utility sends a MODE SENSE SCSI command to the \fIDEVICE\fR and outputs the response. There is a 6 byte and 10 byte (cdb) variant of the MODE SENSE command, this utility defaults to the 10 byte variant. .PP This utility decodes mode page headers and block descriptors but outputs the contents of each mode page in hex. It also has no facility to change the mode page contents or block descriptor data. Mode page contents are decoded and can be changed by the .B sdparm utility. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .PP If no page is given (and \fI\-\-list\fR is not selected) then \fI\-\-all\fR is assumed. The \fI\-\-all\fR option requests all mode pages (but not subpages) in a single response. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-all\fR output all the mode pages reported by the \fIDEVICE\fR. This is what the page code 63 (0x3f) is defined to do. When used once, mode subpages are not fetched. When used twice (e.g. '\-aa'), all mode pages and subpages are requested which is equivalent to '\-\-page=63,255'. .TP \fB\-c\fR, \fB\-\-control\fR=\fIPC\fR \fIPC\fR is the page control value. Up to four different versions of each page are held by the device: .br \fB0\fR : current values (i.e. those active at present) .br \fB1\fR : changeable values .br \fB2\fR : default values (i.e. the manufacturer's settings) .br \fB3\fR : saved values .br The changeable values are bit masks showing which fields could be changed with a MODE SELECT. The saved values will be re\-instated the next time the device is power cycled or reset. If this option is not given then current values [0] are assumed. .TP \fB\-d\fR, \fB\-\-dbd\fR disable block descriptors. By default, block descriptors (usually one (for disks) or none) are returned in a MODE SENSE response. This option sets the "disable block descriptors" (DBD) bit in the cdb which instructs the device not to return any block descriptors in its response. Older devices may not support this setting and may return an "illegal request" sense key; alternatively they may ignore it. Oddly the Reduced Block Command set (RBC) requires this bit set. .TP \fB\-D\fR, \fB\-\-dbout\fR disable outputting block descriptors. Irrespective of whether block descriptors are present in the response or not, they are not output. .TP \fB\-e\fR, \fB\-\-examine\fR examine each mode page in the range 0 through to 62 (inclusive). If some response is given then print out the mode page name or number (in hex) if the name is not known. .TP \fB\-f\fR, \fB\-\-flexible\fR Some devices, bridges and/or drivers attempt crude translations between MODE SENSE 6 and 10 byte commands without correcting the response. This will cause the response to be mis\-interpreted (usually with an error saying the response is malformed). With this option, the length of the response is checked, and if it looks wrong, the response is then decoded as if the other mode sense (cdb length) was sent. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR The default action is to decode known mode page numbers (and subpage numbers) into text. When this option is used once, the response is output in hexadecimal. When this option is used twice, mode page numbers and page control values are output in hex. .TP \fB\-l\fR, \fB\-\-list\fR lists all common page and subpage codes and their names that are found in the command set that matches the peripheral type of the given \fIDEVICE\fR. If no \fIDEVICE\fR and no \fI\-\-page=PG\fR is given then the common page and subpage codes and their names are listed for SBC (e.g. a disk). If no \fIDEVICE\fR is given and a \fI\-\-page=PG\fR is given then the common page and subpage codes and their names are listed for the command set whose peripheral device type matches the value given to \fIPG\fR. For example 'sg_mode \-\-list \-\-page=1' lists the command mode pages and subpages for tape devices. Additionally if a sub_page_code is given then it is interpreted as a transport identifier and command transport specific mode page codes and their names are listed following the main mode page list. Other options are ignored. .TP \fB\-L\fR, \fB\-\-llbaa\fR set the Long LBA Accepted (LLBAA) bit in the MODE SENSE (10) cdb. This bit is not defined in the MODE SENSE (6) cdb so setting the '\-L' and '\-\-six' options is reported as an error. When set the \fIDEVICE\fR may respond with 16 byte block descriptors as indicated by the 'LongLBA' field in the response. In most cases setting this option is not needed. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR The \fILEN\fR argument is the maximum response length in bytes. It is the 'allocation length' field in the cdb. When not given (or \fILEN\fR is zero) then the allocation length field is set to 4096 for MODE SENSE (10) or 252 for MODE SENSE (6). The \fILEN\fR argument must be non\-negative and no greater than 65535 for MODE SENSE (10) and not greater than 255 for MODE SENSE (6). .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR page code to fetch. The \fIPG\fR is assumed to be a decimal value unless prefixed by '0x' or has a trailing 'h'. It should be a value between 0 and 63 (inclusive). When not given and a default is required then a value of 63 (0x3f), which fetches all mode pages, is used. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG,SPG\fR page code and subpage code values to fetch. Both arguments are assumed to be decimal unless flagged as hexadecimal. The page code should be between 0 and 63 inclusive. The subpage code should be between 0 and 255 inclusive. The default value for the subpage code is 0. .TP \fB\-r\fR, \fB\-\-raw\fR output the response in binary to stdout. Error messages and warnings, if any, are sent to stderr. When this option is used twice (e.g. '\-rr') then has the same action as '\-R' .TP \fB\-R\fR output the selected mode page to stdout a byte per line. Each line contains two hexadecimal digits (e.g. "3e"). Useful as input (after editing) to the sg_wr_mode(8) utility. .TP \fB\-6\fR, \fB\-\-six\fR by default this utility sends a 10 byte MODE SENSE command to the \fIDEVICE\fR. However some SCSI devices only support 6 byte MODE SENSE commands (e.g. SCSI\-2 tape drives). This parameter forces the use of 6 byte MODE SENSE commands. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH NOTES If the normal sg_modes utility fails with "illegal command operation code" then try the '\-\-six' (or '\-6') option. .PP This utility performs a SCSI INQUIRY command to determine the peripheral type of the device (e.g. 0 \-> Direct Access Device (disk)) prior to sending a MODE SENSE command. This helps in decoding the block descriptor and mode pages. .PP This utility opens \fIDEVICE\fR with a read\-only flag (e.g. in Unix with the O_RDONLY flag). .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_modes \-a /dev/sda" will work in the 2.6 series kernels. .SH EXIT STATUS The exit status of sg_modes is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-6\fR by default this utility sends a 10 byte MODE SENSE command to the \fIDEVICE\fR. This parameter forces the use of 6 byte MODE SENSE commands. See \fI\-\-six\fR in the main description. .TP \fB\-a\fR see \fI\-\-all\fR in the main description. .TP \fB\-A\fR output all the mode pages and subpages supported by the \fIDEVICE\fR. Same as '\-\-all \-\-all' in the new syntax. .TP \fB\-c\fR=\fIPC\fR \fIPC\fR is the page control value. See \fB\-\-control\fR=\fIPC\fR in the main description. .TP \fB\-d\fR see \fB\-\-dbd\fR in the main description. .TP \fB\-D\fR see \fB\-\-dbout\fR in the main description. .TP \fB\-e\fR see \fB\-\-examine\fR in the main description. .TP \fB\-f\fR see \fB\-\-flexible\fR in the main description. .TP \fB\-h\fR The default action is to decode known mode page numbers (and subpage numbers) into text. With this option mode page numbers (and subpage numbers) are output in hexadecimal. .TP \fB\-H\fR same action as the '\-h' option. .TP \fB\-l\fR see \fB\-\-list\fR in the main description. .TP \fB\-L\fR see \fB\-\-llbaa\fR in the main description. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-m\fR=\fILEN\fR see \fB\-\-maxlen\fR=\fILEN\fR in the main description. .TP \fB\-p\fR=\fIPG\fR \fIPG\fR is page code to fetch. Should be a hexadecimal number between 0 and 3f inclusive (0 to 63 decimal). The default value when required is 3f (fetch all mode pages). .TP \fB\-p\fR=\fIPG,SPG\fR page code and subpage code values to fetch. The page code should be a hexadecimal number between 0 and 3f inclusive. The subpage code should be a hexadecimal number between 0 and ff inclusive. The default value for the subpage code is 0. .TP \fB\-r\fR output the selected mode page to stdout a byte per line. Each line contains two hexadecimal digits (e.g. "3e"). Useful as input (after editing) to the sg_wr_mode(8) utility. .TP \fB\-subp\fR=\fISPG\fR sub page code to fetch. Should be a hexadecimal number between 0 and 0xff inclusive. The default value is 0. .TP \fB\-v\fR increase verbosity of output. .TP \fB\-V\fR print out version string then exit. .TP \fB\-?\fR output usage message then exit. Ignore all other parameters. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sdparm(8), sg_wr_mode(8), sginfo(8), .B sgmode(scsirastools), scsiinfo(net), scu(net), .B seatools(seagate) .PP All these utilities offer some facility to change mode page (or block descriptor) parameters. sg3_utils-1.40/doc/sg_ses.80000664000175000017500000007173012424673250014506 0ustar douggdougg.TH SG_SES "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_ses \- access a SCSI Enclosure Services (SES) device .SH SYNOPSIS .B sg_ses [\fI\-\-byte1=B1\fR] [\fI\-\-clear=STR\fR] [\fI\-\-control\fR] [\fI\-\-data=H,H...\fR] [\fI\-\-descriptor=DN\fR] [\fI\-\-dev\-slot\-num=SN\fR] [\fI\-\-eiioe=A_F\fR] [\fI\-\-enumerate\fR] [\fI\-\-filter\fR] [\fI\-\-get=STR\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-index=IIA\fR | \fI\-\-index=TIA,II\fR] [\fI\-\-inner\-hex\fR] [\fI\-\-join\fR] [\fI\-\-list\fR] [\fI\-\-mask\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-nickname=SEN\fR] [\fI\-\-nickid=SEID\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-sas\-addr=SA\fR] [\fI\-\-set=STR\fR] [\fI\-\-status\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-warn\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Fetches management information from a SCSI Enclosure Service (SES) device. This utility can also modify the state of a SES device. The \fIDEVICE\fR should be a SES device which may be a dedicated enclosure services processor in which case an INQUIRY response's Peripheral Device Type is 13 [0xd]. Alternatively it may be attached to another type of SCSI device (e.g. a disk) in which case the EncServ bit is set in its INQUIRY response. .PP If no options are given (i.e. only the \fIDEVICE\fR argument is given) then the names of all diagnostic pages supported are listed. Most, but not necessarily all, of the named diagnostic pages are defined in the SES standards and drafts. The most recent reference for this utility is the draft SCSI Enclosure Services 3 document T10/2149\-D Revision 7 at http://www.t10.org . Existing standards for SES and SES\-2 are ANSI INCITS 305\-1998 and ANSI INCITS 448\-2008 respectively. .PP Changing the state of an enclosure (e.g. requesting the "ident" (locate) LED to flash on a disk carrier in an array) is typically done using a read\-modify\-write cycle. See the section on CHANGING STATE below. .PP There is a web page discussing this utility at http://sg.danny.cz/sg/sg_ses.html . Support for downloading microcode to a SES device has been placed in a separate utility called sg_ses_microcode. .PP In the following sections "page" refers to a diagnostic page, either fetched with a SCSI RECEIVE DIAGNOSTIC RESULTS command or sent to the \fIDEVICE\fR with a SCSI SEND DIAGNOSTIC command. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-b\fR, \fB\-\-byte1\fR=\fIB1\fR some modifiable pages may need byte 1 (i.e. the second byte) set. In the Enclosure Control page, byte 1 contains the INFO, NON\-CRIT, CRIT and UNRECOV bits. In the Subenclosure String Out, Subenclosure Nickname Control and Download Microcode Control pages, byte 1 is the Subenclosure identifier. Active when the \fI\-\-control\fR and \fI\-\-data=H,H...\fR options are used and the default value is 0. If the \fI\-\-clear=STR\fR or \fI\-\-set=STR\fR option is used then the value read from byte 1 is written back to byte 1. \fIB1\fR is in decimal unless it is prefixed by '0x' or '0X' (or has a trailing 'h' or 'H'). .TP \fB\-C\fR, \fB\-\-clear\fR=\fISTR\fR Used to clear an element field in the Enclosure Control or Threshold Out page. Must be used together with an indexing option to specify which element is to be changed. The Enclosure Control page is assumed if the \fI\-\-page=PG\fR option is not given. See the STR FORMAT section below. .TP \fB\-c\fR, \fB\-\-control\fR will send control information to the \fIDEVICE\fR via a SCSI SEND DIAGNOSTIC command. Cannot give both this option and \fI\-\-status\fR. The Enclosure Control, String Out, Threshold Out, Array Control (obsolete in SES\-2), Subenclosure String Out, Subenclosure Nickname Control and Download Microcode pages can be set currently. This option is assumed if either the \fI\-\-clear=STR\fR or \fI\-\-set=STR\fR option is given. .TP \fB\-d\fR, \fB\-\-data\fR=\fIH,H...\fR permits a string of comma separated (ASCII) hex bytes to be specified (limit 1024). A (single) space separated string of hex bytes is also allowed but the list needs to be in quotes. This option allows the parameters to a control page to be specified. The string given should not include the first 4 bytes (i.e. page code and length). .TP \fB\-d\fR, \fB\-\-data\fR=\- reads one or more data strings from stdin, limit 2048 bytes. stdin may provide ASCII hex as a comma separated list (i.e. as with the \fI\-\-data=H,H...\fR option). Additionally spaces, tabs and line feeds are permitted as separators from stdin . Stops reading stdin when an EOF is detected. .TP \fB\-d\fR, \fB\-\-data\fR=@\fIFN\fR reads one or more data strings from the file called \fIFN\fR, limit 2048 bytes. Otherwise this option is the same as the previous item that reads from stdin. .TP \fB\-D\fR, \fB\-\-descriptor\fR=\fIDN\fR where \fIDN\fR is a descriptor name (string) as found in the Element Descriptor page. This is a medium level indexing alternative to the low level \fI\-\-index=\fR options. If the descriptor name contains a space then \fIDN\fR needs to be surrounded by quotes (single or double) or the space escaped (e.g. preceded by a backslash). See the DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS section below. .TP \fB\-x\fR, \fB\-\-dev\-slot\-num\fR=\fISN\fR, \fB\-\-dsn\fR=\fISN\fR where \fISN\fR is a device slot number found in the Additional Element Status page. Only entries for FCP and SAS devices (with EIP=1) have device slot numbers. \fISN\fR must be a number in the range 0 to 255 (inclusive). 255 is used to indicate there is no corresponding device slot. This is a medium level indexing alternative to the low level \fI\-\-index=\fR options. See the DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS section below. .TP \fB\-E\fR, \fB\-\-eiioe\fR=\fIA_F\fR \fIA_F\fR is either the string 'auto' or 'force'. There was some fuzziness in the interpretation of the 'element index' field in the Additional Element Status page between SES\-2 and SES\-3. The EIIOE bit was introduced to resolve the problem but not all enclosures have caught up. Using '\-\-eiioe=force' will decode this page as if the EIIOE bit is set. Using '\-\-eiioe=auto' will decode this page as if the EIIOE bit is set if the first element index in this page is 1 (in other words a heuristic to guess whether the EIIOE bit should be set or not). .br If the enclosure sets the EIIOE bit then this option has no effect. It is recommended that HP JBOD users set --eiioe=auto . .TP \fB\-e\fR, \fB\-\-enumerate\fR enumerate all known page names and SES elements when this option is given once. If \fI\-\-enumerate\fR is given twice, then the recognised acronyms for the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR and \fI\-\-set=STR\fR options are listed. The utility exits after listing this information (so most other options and \fIDEVICE\fR are ignored). .TP \fB\-f\fR, \fB\-\-filter\fR cuts down on the amount of output from the Enclosure Status page and the Additional Element Status page. When this option is given, any line which has all its binary flags cleared (i.e. 0) is filtered out (i.e. ignored). If a line has some other value on it (e.g. a temperature) then it is output. When this option is used twice only elements associated with the "status=ok" field (in the Enclosure status page) are output. The \fI\-\-filter\fR option is useful for reducing the amount of output generated by the \fI\-\-join\fR option. .TP \fB\-G\fR, \fB\-\-get\fR=\fISTR\fR Used to read a field in a status element. Must be used together with a an indexing option to specify which element is to be read. By default the Enclosure Status page is read, the only other pages that can be read are the Threshold In and Additional Element Status pages. If a value is found it is output in decimal to stdout (by default) or in hexadecimal preceded by "0x" if the \fI\-\-hex\fR option is also given. See the STR FORMAT section below. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. Since there is a lot of information, it is split into two pages. The most important is shown on the first page. Use this option twice (e.g. '\-hh') to output the second page. Note: the \fI\-\-enumerate\fR option might also be viewed as a help or usage type option. And like this option it has a "given twice" form: '\-ee'. .TP \fB\-H\fR, \fB\-\-hex\fR If the \fI\-\-get=STR\fR option is given then output the value found (if any) in hexadecimal, with a leading "0x". Otherwise output the response in hexadecimal. Ignored when all elements from several pages are being accessed. .TP \fB\-I\fR, \fB\-\-index\fR=\fIIIA\fR where \fIIIA\fR is either an individual index (II) or an Element type abbreviation (A). See the INDEXES section below. If the \fI\-\-page=PG\fR option is not given then the Enclosure Status (or Control) page is assumed. May be used with the \fI\-\-join\fR option or one of the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR or \fI\-\-set=STR\fR options. To enumerate the available Element type abbreviations use the \fI\-\-enumerate\fR option. .TP \fB\-I\fR, \fB\-\-index\fR=\fITIA,II\fR where \fITIA,II\fR is an type header index (TI) or Element type abbreviation (A) followed by an individual index (II). See the INDEXES section below. If the \fI\-\-page=PG\fR option is not given then the Enclosure Status (or Control) page is assumed. May be used with the \fI\-\-join\fR option or one of the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR or \fI\-\-set=STR\fR options. To enumerate the available Element type abbreviations use the \fI\-\-enumerate\fR option. .TP \fB\-i\fR, \fB\-\-inner\-hex\fR the outer levels of a status page are decoded and printed out but the innermost level (e.g. the Element Status Descriptor) is output in hex. Also active with the Additional Element Status and Threshold In pages. Can be used with an indexing option and/or \fI\-\-join\fR options. .TP \fB\-j\fR, \fB\-\-join\fR group elements from the Element Descriptor, Enclosure Status and Additional Element Status pages. If this option is given twice then elements from the Threshold In page are also grouped. The order is dictated by the Configuration page. All elements are output unless one of the indexing options is given, in which case only the matching element and its associated fields are output. The \fI\-\-filter\fR option can be added to reduce the amount of output generated by this option. See the INDEXES and DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS sections below. .TP \fB\-l\fR, \fB\-\-list\fR This option is equivalent to \fI\-\-enumerate\fR. See that option. .TP \fB\-M\fR, \fB\-\-mask\fR When modifying elements, the default action is a read (status element), mask, modify (based on \fI\-\-clear=STR\fR or \fI\-\-set=STR\fR) then write back as the control element. The mask step is new in sg_ses version 1.98 and is based on what is allowable (and in the same location) in draft SES\-3 revision 6. Those masks may evolve, as they have in the past. This option re\-instates the previous logic which was to ignore the mask step. The default action (i.e. without this option) is to perform the mask step in the read\-mask\-modify\-write sequence. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR \fILEN\fR is placed in the ALLOCATION LENGTH field of the SCSI RECEIVE DIAGNOSTIC RESULTS commands sent by the utility. It represents the maximum size of data the SES device can return (in bytes). It cannot exceed 65535 and defaults to 65532 (bytes). Some systems may not permit such large sizes hence the need for this option. If \fILEN\fR is set to 0 then the default size is used. .TP \fB\-n\fR, \fB\-\-nickname\fR=\fISEN\fR where \fISEN\fR is the new Subenclosure Nickname. Only the first 32 characters (bytes) of \fISEN\fR are used, if more are given they are ignored. See the SETTING SUBENCLOSURE NICKNAME section below. .TP \fB\-N\fR, \fB\-\-nickid\fR=\fISEID\fR where \fISEID\fR is the Subenclosure identifier that the new Nickname (\fISEN\fR) will be applied to. So \fISEID\fR must be an existing Subenclosure identifier. The default value is 0 which is the main enclosure. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR where \fIPG\fR is a page abbreviation or code (a number). If \fIPG\fR starts with a digit it is assumed to be in decimal unless prefixed by 0x for hex. Valid range is 0 to 255 (0x0 to 0xff) inclusive. Default is page 'sdp' which is page_code 0 (i.e. "Supported Diagnostic Pages") if no other options are given. .TP \fB\-r\fR, \fB\-\-raw\fR outputs the chosen status page in ASCII hex in a format suitable for a later invocation using the \fI\-\-data=\fR option. A page less its first 4 bytes (page code and length) is output. When used twice (e.g. \fI\-rr\fR) the full page contents is output in binary to stdout. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-A\fR, \fB\-\-sas\-addr\fR=\fISA\fR this is an indexing method for SAS end devices (e.g. SAS disks). The utility will try to find the element or slot in the Additional Element Status page whose SAS address matches \fISA\fR. For a SAS disk or tape that SAS address is its target port identifier for the port connected to that element or slot. Most SAS disks and tapes have two such target ports, usually numbered consecutively. .br SATA devices in a SAS enclosure often receive "manufactured" target port identifiers from a SAS expander; typically will a SAS address close to but different from the SAS address of the expander itself. Note that this manufactured target port identifier is different from a SATA disk's WWN. .br \fISA\fR is a hex number that is up to 8 digits long. It may have a leading '0x' or '0X' or a trailing 'h' or 'H'. This option is a medium level indexing alternative to the low level \fI\-\-index=\fR options. See the DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS section below. .TP \fB\-S\fR, \fB\-\-set\fR=\fISTR\fR Used to set an element field in the Enclosure Control or Threshold Out page. Must be used together with an indexing option to specify which element is to be changed. The Enclosure Control page is assumed if the \fI\-\-page=PG\fR option is not given. See the STR FORMAT section below. .TP \fB\-s\fR, \fB\-\-status\fR will fetch page from the \fIDEVICE\fR via a SCSI RECEIVE DIAGNOSTIC RESULTS command. In the absence of other options that imply modifying a page (e.g. \fI\-\-control\fR or \fI\-\-set=STR\fR) then \fI\-\-status\fR is assumed. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-w\fR, \fB\-\-warn\fR warn about certain irregularities with warnings sent to stderr. The join is a complex operation that relies on information from several pages to be synchronized. The quality of SES devices vary and to be fair, the descriptions from T10 drafts and standards have been tweaked several times (see the EIIOE bit) in order to clear up confusion. .SH INDEXES An enclosure can have information about its disk and tape drives plus other supporting components like power supplies spread across several pages. Addressing a specific element (overall or individual) within a page is complicated. This section describes low level indexing (i.e. choosing a single element (or a group of related elements) from a large number of elements). If available, the medium level indexing described in the following section (DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS) might be simpler to use. .PP The Configuration page is key to low level indexing: it contains a list of "type headers", each of which contains an Element type (e.g. Array Device Slot), a Subenclosure identifier (0 for the primary enclosure) and a "Number of possible elements". Corresponding to each type header, the Enclosure Status page has one "overall" element plus "Number of possible elements" individual elements all of which have the given Element type. For some Element types the "Number of possible elements" will be 0 so the Enclosure Status page has only one "overall" element corresponding to that type header. The Element Descriptor page and the Threshold (In and Out) pages follow the same pattern as the Enclosure Status page. .PP The Additional Element Status page is a bit more complicated. It has entries for "Number of possible elements" of certain Element types. It does not have entries corresponding to the "overall" elements. To make the correspondence a little clearer each descriptor in this page optionally contains an "Element Index Present" (EIP) indicator. If EIP is set then each element's "Element Index" field refers to the position of the corresponding element in the Enclosure Status page. .PP Addressing a single overall element or a single individual element is done with two indexes: TI and II. Both are origin 0. TI=0 corresponds to the first type header entry which must be a Device Slot or Array Device Slot Element type (according to the SES\-2 standard). To address the corresponding overall instance, II is set to \-1, otherwise II can be set to the individual instance index. As an alternative to the type header index (TI), an Element type abbreviation (A) optionally followed by a number (e.g. "ps" refers to the first Power Supply Element type; "ps1" refers to the second) can be given. .PP One of two command lines variants can be used to specify indexes: \fI\-\-index=TIA,II\fR where \fITIA\fR is either an type header index (TI) or an Element type abbreviation (A) (e.g. "ps" or "ps1"). \fIII\fR is either an individual index or "\-1" to specify the overall element. The second variant is \fI\-\-index=IIA\fR where \fIIIA\fR is either an individual index (II) or an Element type abbreviation (A). When \fIIIA\fR is an individual index then the option is equivalent to \fI\-\-index=0,II\fR. When \fIIIA\fR is an Element type abbreviation then the option is equivalent to \fI\-\-index=A,\-1\fR. .PP To cope with vendor specific Element types (which should be in the range 128 to 255) the Element type can be given as a number with a leading underscore. For example these are equivalent: \fI\-\-index=arr\fR and \fI\-\-index=_23\fR since the Array Device Slot Element type value is 23. Also \fI\-\-index=ps1\fR and \fI\-\-index=_2_1\fR are equivalent. .PP Another example: if the first type header in the Configuration page has has Array Device Slot Element type then \fI\-\-index=0,\-1\fR is equivalent to \fI\-\-index=arr\fR. Also \fI\-\-index=arr,3\fR is equivalent to \fI\-\-index=3\fR. .PP The \fI\-\-index=\fR options can be used to reduce the amount of output (e.g. only showing the element associated with the second 12 volt power supply). They may also be used together with with the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR and \fI\-\-set=STR\fR options which are described in the STR section below. .SH DESCRIPTOR NAME, DEVICE SLOT NUMBER AND SAS ADDRESS The three options: \fI\-\-descriptor=DN\fR, \fI\-\-dev\-slot\-num=SN\fR and \fI\-\-sas\-addr=SA\fR allow medium level indexing, as an alternative to the low level \fI\-\-index=\fR options. Only one of the three options can be used in an invocation. Each of the three options implicitly set the \fI\-\-join\fR option since they need either the Element Descriptor page or the Additional Element Status page as well as the pages needed by the \fI\-\-index=\fR option. .PP These medium level indexing options need support from the SES device and that support is optional. For example the \fI\-\-descriptor=DN\fR needs the Element Descriptor page provided by the SES device however that is optional. Also the provided descriptor names need to be useful, and having descriptor names which are all "0" is not very useful. Also some elements (e.g. overall elements) may not have descriptor names. .PP These medium level indexing options can be used to reduce the amount of output (e.g. only showing the elements related to device slot number 3). They may also be used together with with the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR and \fI\-\-set=STR\fR options which are described in the following section. Note that even if a field can be set (e.g. "do not remove" (dnr)) and that field can be read back with \fI\-\-get=STR\fR confirming that change, the disk array may still ignore it (e.g. because it does not have the mechanism to lock the disk drawer). .SH STR FORMAT The \fISTR\fR operands of the \fI\-\-clear=STR\fR, \fI\-\-get=STR\fR and \fI\-\-set=STR\fR options all have the same structure. There are two forms: .br [=] .br :[:][=] .PP The is one of a list of common fields (e.g. "ident" and "fault") that the utility converts internally into the second form. The is usually in the range 0 to 3, the must be in the range 0 to 7 and the must be in the range 1 to 64 (default 1). The number of bits are read in the left to right sense of the element tables shown in the various SES draft documents. For example the 8 bits of byte 2 would be represented as 2:7:8 with the most significant bit being 2:7 and the least significant bit being 2:0 . .PP The is optional but is ignored if provided to \fI\-\-get=STR\fR. For \fI\-\-set=STR\fR the default is 1 while for \fI\-\-clear=STR\fR the default value is 0 . is assumed to be decimal, hexadecimal values can be given in the normal fashion. .PP The supported list of s can be viewed by using the \fI\-\-enumerate\fR option twice (or "\-ee"). .SH CHANGING STATE This utility has various techniques for changing the state of a SES device. As noted above this is typically a read\-modify\-write type operation. Most modifiable pages have a "status" (or "in") page that can be read, and a corresponding "control" (or "out") page that can be written back to change the state of the enclosure. .PP The lower level technique provided by this utility involves outputting a "status" page in hex with \fI\-\-raw\fR. Then a text editor can be used to edit the hex (note: to change an Enclosure Control descriptor the SELECT bit needs to be set). Next the control page data can fed back with the \fI\-\-data=H,H...\fR option together with the \fI\-\-control\fR option; the \fI\-\-byte1=B1\fR option may need to be given as well. .PP Changes to the Enclosure Control page (and the Threshold Out page) can be done at a higher level. This involves choosing a page (the default in this case is the Enclosure Control page). Next choose an individual or overall element index (or name it with its Element Descriptor string). Then give the element's name (e.g. "ident" for RQST IDENT) or its position within that element (e.g. in an Array Device Slot Control element RQST IDENT is byte 2, bit 1 and 1 bit long ("2:1:1")). Finally a value can be given, if not the value for \fI\-\-set=STR\fR defaults to 1 and for \fI\-\-clear=STR\fR defaults to 0. .SH SETTING SUBENCLOSURE NICKNAME The format of the Subenclosure Nickname control page is different from its corresponding status page. The status page reports all Subenclosure Nicknames (and Subenclosure identifier 0 is the main enclosure) while the control page allows only one of them to be changed. Therefore using the \fB\-\-data\fR option technique to change a Subenclosure nickname is difficult (but still possible). .PP To simplify changing a Subenclosure nickname the \fI\-\-nickname=SEN\fR and \fI\-\-nickid=SEID\fR options have been added. If the \fISEN\fR string contains spaces or other punctuation, it should be quoted: surrounded by single or double quotes (or the offending characters escaped). If the \fI\-\-nickid=SEID\fR is not given then a Subenclosure identifier of 0 is assumed. As a guard the \fI\-\-control\fR option must also be given. If the \fI\-\-page=PG\fR option is not given then \fI\-\-page=snic\fR is assumed. .PP When \fI\-\-nickname=SEN\fR is given then the Subenclosure Nickname Status page is read to obtain the Generation Code field. That Generation Code together with no more than 32 bytes from the Nickname (\fISEN\fR) and the Subenclosure Identifier (\fISEID\fR) are written to the Subenclosure Nickname Control page. .PP There is an example of changing a nickname in the EXAMPLES section below. .SH NOTES This utility can be used to fetch arbitrary (i.e. non SES) diagnostic pages (using the SCSI READ DIAGNOSTIC command). To this end the \fI\-\-page=PG\fR and \fI\-\-hex\fR options would be appropriate. Arbitrary diagnostic pages can be sent to a device with the sg_senddiag utility. .PP The most troublesome part of the join operation is associating Additional Element Status descriptors correctly. At least one SES device vendor has misinterpreted the SES\-2 standard with its "element index" field. The code in this utility interprets the "element index" field as per the SES\-2 standard and if that yields an inappropriate Element type, adjusts its indexing to follow that vendor's misinterpretation. .PP In draft SES\-3 revision 5 the "Door Lock" element name was changed to the "Door" (and an OPEN field was added to the status element). As a consequence the former 'dl' element type abbreviation has been changed to 'do'. .PP There is a related command set called SAF\-TE (SCSI attached fault\-tolerant enclosure) for enclosure (including RAID) status and control. SCSI devices that support SAF\-TE report "Processor" peripheral device type (0x3) in their INQUIRY response. See the sg_safte utility in this package or safte\-monitor on the Internet. .SH EXAMPLES Examples can also be found at http://sg.danny.cz/sg/sg_ses.html .PP The following examples use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP To view the supported pages: .PP sg_ses /dev/bsg/6:0:2:0 .PP To view the Configuration Diagnostic page: .PP sg_ses \-\-page=cf /dev/bsg/6:0:2:0 .PP To view the Enclosure Status page: .PP sg_ses \-\-page=es /dev/bsg/6:0:2:0 .PP To get the (attached) SAS address of that device (which is held in the Additional Element Sense page (page 10)) printed on hex: .PP sg_ses \-p aes \-D ArrayDevice07 \-G at_sas_addr \-H /dev/sg3 .PP To collate the information in the Enclosure Status, Element Descriptor and Additional Element Status pages the \fI\-\-join\fR option can be used: .PP sg_ses \-\-join /dev/sg3 .PP This will produce a lot of output. To filter out lines that don't contain much information add the \fI\-\-filter\fR option: .PP sg_ses \-\-join \-\-filter /dev/sg3 .PP Fields in the various elements of the Enclosure Control and Threshold pages can be changed with the \fI\-\-clear=STR\fR and \fI\-\-set=STR\fR options. [All modifiable pages can be changed with the \fI\-\-raw\fR and \fI\-\-data=H,H...\fR options.] The following example looks at making the "ident" LED (also called "locate") flash on "ArrayDevice07" which is a disk (or more precisely the carrier drawer the disk is in): .PP sg_ses \-\-index=7 \-\-set=2:1:1 /dev/sg3 .PP If the Element Descriptor diagnostic page shows that "ArrayDevice07" is the descriptor name associated with element index 7 then this invocation is equivalent to the previous one: .PP sg_ses \-\-descriptor=ArrayDevice07 \-\-set=2:1:1 /dev/sg3 .PP Further the byte 2, bit 1 (for 1 bit) field in the Array Device Slot Control element is RQST IDENT for asking a disk carrier to flash a LED so it can be located. In this case "ident" (or "locate") is accepted as an acronym for that field: .PP sg_ses \-\-descriptor=ArrayDevice07 \-\-set=ident /dev/sg3 .PP To stop that LED flashing: .PP sg_ses \-\-dev\-slot\-num=7 \-\-clear=ident /dev/sg3 .PP The above assumes the descriptor name 'ArrayDevice07' corresponds to device slot number 7. .PP Now for an example of a more general but lower level technique for changing a modifiable diagnostic page. The String (In and Out) diagnostics page is relatively simple (compared with the Enclosure Status/Control page). However the use of this lower level technique is awkward involving three steps: read, modify then write. First check the current String (In) page contents: .PP sg_ses \-\-page=str /dev/bsg/6:0:2:0 .PP Now the "read" step. The following command will send the contents of the String page (from byte 4 onwards) to stdout. The output will be in ASCII hex with pairs of hex digits representing a byte, 16 pairs per line, space separated. The redirection puts stdout in a file called "t": .PP sg_ses \-\-page=str \-\-raw /dev/bsg/6:0:2:0 > t .PP Then with the aid of the SES\-3 document (in revision 3: section 6.1.6) use your favourite editor to change t. The changes can be sent to the device with: .PP sg_ses \-\-page=str \-\-control \-\-data=\- /dev/bsg/6:0:2:0 < t .PP If the above is successful, the String page should have been changed. To check try: .PP sg_ses \-\-page=str /dev/bsg/6:0:2:0 .PP To change the nickname on the main enclosure: .PP sg_ses \-\-nickname='1st enclosure' \-\-control /dev/bsg/6:0:2:0 .SH EXIT STATUS The exit status of sg_ses is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_safte, sg_senddiag, sg_ses_microcode, sg3_utils (sg3_utils); .B safte\-monitor (Internet) sg3_utils-1.40/doc/sg_stpg.80000664000175000017500000001263212271755144014670 0ustar douggdougg.TH SG_STPG "8" "January 2014" "sg3_utils\-1.38" SG3_UTILS .SH NAME sg_stpg \- send SCSI SET TARGET PORT GROUPS command .SH SYNOPSIS .B sg_stpg [\fI\-\-active\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-offline\fR] [\fI\-\-optimized\fR] [\fI\-\-raw\fR] [\fI\-\-standby\fR] [\fI\-\-state=S,S...\fR] [\fI\-\-tp=P,P...\fR] [\fI\-\-unavailable\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI SET TARGET PORT GROUPS command to \fIDEVICE\fR. This utility has different modes depending on whether the \fI\-\-tp=\fR option is given. .PP If \fI\-\-tp=\fR is given then the SET TARGET PORT GROUPS command parameter block is built with a descriptor for each element in the list given to \fI\-\-tp=\fR. The corresponding asymmetric access state value is either taken from the \fI\-\-state=\fR list or, if that is not given, from one of the explicit state options (e.g. \fI\-\-unavailable\fR), used repeatedly if required. .PP If \fI\-\-tp=\fR is not given then a sequence of SCSI commands are sent to the \fIDEVICE\fR leading up to the SET TARGET PORT GROUPS command. First an INQUIRY is sent to fetch the device identification VPD page to find the (primary) target port group associated with \fIDEVICE\fR. Then a REPORT TARGET PORT GROUPS command is issued to find the current state and whether a transition to the requested state is supported. If so the SET TARGET PORT GROUPS command is sent. .PP Target port group access is described in SPC\-4 found at www.t10.org in sections 5.8 and 5.16 (in rev 36e dated 2012/8/24). The SET TARGET PORT GROUPS command is also described in section 6.45 of that document. .PP .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-a\fR, \fB\-\-active\fR set active/non\-optimized state. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response to the REPORT TARGET PORT GROUPS command in hex then exit. .TP \fB\-O\fR, \fB\-l\fR, \fB\-\-offline\fR set offline state. This is the appropriate state to set a target port to prior to removing the device. Note that a relative target port identifier should be given with this state (rather than a target port group identifier that all other states take). .TP \fB\-o\fR, \fB\-\-optimized\fR set active/optimized state. If no other state options or \fI\-\-tp=\fR option are given then active/optimized is the default state. .TP \fB\-r\fR, \fB\-\-raw\fR output response to the REPORT TARGET PORT GROUPS command in binary to stdout then exit. .TP \fB\-s\fR, \fB\-\-standby\fR set standby state. Port group shall accept those commands listed for "unavailable" state plus LOG SELECT/SENSE, MODE SELECT/SENSE, RECEIVE DIAGNOSTIC RESULTS, SEND DIAGNOSTIC, PERSISTENT RESERVE IN/OUT commands. .TP \fB\-S\fR, \fB\-\-state\fR=\fIS,S...\fR specifies a comma separated list (one element of more) of states. Either a number or an abbreviation can be given. A number is assumed to be a decimal number unless it is prefixed by "0x" or has a trailing "h" in which case a hexadecimal value is assumed. Only the values 0, 1, 2, 3 or 14 are accepted. The accepted abbreviations are "an", "ao", "o", "s" or "u"; which represent active/non\-optimized(1), active/optimized(0), offline(14), standby(2) or unavailable(3) respectively. .TP \fB\-t\fR, \fB\-\-tp\fR=\fIP,P...\fR specifies a comma separated list (one element of more). Each elements is either a target port group identifier (when the corresponding state is other than "offline") or a relative target port identifier (when the corresponding state is "offline"). Each element is assumed to be a decimal number unless it is prefixed by "0x" or has a trailing "h" in which case a hexadecimal value is assumed. .TP \fB\-u\fR, \fB\-\-unavailable\fR set unavailable state. Port group shall only accept INQUIRY, REPORT LUNS, REPORT/SET TARGET PORT GROUPS, REQUEST SENSE and READ/WRITE BUFFER commands. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES The SET TARGET PORT GROUPS command should be supported whenever the TPGS value in a standard INQUIRY response is 2 or 3. [View with sg_inq utility.] .PP Notice that the offline state is termed as a "secondary target port asymmetric access state" and takes a relative target port identifier (i.e. acts on a single target port). All the other states are termed as "primary target port asymmetric access states" and each takes a target port group identifier (i.e. acts on one or more target ports). .PP When \fI\-\-tp=\fR is given then the same number of elements should be given to the \fI\-\-state=\fR option. If more than one list element is given to \fI\-\-tp=\fR and an equal number of elements is _not_ given to the \fI\-\-state=\fR option, then if only one state is specified then it is repeated. .SH EXIT STATUS The exit status of sg_stpg is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2007\-2014 Hannes Reinecke, Christophe Varoqui and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_rtpg (sg3_utils) sg3_utils-1.40/doc/sg_read_buffer.80000664000175000017500000001015212333156560016146 0ustar douggdougg.TH SG_READ_BUFFER "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_read_buffer \- send SCSI READ BUFFER command .SH SYNOPSIS .B sg_read_buffer [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id=ID\fR] [\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends a SCSI READ BUFFER command to the \fIDEVICE\fR, and if there is a response either decodes it, prints it in hexadecimal or sends it in binary to stdout. If a response is received for a "descriptor" mode then, in the absence of \fI\-\-hex\fR and \fI\-\-raw\fR, it is decoded. Response for non\-descriptor modes are output in hexadecimal unless the \fI\-\-raw\fR option is given. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. If used multiple times also prints the mode names and their acronyms. .TP \fB\-H\fR, \fB\-\-hex\fR output the response in hexadecimal. When given twice the response is output in hex with the corresponding representation in ASCII to the right of each line. .TP \fB\-i\fR, \fB\-\-id\fR=\fIID\fR this option sets the buffer id field in the cdb. \fIID\fR is a value between 0 (default) and 255 inclusive. .TP \fB\-l\fR, \fB\-\-length\fR=\fILEN\fR where \fILEN\fR is the length, in bytes, that is placed in the "allocation length" field in the cdb. The default value is 4 (bytes). The device may respond with less bytes. .TP \fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR this option sets the mode field in the cdb. \fIMO\fR is a value between 0 (default) and 31 inclusive. Alternatively an abbreviation can be given. See the MODES section below. To list the available mode abbreviations use an invalid one (e.g. '\-\-mode=xxx'). As an example, to fetch the read buffer descriptor give '\-\-mode=desc' . .TP \fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR this option sets the buffer offset field in the cdb. \fIOFF\fR is a value between 0 (default) and 2**24\-1 . It is a byte offset. .TP \fB\-r\fR, \fB\-\-raw\fR if a response is received then it is sent in binary to stdout. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH MODES Following is a list of READ BUFFER command settings for the MODE field. First is an acronym accepted by the \fIMO\fR argument of this utility. Following the acronym in square brackets are the corresponding decimal and hex values that may also be given for \fIMO\fR. The following are listed in numerical order. .TP hd [0, 0x0] Combined header and data (obsolete in SPC\-4). .TP vendor [1, 0x1] Vendor specific. .TP data [2, 0x2] Data. .TP desc [3, 0x3] Descriptor: yields 4 bytes that contain an offset boundary field (1 byte) and buffer capacity (3 bytes). .TP echo [10, 0xa] Read data from echo buffer (was called "Echo buffer" in SPC\-3). .TP echo_desc [11, 0xb] Echo buffer descriptor: yields 4 bytes of which the last (lowest) 13 bits represent the echo buffer capacity. The maximum echo buffer size is 4096 bytes. .TP en_ex [26, 0x1a] Enable expander communications protocol and Echo buffer. Made obsolete in SPC\-4. .TP err_hist [28, 0x1c] Error history. Introduced in SPC\-4. .SH NOTES All numbers given with options are assumed to be decimal. Alternatively numerical values can be given in hexadecimal preceded by either "0x" or "0X" (or has a trailing "h" or "H"). .SH EXIT STATUS The exit status of sg_read_buffer is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Luben Tuikov and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2014 Luben Tuikov and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_write_buffer(sg3_utils) sg3_utils-1.40/doc/sg_rbuf.80000664000175000017500000001562611715321645014654 0ustar douggdougg.TH SG_RBUF "8" "January 2007" "sg3_utils\-1.23" SG3_UTILS .SH NAME sg_rbuf \- reads data using SCSI READ BUFFER command .SH SYNOPSIS .B sg_rbuf [\fI\-\-buffer=EACH\fR] [\fI\-\-dio\fR] [\fI\-\-help\fR] [\fI\-\-mmap\fR] [\fI\-\-quick\fR] [\fI\-\-size=OVERALL\fR] [\fI\-\-test\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_rbuf [\fI\-b=EACH_KIB\fR] [\fI\-d\fR] [\fI\-m\fR] [\fI\-q\fR] [\fI\-s=OVERALL_MIB\fR] [\fI\-t\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This command reads data with the SCSI READ BUFFER command and then discards it. Typically the data being read is from a disk's memory cache. It is assumed that the data is sourced quickly (although this is not guaranteed by the SCSI standards) so that it is faster than reading data from the media. This command is designed for timing transfer speeds across a SCSI transport. .PP To fetch the data with a SCSI READ BUFFER command and optionally decode it see the sg_read_buffer utility. There is also a sg_write_buffer utility useful for downloading firmware amongst other things. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-buffer\fR=\fIEACH\fR where \fIEACH\fR is the number of bytes to be transferred by each READ BUFFER command. The default is the actual available buffer size returned by the READ BUFFER (descriptor) command. The maximum is the same as the default, hence this argument can only be used to reduce the size of each transfer to less than the device's actual available buffer size. .TP \fB\-d\fR, \fB\-\-dio\fR use direct IO if available. This option is only available if the \fIDEVICE\fR is a sg driver device node (e.g. /dev/sg1). In this case the sg driver will attempt to configure the DMA from the SCSI adapter to transfer directly into user memory. This will eliminate the copy via kernel buffers. If not available then this will be reported and indirect IO will be done instead. .TP \fB\-h\fR, \fB\-\-help\fR print usage message then exit. .TP \fB\-m\fR, \fB\-\-mmap\fR use memory mapped IO if available. This option is only available if the \fIDEVICE\fR is a sg driver device node (e.g. /dev/sg1). In this case the sg driver will attempt to configure the DMA from the SCSI adapter to transfer directly into user memory. This will eliminate the copy via kernel buffers. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-q\fR, \fB\-\-quick\fR only transfer the data into kernel buffers (typically by DMA from the SCSI adapter card) and do not move it into the user space. This option is only available if the \fIDEVICE\fR is a sg driver device node (e.g. /dev/sg1). .TP \fB\-s\fR, \fB\-\-size\fR=\fIOVERALL\fR where \fIOVERALL\fR is the size of total transfer in bytes. The default is 200 MiB (200*1024*1024 bytes). The actual number of bytes transferred may be slightly less than requested since all transfers are the same size (and an integer division is involved rounding towards zero). .TP \fB\-t\fR, \fB\-\-time\fR times the bulk data transfer component of this command. The elapsed time is printed out plus a MB/sec calculation. In this case "MB" is 1,000,000 bytes. The gettimeofday() system call is used internally for the time calculation. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH NOTES This command is typically used on modern SCSI disks which have a RAM cache in their drive electronics. If no IO to the magnetic media, or slower devices like flash RAM, is involved then the disk may be able to source data fast enough to saturate the bandwidth of the SCSI transport. The bottleneck may then be the DMA element in the HBA, the Linux drivers or the host machine's hardware (e.g. speed of RAM). .PP Various numeric arguments (e.g. \fIOVERALL\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .SH EXAMPLES .PP On the test system /dev/sg0 corresponds to a fast disk on a U2W SCSI bus (max 80 MB/sec). The disk specifications state that its cache is 4 MB. .br $ time ./sg_rbuf /dev/sg0 .br READ BUFFER reports: buffer capacity=3434944, .br offset boundary=6 .br Read 200 MiB (actual 199 MiB, 209531584 bytes), .br buffer size=3354 KiB .br real 0m5.072s, user 0m0.000s, sys 0m2.280s .PP So that is approximately 40 MB/sec at 40 % utilization. Now with the addition of the "\-q" option this throughput improves and the utilization drops to 0%. .br $ time ./sg_rbuf \-q /dev/sg0 .br READ BUFFER reports: buffer capacity=3434944, .br offset boundary=6 .br Read 200 MiB (actual 199 MiB, 209531584 bytes), .br buffer size=3354 KiB .br real 0m2.784s, user 0m0.000s, sys 0m0.000s .SH EXIT STATUS The exit status of sg_rbuf is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-b\fR=\fIEACH_KIB\fR where \fIEACH_KIB\fR is the number of Kilobytes (i.e. 1024 byte units) to be transferred by each READ BUFFER command. Similar to the \fI\-\-buffer=EACH\fR option in the main description but the units are different. .TP \fB\-d\fR use direct IO if available. Equivalent to the \fI\-\-dio\fR option in the main description. .TP \fB\-m\fR use memory mapped IO if available. Equivalent to the \fI\-\-mmap\fR option in the main description. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-q\fR only transfer the data into kernel buffers (typically by DMA from the SCSI adapter card) and do not move it into the user space. Equivalent to the \fI\-\-quick\fR option in the main description. .TP \fB\-s\fR=\fIOVERALL_MIB\fR where \fIOVERALL_MIB\fR is the size of total transfer in Megabytes (1048576 bytes). Similar to the \fI\-\-size=OVERALL\fR option in the main description but the units are different. .TP \fB\-t\fR times the bulk data transfer component of this command. Equivalent to the \fI\-\-time\fR option in the main description. .TP \fB\-v\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR print out version string then exit. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2007 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_read_buffer, sg_write_buffer, sg_test_rwbuf(all in sg3_utils) sg3_utils-1.40/doc/sgm_dd.80000664000175000017500000002710712053021257014447 0ustar douggdougg.TH SGM_DD "8" "November 2019" "sg3_utils\-1.35" SG3_UTILS .SH NAME sgm_dd \- copy data to and from files and devices, especially SCSI devices .SH SYNOPSIS .B sgm_dd [\fIbs=BS\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR] [\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .PP [\fIbpt=BPT\fR] [\fIcdbsz=\fR6|10|12|16] [\fIdio=\fR0|1] [\fIsync=\fR0|1] [\fItime=\fR0|1] [\fIverbose=VERB\fR] .SH DESCRIPTION .\" Add any additional description here .PP Copy data to and from any files. Specialized for "files" that are Linux SCSI generic (sg) devices and raw devices. Uses memory mapped transfers on sg devices. Similar syntax and semantics to .B dd(1) but does not perform any conversions. .PP Will only perform memory mapped transfers when \fIIFILE\fR or \fIOFILE\fR are SCSI generic (sg) devices. .PP If both \fIIFILE\fR and \fIOFILE\fR are sg devices then memory mapped transfers are performed on \fIIFILE\fR. If no other flags are specified then indirect IO is performed on \fIOFILE\fR. If 'oflag=dio' is given then direct IO is attempted on \fIOFILE\fR. If 'oflag=smmap' is given then shared mmap\-ed IO (sharing the mmap\-ed reserve buffer associated with \fIIFILE\fR) is attempted. In both latter cases if the faster IO option is not available, they fall back to indirect IO and report this at the end of the copy. .PP The first group in the synopsis above are "standard" Unix .B dd(1) operands. The second group are extra options added by this utility. Both groups are defined below. .SH OPTIONS .TP \fBbpt\fR=\fIBPT\fR each IO transaction will be made using \fIBPT\fR blocks (or less if near the end of the copy). Default is 128 for block sizes less that 2048 bytes, otherwise the default is 32. So for bs=512 the reads and writes will each convey 64 KiB of data by default (less if near the end of the transfer or memory restrictions). When cd/dvd drives are accessed, the block size is typically 2048 bytes and bpt defaults to 32 which again implies 64 KiB transfers. .TP \fBbs\fR=\fIBS\fR where \fIBS\fR .B must be the block size of the physical device. Note that this differs from .B dd(1) which permits \fIBS\fR to be an integral multiple. Default is 512 which is usually correct for disks but incorrect for cdroms (which normally have 2048 byte blocks). For this utility the maximum size of each individual IO operation is \fIBS\fR * \fIBPT\fR bytes. .TP \fBcdbsz\fR=6 | 10 | 12 | 16 size of SCSI READ and/or WRITE commands issued on sg device names. Default is 10 byte SCSI command blocks (unless calculations indicate that a 4 byte block number may be exceeded, in which case it defaults to 16 byte SCSI commands). .TP \fBcount\fR=\fICOUNT\fR copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices report from SCSI READ CAPACITY commands or that block devices (or their partitions) report. Normal files are not probed for their size. If \fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e. not explicitly given) then the derived count is scaled back so that the copy will not overrun the device. If the file name is a block device partition and \fICOUNT\fR is not given then the size of the partition rather than the size of the whole device is used. If \fICOUNT\fR is not given and cannot be derived then an error message is issued and no copy takes place. .TP \fBdio\fR=0 | 1 permits direct IO to be selected on the write\-side (i.e. on \fIOFILE\fR). Only allowed when the read\-side (i.e. \fIIFILE\fR) is a sg device. When 1 there may be a "zero copy" copy (i.e. mmap\-ed transfer on the read into the user space and direct IO from there on the write, potentially two DMAs and no data copying from the CPU). Default is 0. The same action as 'dio=1' is also available with 'oflag=dio'. .TP \fBibs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBif\fR=\fIIFILE\fR read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR is given. .TP \fBiflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIIFILE\fR and are ignored when \fIIFILE\fR is stdin. .TP \fBobs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBof\fR=\fIOFILE\fR write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed. If \fIOFILE\fR is '.' (period) then it is treated the same way as /dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it is _not_ truncated; it is overwritten from the start of \fIOFILE\fR unless 'oflag=append' or \fISEEK\fR is given. .TP \fBoflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIOFILE\fR and are ignored when \fIOFILE\fR is /dev/null, '.' (period), or stdout. .TP \fBseek\fR=\fISEEK\fR start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR. Default is block 0 (i.e. start of file). .TP \fBskip\fR=\fISKIP\fR start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR. Default is block 0 (i.e. start of file). .TP \fBsync\fR=0 | 1 when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the transfer. Only active when \fIOFILE\fR is a sg device file name. .TP \fBtime\fR=0 | 1 when 1, times transfer and does throughput calculation, outputting the results (to stderr) at completion. When 0 (default) doesn't perform timing. .TP \fBverbose\fR=\fIVERB\fR as \fIVERB\fR increases so does the amount of debug output sent to stderr. Default value is zero which yields the minimum amount of debug output. A value of 1 reports extra information that is not repetitive. A value 2 reports cdbs and responses for SCSI commands that are not repetitive (i.e. other that READ and WRITE). Error processing is not considered repetitive. Values of 3 and 4 yield output for all SCSI commands (and Unix read() and write() calls) so there can be a lot of output. .TP \fB\-\-help\fR outputs usage message and exits. .TP \fB\-\-version\fR outputs version number information and exits. .SH FLAGS Here is a list of flags and their meanings: .TP append causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For normal files this will lead to data appended to the end of any existing data. Cannot be used together with the \fIseek=SEEK\fR option as they conflict. The default action of this utility is to overwrite any existing data from the beginning of the file or, if \fISEEK\fR is given, starting at block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g. a disk) will usually be ignored or may cause an error to be reported. .TP dio is only active with oflag (i.e. 'oflag=dio'). Its action is described in the 'dio=1' option description above. .TP direct causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. This flag requires some memory alignment on IO. Hence user memory buffers are aligned to the page size. Has no effect on sg, normal or raw files. .TP dpo set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not supported for 6 byte cdb variants of READ and WRITE. Indicates that data is unlikely to be required to stay in device (e.g. disk) cache. May speed media copy and/or cause a media copy to have less impact on other device users. .TP dsync causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. The "d" is prepended to lower confusion with the 'sync=0|1' option which has another action (i.e. a synchronisation to media at the end of the transfer). .TP excl causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. .TP fua causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE commands. This only has effect with sg devices. The 6 byte variants of the SCSI READ and WRITE commands do not support the FUA bit. Only active for sg device file names. .TP null has no affect, just a placeholder. .TP smmap is only active for oflag. It sets shared mmap IO usage on \fIOFILE\fR if it is a sg device node. The \fIIFILE\fR also needs to be a sg device node (or there is no mmap\-ed reserve buffer to share). .SH RETIRED OPTIONS Here are some retired options that are still present: .TP fua=0 | 1 | 2 | 3 force unit access bit. When 3, fua is set on both \fIIFILE\fR and \fIOFILE\fR; when 2, fua is set on \fIIFILE\fR; when 1, fua is set on \fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag. .SH NOTES A raw device must be bound to a block device prior to using sgm_dd. See .B raw(8) for more information about binding raw devices. To be safe, the sg device mapping to SCSI block devices should be checked with 'cat /proc/scsi/scsi' before use. .PP Raw device partition information can often be found with .B fdisk(8) [the "\-ul" argument is useful in this respect]. .PP Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The count, skip and seek parameters can take 64 bit values (i.e. very big numbers). Other values are limited to what can fit in a signed 32 bit number. .PP Data usually gets to the user space in a 2 stage process: first the SCSI adapter DMAs into kernel buffers and then the sg driver copies this data into user memory (write operations reverse this sequence). With memory mapped transfers a kernel buffer reserved by sg is memory mapped (see the .B mmap(2) system call) into the user space. When this is done the second (redundant) copy from kernel buffers to user space is not needed. Hence the transfer is faster and requires less "grunt" from the CPU. .PP All informative, warning and error output is sent to stderr so that dd's output file can be stdout and remain unpolluted. If no options are given, then the usage message is output and nothing else happens. .PP For sg devices this utility issues SCSI READ and WRITE (SBC) commands which are appropriate for disks and reading from CD/DVD/BD drives. Those commands are not formatted correctly for tape devices so sgm_dd should not be used on tape devices. .PP This utility stops the copy if any error is encountered. For more advanced "copy on error" logic see the .B sg_dd utility (and its 'coe' flag). .SH EXAMPLES .PP See the examples given in the man page for .B sg_dd(8). .SH SIGNALS The signal handling has been borrowed from dd: SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred and the records in + out counts; then they have their default action. SIGUSR1 causes the same information to be output yet the copy continues. All output caused by signals is sent to stderr. .SH EXIT STATUS The exit status of sgm_dd is 0 when it is successful. Otherwise see the sg3_utils(8) man page. Since this utility works at a higher level than individual commands, and there are 'coe' and 'retries' flags, individual SCSI command failures do not necessary cause the process to exit. .SH AUTHORS Written by Douglas Gilbert and Peter Allworth. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2012 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" The simplest variant of this utility is called .B sg_dd. A POSIX threads version of this utility called .B sgp_dd is in the sg3_utils package. The lmbench package contains .B lmdd which is also interesting. .B raw(8), dd(1) sg3_utils-1.40/doc/sg_referrals.80000664000175000017500000000514312334207341015666 0ustar douggdougg.TH SG_REFERRALS "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_referrals \- send SCSI REPORT REFERRALS command .SH SYNOPSIS .B sg_referrals [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-one-segment\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send the SCSI REPORT REFERRALS command to the \fIDEVICE\fR and outputs the response. This command was introduced in (draft) SBC\-3 revision 24 and devices that support referrals should support this command. .PP The default action is to decode the response for all user data segment referral descriptors. The amount of output can be reduced by the \fI\-\-lba\fR and \fI\-\-one-segment\fR options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response to this command in ASCII hex. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the Logical Block Address (LBA) in the first user data segment the \fIDEVICE\fR should report the referrals parameter data for. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given then 256 is used. 256 is enough space for the response header and user data segment descriptors. .TP \fB\-s\fR, \fB\-\-one-segment\fR report the user data segment of the segment spefified by the \fILBA\fR parameter only. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout). .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). Additional output caused by this option is sent to stderr. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES For a discussion of referrals see section 4.25 of sbc3r25.pdf at http://www.t10.org (or the corresponding section of a later draft). .SH EXIT STATUS The exit status of sg_referrals is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert and Hannes Reinecke. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2014 Douglas Gilbert and Hannes Reinecke .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd(8) sg3_utils-1.40/doc/sg_safte.80000664000175000017500000001005012053021257014772 0ustar douggdougg.TH SG_SAFTE "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_safte \- access SCSI Accessed Fault\-Tolerant Enclosure (SAF\-TE) device .SH SYNOPSIS .B sg_safte [\fI\-\-config\fR] [\fI\-\-devstatus\fR] [\fI\-\-encstatus\fR] [\fI\-\-flags\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-insertions\fR] [\fI\-\-raw\fR] [\fI\-\-usage\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Fetches enclosure status (via a SCSI READ BUFFER command). The \fIDEVICE\fR should be a SAF\-TE device which may be a storage array controller (INQUIRY peripheral device type 0xc) or a generic processor device (INQUIRY peripheral device type 0x3). .PP If no options are given (only the \fIDEVICE\fR argument) then the overall enclosure status as reported by the option .I \-\-config .R is reported. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-c\fR, \fB\-\-config\fR will issues a .I Read Enclosure Configuration .R (READ BUFFER ID 0) cdb to the device, which returns a list of the enclosure hardware resources. .TP \fB\-d\fR, \fB\-\-devstatus\fR will issue a .I Read Device Slot Status .R (READ BUFFER ID 4) cdb to the device, which returns information about the current state of each drive or slot. .TP \fB\-s\fR, \fB\-\-encstatus\fR will issue a .I Read Enclosure Status .R (READ BUFFER ID 1) cdb to the device, which returns the operational state of the components. .TP \fB\-f\fR, \fB\-\-flags\fR will issue a .I Read Global Flags .R (READ BUFFER ID 5) cdb to the device, which read the most recent state of the global flags of the RAID processor device. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the response to a READ BUFFER command in ASCII hex to stdout. If used once, output the response to the first READ BUFFER command (i.e. with buffer_id=0). This should be the enclosure configuration. If used twice (or more often), the response to subsequent READ BUFFER commands is output. .TP \fB\-i\fR, \fB\-\-insertions\fR will issue a .I Read Device Insertions .R (READ BUFFER ID 3) cdb to the device, which returns information about the number of times devices have been inserted whilst the RAID system was powered on. .TP \fB\-r\fR, \fB\-\-raw\fR output the response to a READ BUFFER command in binary to stdout. If used once, output the response to the first READ BUFFER command (i.e. with buffer_id=0). This should be the enclosure configuration. If used twice (or more often), the response to subsequent READ BUFFER commands is output. .TP \fB\-u\fR, \fB\-\-usage\fR will issue a .I Read Usage Statistics .R (READ BUFFER ID 2) cdb to the device, which returns the information on total usage time and number of power\-on cycles of the RAID device. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES The implementation is based on the intermediate review document eg as found at .PP http://www.intel.com/design/servers/ipmi/saf\-te.htm .PP As the specification was never finalized this document serves as the de\-facto standard. .PP Similar functionality is provided by SPC\-4 SCSI Enclosure Services devices (Peripheral device type 0xd), which can be queried with the sg_ses utility. .SH EXAMPLES To view the configuration: .PP sg_safte /dev/sg1 .PP To view the device slot status: .PP sg_safte \-\-devstatus /dev/sg1 .PP .SH EXIT STATUS The exit status of sg_safte is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Hannes Reinecke and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Hannes Reinecke and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_ses (in sg3_utils package); safte\-monitor (internet) sg3_utils-1.40/doc/sg_unmap.80000664000175000017500000001446112326640175015033 0ustar douggdougg.TH SG_UNMAP "8" "April 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_unmap \- send SCSI UNMAP command (known as 'trim' in ATA specs) .SH SYNOPSIS .B sg_unmap [\fI\-\-anchor\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] [\fI\-\-in=FILE\fR] [\fI\-\-lba=LBA,LBA...\fR] [\fI\-\-num=NUM,NUM...\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI UNMAP command to \fIDEVICE\fR to unmap one or more logical blocks. This command was introduced in SBC\-3 revision 18 under the broad heading of "logical block provisioning". Logical blocks may also be unmapped by the SCSI WRITE SAME command; see the sg_write_same utility. The unmap capability is closely related to the ATA DATA SET MANAGEMENT command with the "Trim" bit set. .PP Logical blocks to be unmapped can be specified in one of two ways to this utility. One way is by supplying the start LBAs to the '\-\-lba=' option and the corresponding number(s) to unmap to the '\-\-num=' option. The other way is by putting start LBA and number to unmap pairs in a file whose name is given to the '\-\-in=' option. All values are assumed to be decimal unless prefixed by "0x" (or "0X") or have a trailing "h" (or "H") in which case they are interpreted as hexadecimal. Suffix multipliers are permitted on decimal values (e.g. '\-\-num=1m'). .PP When the '\-\-lba=' option is given then the '\-\-num=' option must also be given. If one has a comma separated list as its argument then the other must have the same number of elements in its list. The arguments can use a single space as a separator but need to be in quotes or escaped to not be misinterpreted by the shell. .PP With the '\-\-in=FILE' option an even number of values must be found and are interpreted as pairs: the first value in each pair is a starting LBA and the second value is the number to unmap from that LBA. Everything from and including a "#" on a line is ignored as are blank lines. Values may be comma, space and tab separated or appear on separate lines. Each line should not exceed 1023 bytes in length. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-anchor\fR sets the 'Anchor' bit in the command (introduced in sbc3r22). .TP \fB\-g\fR, \fB\-\-grpnum\fR=\fIGN\fR sets the 'Group number' field to \fIGN\fR. Defaults to a value of zero. \fIGN\fR should be a value between 0 and 31. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-I\fR, \fB\-\-in\fR=\fIFILE\fR where \fIFILE\fR is a file name containing pairs of values. The first member of each pair is a starting LBA and the second member of the pair is the number of logical blocks to unmap from and including that starting LBA. Values are interpreted as decimal unless indicated otherwise. This option cannot be present with the '\-\-lba=' option. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA,LBA...\fR where \fILBA,LBA...\fR is a string of comma (or space) separated values that are interpreted as starting logical block addresses. Each number is interpreted as decimal unless prefixed by '0x' or '0X' (or it has a trailing 'h' or 'H'). An argument that contains any space separators needs to be quoted (or otherwise escaped). When this option is given then the '\-\-num=' option must also be given and they must contain the same number of elements in their arguments. .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM,NUM...\fR where \fINUM,NUM...\fR is a string of comma (or space) separated values that are interpreted as a number of logical blocks to unmap. Each number is interpreted as decimal unless prefixed by '0x' or '0X' (or it has a trailing 'h' or 'H'). Note that 0 blocks is acceptable. An argument that contains any space separators needs to be quoted (or otherwise escaped). When this option is given then the '\-\-lba=' option must also be given and they must contain the same number of elements in their arguments. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fITO\fR where \fITO\fR is a timeout value (in seconds) for the UNMAP command. The default value is 60 seconds. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES Some limits: an LBA can be up to 64 bits, a NUM up to 32 bits (imposed by structure of UNMAP SCSI command parameter data). The NUM is further constrained by the MAXIMUM UNMAP LBA COUNT field in the BLOCK LIMITS VPD page (0xb0). The maximum number of LBA,NUM pairs is limited to 128 by this utility and may be further constrained by the MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT field in the BLOCK LIMITS VPD page. .PP Since it is unclear how long the UNMAP command will take to execute a '\-\-timeout=" option has been provided. The default timeout period is 60 seconds. If all the logical blocks on a logical unit (e.g. a disk drive) are to be unmapped then the FORMAT UNIT SCSI command (see the sg_format utility) may be considered as an alternative. .PP Support for logical block provisioning is indicated by the LBPME bit in the response to the SCSI READ CAPACITY (16) command (see the sg_readcap utility). .PP In SBC\-3 revision 25 the LBPU and ANC_SUP bits where added to the Logical Block Provisioning VPD page. When LBPU is set it indicates that the device supports the UNMAP command. When the ANC_SUP bit is set it indicates the device supports anchored LBAs. .PP The SCSI UNMAP command does the "right thing" with respect to command queueing. However its ATA counterpart: the DATA SET MANAGEMENT command with the "Trim" bit set does not interact well with SATA queueing known as NCQ. To address this problem T13 have introduced a new command called SFQ DATA SET MANAGEMENT which also has a Trim bit. .SH EXAMPLES In the examples directory of the sg3_utils package there is a sg_unmap_example.txt file that shows the format that the '\-\-in=' option accepts. .SH EXIT STATUS The exit status of sg_unmap is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_format,sg_get_lba_status,sg_readcap,sg_vpd,sg_write_same(sg3_utils) sg3_utils-1.40/doc/sg_map.80000664000175000017500000001314712142450532014460 0ustar douggdougg.TH SG_MAP "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME sg_map \- displays mapping between Linux sg and other SCSI devices .SH SYNOPSIS .B sg_map [\fI\-a\fR] [\fI-h\fR] [\fI\-i\fR] [\fI\-n\fR] [\fI\-scd\fR] [\fI\-sd\fR] [\fI\-sr\fR] [\fI\-st\fR] [\fI\-V\fR] [\fI\-x\fR] .SH DESCRIPTION .\" Add any additional description here .PP Sometimes it is difficult to determine which SCSI device a sg device name (e.g. /dev/sg0) refers to. This command loops through the sg devices and finds the corresponding SCSI disk, cdrom or tape device name (if any). Scanners are an example of SCSI devices that have no alternate SCSI device name apart from their sg device name. .PP This utility is deprecated and has not been updated for years, only very obvious bugs will be fixed. Unless a very old version of Linux is being used (e.g. 2.4 series or earlier), then please use a utility like lsscsi(8) or the facilities offered by udev(8). .SH OPTIONS .TP \fB\-a\fR assume the sg devices have alphabetical device names and loop through /dev/sga, /dev/sgb, etc. Default is numeric scan. Note that sg device nodes with an alphabetical index have been deprecated since the Linux kernel 2.2 series. .TP \fB\-h\fR print usage message then exit. .TP \fB\-i\fR in addition do a standard INQUIRY and output vendor, product and revision strings for devices that are found. .TP \fB\-n\fR assume the sg devices have numeric device names and loop through /dev/sg0, /dev/sg1, etc. Default is numeric scan .TP \fB\-scd\fR display mappings to SCSI cdrom device names of the form /dev/scd0, /dev/scd1 etc .TP \fB\-sd\fR display mappings to SCSI disk device names .TP \fB\-sr\fR display mappings to SCSI cdrom device names of the form /dev/sr0, /dev/sr1 etc .TP \fB\-st\fR display mappings to SCSI tape device names .TP \fB\-V\fR print out version string then exit (without further ado). .TP \fB\-x\fR after each active sg device name is displayed there are five digits: .SH NOTES If no options starting with "\-s" are given then the mapping to all SCSI disk, cdrom and tape device names is shown. .PP If the device file system (devfs) is present a line noting this is output. The "native" devfs scsi hierarchy makes the relationship between a sg device name and any corresponding disk, cdrom or tape device name easy to establish. This replaces the need for this command. However many applications will continue to look for Linux SCSI device names in their traditional places. [Devfs supplies a compatibility daemon called devfsd whose default configuration adds back the Linux device names in their traditional positions. .PP Quite often the mapping information can be derived by observing the output of the command: "cat /proc/scsi/scsi". However if devices have been added since boot this can be deceptive. .PP In the Linux kernel 2.6 series something close to the mapping shown by this utility can be found by analysing sysfs. The main difference is that sysfs analysis will show the mapping between sg nodes and other SCSI device nodes in terms of major and minor numbers. While major 8, minor 16 will usually be /dev/sdb this is not necessarily so. Facilities associated with udev may assign major 8, minor 16 some other device node name. This version of sg_map has been extended to cope with sparse disk device node names of the form "/dev/sd" where can be one of [a\-z,aa\-zz,aaa\-zzz]. See the sg_map26 utility for a more precise way (i.e. less directory scanning) for mapping between sg device names and higher level names; including finding user defined names. .PP This utility was written at a time when hotplugging of SCSI devices was not supported in Linux. It used a simple algorithm to scan sg device nodes in ascending numeric or alphabetical order, stopping after there were 5 consecutive errors. .PP In the Linux kernel 2.6 series, this utility uses sysfs to find which sg device nodes are active and only checks those. Hence there can be large "holes" in the numbering of sg device nodes (e.g. after an adapter has been removed) and still all active sg device nodes will be listed. This utility assumes that sg device nodes are named using the normal conventions and searches from /dev/sg0 to /dev/sg4095 inclusive. .SH EXAMPLES .PP My system has a SCSI disk, a cd writer and a dvd player: .br $ sg_map .br # Note: the devfs pseudo file system is present .br /dev/sg0 /dev/sda .br /dev/sg1 /dev/sr0 .br /dev/sg2 /dev/sr1 .PP In order to find which sg device name corresponds to the disk: .br $ sg_map \-sd .br # Note: the devfs pseudo file system is present .br /dev/sg0 /dev/sda .br /dev/sg1 .br /dev/sg2 .PP The "\-x" option gives the following output: .br sg_map \-x .br # Note: the devfs pseudo file system is present .br /dev/sg0 1 0 1 0 0 /dev/sda .br /dev/sg1 2 0 4 0 5 /dev/sr0 .br /dev/sg2 2 0 6 0 5 /dev/sr1 .PP When a SCSI scanner is added the output becomes: .br $ sg_map .br # Note: the devfs pseudo file system is present .br /dev/sg0 /dev/sda .br /dev/sg1 /dev/sr0 .br /dev/sg2 /dev/sr1 .br /dev/sg3 .PP By process of elimination /dev/sg3 must be the scanner. .SH EXIT STATUS The exit status of sg_map is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2013 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_map26(8) , .B scsi_info(8) , .B scsidev(8) , .B devfsd(8) , .B lsscsi(8) , .B udev(7) sg3_utils-1.40/doc/rescan-scsi-bus.sh.80000664000175000017500000000476512271755144016644 0ustar douggdougg.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.41.2. .TH RESCAN-SCSI-BUS.SH "1" "leden 2014" "rescan-scsi-bus.sh 1.57" "User Commands" .SH NAME rescan-scsi-bus.sh \- script for adding and removing SCSI devices without rebooting .SH SYNOPSIS .B rescan-scsi-bus.sh [\fIoptions\fR] [\fIhost \fR[\fIhost \fR...]] .SH OPTIONS .TP \fB\-a\fR, \fB\-\-alltargets\fR scan all targets, not just currently existing [default: disabled] .TP \fB\-d\fR enable debug [default: 0] .TP \fB\-l\fR activates scanning for LUNs 0\-\-7 [default: 0] .TP \fB\-L\fR NUM activates scanning for LUNs 0\-\-NUM [default: 0] .TP \fB\-w\fR, \fB\-\-wide\fR scan for target device IDs 0\-\-15 [default: 0\-\-7] .TP \fB\-c\fR enables scanning of channels 0 1 [default: 0 / all detected ones] .TP \fB\-r\fR, \fB\-\-remove\fR enables removing of devices [default: disabled] .TP \fB\-f\fR, \fB\-\-flush\fR flush failed multipath devices [default: disabled] .TP \fB\-i\fR, \fB\-\-issue\-lip\fR issue a FibreChannel LIP reset [default: disabled] .TP \fB\-u\fR, \fB\-\-update\fR look for existing disks that have been remapped .TP \fB\-s\fR, \fB\-\-resize\fR look for resized disks and reload associated multipath devices, if applicable .TP \fB\-\-forcerescan\fR rescan existing devices .TP \fB\-\-forceremove\fR remove and readd every device (DANGEROUS) .TP \fB\-\-nooptscan\fR don't stop looking for LUNs is 0 is not found .TP \fB\-\-color\fR use coloured prefixes OLD/NEW/DEL .TP \fB\-\-hosts\fR=\fILIST\fR scan only host(s) in \fILIST\fR .TP \fB\-\-channels\fR=\fILIST\fR scan only channel(s) in \fILIST\fR .TP \fB\-\-ids\fR=\fILIST\fR scan only target ID(s) in \fILIST\fR .TP \fB\-\-luns\fR=\fILIST\fR scan only lun(s) in \fILIST\fR .TP \fB\-\-sync\fR, \fB\-\-nosync\fR issue a sync / no sync [default: sync if remove] .TP \fB\-\-attachpq3\fR tell kernel to attach sg to LUN 0 that reports PQ=3 .TP \fB\-\-reportlun2\fR tell kernel to try REPORT_LUN even on SCSI2 devices .TP \fB\-\-largelun\fR tell kernel to support LUNs > 7 even on SCSI2 devs .TP \fB\-\-sparselun\fR tell kernel to support sparse LUN numbering .IP Host numbers may thus be specified either directly on cmd line (deprecated) or or with the \fB\-\-hosts\fR=\fILIST\fR parameter (recommended). .PP \fILIST\fR: A[\-B][,C[\-D]]... is a comma separated list of single values and ranges (No spaces allowed.) .SH SEE ALSO \fBrescan-scsi-bus.sh\fR Homepage: \fBhttp://www.garloff.de/kurt/linux/#rescan-scsi\fR .PP \fBsg3_utils\fR Homepage: \fBhttp://sg.danny.cz/sg\fR sg3_utils-1.40/doc/sg_sync.80000664000175000017500000001031612176051475014664 0ustar douggdougg.TH SG_SYNC "8" "July 2013" "sg3_utils\-1.37" SG3_UTILS .SH NAME sg_sync \- send SCSI SYNCHRONIZE CACHE command .SH SYNOPSIS .B sg_sync [\fI\-\-16\fR] [\fI\-\-count=COUNT\fR] [\fI\-\-group=GN\fR] [\fI\-\-help\fR] [\fI\-\-immed\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-sync\-nv\fR] [\fI\-\-timeout=SECS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send SYNCHRONIZE CACHE(10) or SYNCHRONIZE CACHE(16) command to \fIDEVICE\fR. These commands are defined for SCSI block devices (see SBC\-3). If successful these commands make sure that any blocks whose latest versions are held in cache are written to (also termed as "synchronized with") the medium. .PP If the \fILBA\fR and \fICOUNT\fR arguments are both zero (their defaults) then all blocks in the cache are synchronized. If \fILBA\fR is greater than zero while \fICOUNT\fR is zero then blocks in the cache whose addresses are from and including \fILBA\fR to the highest lba on the device are synchronized. If both \fILBA\fR and \fICOUNT\fR are non zero then blocks in the cache whose addresses lie in the range \fILBA\fR to \fILBA\fR+\fICOUNT\fR\-1 inclusive are synchronized with the medium. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-S\fR, \fB\-\-16\fR performs a SYNCHRONIZE CACHE(16) command. Default is to perform a SYNCHRONIZE CACHE(10) command. .TP \fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR where \fICOUNT\fR is the number of blocks to synchronize from and including \fILBA\fR. Default value is 0. When 0 then all blocks in the cache from and including \fILBA\fR argument to the highest block address are synchronized. .TP \fB\-g\fR, \fB\-\-group\fR=\fIGN\fR where \fIGN\fR is the group number which can be between 0 and 31 inclusive. The default value is 0 . Group numbers are used to segregate data collected within the device. This is a new feature in SBC\-2 and can probably be ignored for the time being. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-immed\fR sets the IMMED bit in the SYNCHRONIZE CACHE command. This instructs the device, if the format of the command is acceptable, to return a GOOD status immediately rather than wait for the blocks in the cache to be synchronized with (i.e. written to) the medium. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the lowest logical block address in the cache to synchronize to the medium. Default value is 0 . .TP \fB\-s\fR, \fB\-\-sync\-nv\fR synchronize the (volatile) cache with the non\-volatile cache. Without this option (or if there is no non\-volatile cache in the device) the synchronization is with the medium. The SYNC_NV bit was made obsolete in SBC\-3 revision 35d. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fISECS\fR where \fISECS\fR is the number of seconds the OS allows the SYNCHRONIZE CACHE(16) to complete before it tries to cancel the command. Cancelling commands (typically with the task management function "abort task") is best avoided. Note this option is only active together with the \fI\-\-16\fR option. The default timeout is 60 seconds for both SYNCHRONIZE CACHE(10) and SYNCHRONIZE CACHE(16). Note that timeout issues can be avoided with the \fI\-\-immed\fR option. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES With the SYNCHRONIZE CACHE(16) command \fILBA\fR can be up to 64 bits in size and \fICOUNT\fR up to 32 bits in size. With the SYNCHRONIZ CACHE(10) command \fILBA\fR can be up to 32 bits in size and \fICOUNT\fR up to 16 bits in size. .PP Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .SH EXIT STATUS The exit status of sg_sync is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_start(sg3_utils) sg3_utils-1.40/doc/sg_rdac.80000664000175000017500000000243512053021257014611 0ustar douggdougg.TH SG_RDAC "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_rdac \- display or modify SCSI RDAC Redundant Controller mode page .SH SYNOPSIS .B sg_rdac [\fI\-a\fR] [\fI\-f=LUN\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP sg_rdac displays or modifies the RDAC controller settings via the Redundant Controller mode page (0x2C). When modifying the settings it allows to transfer the ownership of individual drives to the controller the command was received on. .SH OPTIONS .TP \fB\-a\fR Transfer all (visible) devices .TP \fB\-f\fR=\fILUN\fR Transfer the device identified by \fILUN\fR. This command will only work if the controller supports 'Dual Active Mode' (aka active/active mode). .TP \fB\-v\fR be verbose .TP \fB\-V\fR print version string then exit .SH EXIT STATUS The exit status of sg_rdac is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Hannes Reinecke , based on sg_emc_trespass. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2012 Hannes Reinecke, Douglas Gilbert. .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. sg3_utils-1.40/doc/sg_sat_read_gplog.80000664000175000017500000001230012430315266016647 0ustar douggdougg.TH SG_SAT_READ_GPLOG "8" "November 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_sat_read_gplog \- use ATA READ LOG EXT command via a SCSI to ATA Translation (SAT) layer .SH SYNOPSIS .B sg_sat_read_gplog [\fI\-\-ck_cond\fR] [\fI\-\-count=CO\fR] [\fI\-\-dma\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-len=\fR{16|12}] [\fI\-\-log=\fRLA] [\fI\-\-page=\fRPN] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends an ATA READ LOG EXT or an ATA READ LOG DMA EXT command to the \fIDEVICE\fR. This command is used to read the general purpose log of (S)ATA disks (not ATAPI devices such as DVD driver). Rather than send the READ LOG (DMA) EXT command directly to the device it is sent via a SCSI transport which is assumed to contain a SCSI to ATA Translation (SAT) Layer (SATL). The SATL may be in an operating system driver, in host bus adapter (HBA) firmware or in some external enclosure. .PP This utility does not currently attempt to decode the response from the ATA disk, rather it outputs the response in ASCII hexadecimal grouped in 16 bit words. Following ATA conventions those words are decoded little endian (note that SCSI commands use a big endian representation). In the future this utility may attempt to decode some log pages, perhaps using the \fI\-\-decode\fR option. .PP The SAT\-2 standard (SAT ANSI INCITS 465-2010, prior draft: sat2r09.pdf at www.t10.org) defines two SCSI "ATA PASS\-THROUGH" commands: one using a 16 byte "cdb" and the other with a 12 byte cdb. This utility defaults to using the 16 byte cdb variant. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-C\fR, \fB\-\-ck_cond\fR sets the CK_COND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set the SATL should yield a sense buffer containing a ATA Result descriptor irrespective of whether the ATA command succeeded or failed. When clear the SATL should only yield a sense buffer containing a ATA Result descriptor if the ATA command failed. .TP \fB\-c\fR, \fB\-\-count\fR=\fICO\fR the number \fICO\fR is placed in the "count" field in the ATA READ LOG EXT command. This specified the number of 512-byte blocks of data to be read from the specified log. .TP \fB\-d\fR, \fB\-\-dma\fR use the ATA READ LOG DMA EXT command instead of ATA READ LOG EXT command. Some devices require this to return valid log data. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-H\fR, \fB\-\-hex\fR when given once, the response is output in ASCII hexadecimal bytes. When given twice, then the response is grouped into 16 bit words using ATA conventions (i.e. little endian); this is the default output (i.e. when this option is not given). When given thrice (i.e. '\-HHH') the output is in hex, grouped in 16 bit words (without a leading offset and trailing ASCII on each line), in a format that is acceptable for 'hdparm \-\-Istdin' to process. .TP \fB\-L\fR, \fB\-\-log\fR=\fILA\fR the number \fILA\fR is known as the "log address" in the ATA standards and is placed in bits 7:0 of the "lba" field of the ATA READ LOG (DMA) EXT command. This specifies the log to be returned (See ATA-ACS for a detailed list of available log addresses). The default value placed in the "lba field is 0, returning the directory of available logs. The maximum value allowed for \fILOG\fR is 0xff. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPN\fR the number \fIPN\fR is the page number (within the log address) and is placed in bits 32:16 of the "lba" field of the ATA READ LOG (DMA) EXT command. The default value placed in the "lba" field is 0. The maximum value allowed for \fILOG\fR is 0xffff. .TP \fB\-l\fR, \fB\-\-len\fR={16|12} this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands. The argument can either be 16 or 12. The default is 16. Some SCSI transports cannot convey SCSI commands longer than 12 bytes. .TP \fB\-r\fR, \fB\-\-readonly\fR causes the \fIDEVICE\fR to be opened with the read\-only flag (O_RDONLY in Unix). The default action is to open \fIDEVICE\fR with the read\-write flag (O_RDWR in Unix). In some cases sending power management commands to ATA disks are defeated by OS actions on the close() if the \fIDEVICE\fR was opened with the read\-write flag (e.g. the OS might think it needs to flush something to disk). .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string .SH NOTES Prior to Linux kernel 2.6.29 USB mass storage limited sense data to 18 bytes which made the \fB\-\-ck_cond\fR option yield strange (truncated) results. .SH EXIT STATUS The exit status of sg_sat_read_gplog is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Hannes Reinecke and Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2014 Hannes Reinecke, SUSE Linux GmbH .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_sat_identify(sg3_utils), sg_inq(sg3_utils), sdparm(sdparm), .B hdparm(hdparm) sg3_utils-1.40/doc/sg_format.80000664000175000017500000006122312357543201015175 0ustar douggdougg.TH SG_FORMAT "8" "July 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_format \- format, resize or modify protection information of a SCSI disk .SH SYNOPSIS .B sg_format [\fI\-\-cmplst=\fR{0|1}] [\fI\-\-count=COUNT\fR] [\fI\-\-dcrt\fR] [\fI\-\-early\fR] [\fI\-\-fmtpinfo=FPI\fR] [\fI\-\-format\fR] [\fI\-\-help\fR] [\fI\-\-ip_def\fR] [\fI\-\-long\fR] [\fI\-\-mode=MP\fR] [\fI\-\-pfu=PFU\fR] [\fI\-\-pie=PIE\fR] [\fI\-\-pinfo\fR] [\fI\-\-poll=PT\fR] [\fI\-\-resize\fR] [\fI\-\-rto_req\fR] [\fI\-\-security\fR] [\fI\-\-six\fR] [\fI\-\-size=SIZE\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wait\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Not all SCSI direct access devices need to be formatted and some have vendor specific formatting procedures. SCSI disks with rotating media are probably the largest group that do support a 'standard' format operation. They are typically factory formatted to a block size of 512 bytes with the largest number of blocks that the manufacturer recommends. The manufacturer's recommendation typically leaves aside a certain number of tracks, spread across the media, for reassignment of blocks to logical block addresses during the life of the disk. .PP This utility can format modern SCSI disks and potentially change their block size (if permitted) and the block count (i.e. number of accessible blocks on the media also known as "resizing"). Resizing a disk to less than the manufacturer's recommended block count is sometimes called "short stroking" (see NOTES section). Resizing the block count while not changing the block size may not require a format operation. The SBC\-2 standard (see www.t10.org) has obsoleted the "format device" mode page. Many of the low level details found in that mode page are now left up to the discretion of the manufacturer. .PP When this utility is used without options (i.e. it is only given a DEVICE argument) it prints out the existing block size and block count derived from two sources. These two sources are a block descriptor in the response to a MODE SENSE command and the response to a READ CAPACITY command. The reason for this double check is to detect a "format corrupt" state (see NOTES section). This usage will not modify the disk. .PP When this utility is used with the "\-\-format" (or "\-F") option it will attempt to format the given DEVICE. There is a 15 second pause during which time the user is invited thrice (5 seconds apart) to abort sg_format. This occurs just prior the SCSI FORMAT UNIT command being issued. See the NOTES section for more information. .PP Protection information is optional and is made up of one or more protection intervals, each made up of 8 bytes associated with each logical block. Four protection types are defined with protection type 0 being no protection intervals. See the PROTECTION INFORMATION section below for more information. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-C\fR, \fB\-\-cmplst\fR={0|1} sets the CMPLST ("complete list") bit in the FORMAT UNIT cdb to 0 or 1. The default is 1 in which case the existing GLIST (grown list) is ignored. If the value is 0 then the existing GLIST is taken into account. See the LISTS section below. In most cases this bit should be left set; some MO disk drives need this bit cleared. .TP \fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR where \fICOUNT\fR is the number of blocks to be formatted or media to be resized to. Can be used with either \fI\-\-format\fR or \fI\-\-resize\fR. With \fI\-\-format\fR this option need not be given in which case it is assumed to be zero. With \fI\-\-format\fR the interpretation of \fICOUNT\fR is: .br (\fICOUNT\fR > 0) : only format the first \fICOUNT\fR blocks and READ .br CAPACITY will report \fICOUNT\fR blocks after format .br (\fICOUNT\fR = 0) and block size unchanged : use existing block count .br (\fICOUNT\fR = 0) and block size changed : recommended maximum block .br count for new block size .br (\fICOUNT\fR = \-1) : use recommended maximum block count .br (\fICOUNT\fR < \-1) : illegal .br With \fI\-\-resize\fR this option must be given and \fICOUNT\fR has this interpretation: .br (\fICOUNT\fR > 0) : after resize READ CAPACITY will report \fICOUNT\fR .br blocks .br (\fICOUNT\fR = 0) : after resize READ CAPACITY will report 0 blocks .br (\fICOUNT\fR = \-1) : after resize READ CAPACITY will report its .br maximum number of blocks .br (\fICOUNT\fR < \-1) : illegal .br In both cases if the given \fICOUNT\fR exceeds the maximum number of blocks (for the block size) then the disk reports an error. See NOTES section below. .TP \fB\-D\fR, \fB\-\-dcrt\fR this option sets the DCRT bit in the FORMAT UNIT command's parameter list header. It will "disable certification". Certification verifies that blocks are usable during the format process. Using this option may speed the format. The default action of this utility (i.e. when this option is not given) is to clear the DCRT bit thereby requesting "media certification". When the DCRT bit is set, the FOV bit must also be set hence sg_format does that. .TP \fB\-e\fR, \fB\-\-early\fR during a format operation, The default action of this utility is to poll the disk every 60 seconds to determine the progress of the format operation until it is finished. When this option is given this utility will exit "early", that is as soon as the format operation has commenced. Then the user can monitor the progress of the ongoing format operation with other utilities (e.g. sg_turs(8) or sg_requests(8)). This option and \fI\-\-wait\fR are mutually exclusive. .TP \fB\-f\fR, \fB\-\-fmtpinfo\fR=\fIFPI\fR sets the FMTPINFO field in the FORMAT UNIT cdb to a value between 0 and 3. The default value is 0. The FMTPINFO field from SBC\-3 revision 16 is a 2 bit field (bits 7 and 6 of byte 1 in the cdb). Prior to that it was a single bit field (bit 7 of byte 1 in the cdb) and there was an accompanying bit called RTO_REQ (bit 6 of byte 1 in the cdb). The deprecated options "\-\-pinfo" and "\-\-rto\-req" represent the older usage. This option should be used in their place. See the PROTECTION INFORMATION section below for more information. .TP \fB\-F\fR, \fB\-\-format\fR issue a SCSI FORMAT UNIT command. .B This will destroy all the data held on the media. This option is required to change the block size of a disk. The user is given a 15 second count down to ponder the wisdom of doing this, during which time control\-C (amongst other Unix commands) can be used to kill this process before it does any damage. .br When used three times (or more) the preliminary MODE SENSE and SELECT commands are bypassed, leaving only the initial INQUIRY and FORMAT UNIT commands. This is for emergency use (e.g. when the MODE SENSE/SELECT commands are not working) and cannot change the logical block size. .br See NOTES section for implementation details and EXAMPLES section for typical use. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage information then exit. .TP \fB\-I\fR, \fB\-\-ip_def\fR sets the default Initialization Pattern. Some disks (SSDs) use this to flag that a format should fully provision (i.e. associate a physical block with every logical block). The same disks (SSDs) might thin provision if this option is not given. If this option is given then the \fI\-\-security\fR option cannot be given. .TP \fB\-l\fR, \fB\-\-long\fR the default action of this utility is to assume 32 bit logical block addresses. With 512 byte block size this permits more than 2 terabytes (almost 2 ** 41 bytes) on a single disk. This option selects commands and parameters that allow for 64 bit logical block addresses. Specifically this option sets the "longlba" flag in the MODE SENSE (10) command and uses READ CAPACITY (16) rather than READ CAPACITY (10). If this option is not given and READ CAPACITY (10) or MODE SELECT detects a disk the needs more than 32 bits to represent its logical blocks then it is set internally. This option does not set the LONGLIST bit in the FORMAT UNIT command. The LONGLIST bit is set as required depending other parameters (e.g. when '\-\-pie=PIE' is greater than zero). .TP \fB\-M\fR, \fB\-\-mode\fR=\fIMP\fR \fIMP\fR is a mode page number (0 to 62 inclusive) that will be used for reading and perhaps changing the device logical block size. The default is 1 which is the Read\-Write Error Recovery mode page. .TP \fB\-P\fR, \fB\-\-pfu\fR=\fIPFU\fR sets the "Protection Field Usage" field in the parameter block associated with a FORMAT UNIT command to \fIPFU\fR. The default value is 0, the only other defined value currently is 1. See the PROTECTION INFORMATION section below for more information. .TP \fB\-q\fR, \fB\-\-pie\fR=\fIPIE\fR sets the "Protection Interval Exponent" field in the parameter block associated with a FORMAT UNIT command to \fIPIE\fR. The default value is 0. \fIPIE\fR can only be non-zero with protection types 2 and 3. The value of 0 is typical for 512 byte blocks; with 4096 byte blocks a value of 3 may be appropriate (i.e. 8 protection intervals interleaved with 4096 bytes of user data). A device may not support any non-zero values. This field first appeared in SBC\-3 revision 18. .TP \fB\-p\fR, \fB\-\-pinfo\fR this option is deprecated, use the \fI\-\-fmtpinfo=FPI\fR option instead. If used, then it sets bit 7 of byte 1 in the FORMAT UNIT cdb and that is equivalent to setting \fI\-\-fmtpinfo=2\fR. [So if \fI\-\-pinfo\fR is used (plus \fI\-\-fmtpinfo=FPI\fR and \fI\-\-pfu=PFU\fR are not given or their arguments are 0) then protection type 1 is selected.] .TP \fB\-x\fR, \fB\-\-poll\fR=\fIPT\fR where \fIPT\fR is the type of poll used. If \fIPT\fR is 0 then a TEST UNIT READY command is used, otherwise a REQUEST SENSE command is used. The default is currently 0 but this will change to 1 in the near future. See the NOTES sections below. .TP \fB\-r\fR, \fB\-\-resize\fR rather than format the disk, it can be resized. This means changing the number of blocks on the device reported by the READ CAPACITY command. This option should be used with the \fI\-\-count=COUNT\fR option. The contents of all logical blocks on the media remain unchanged when this option is used. This means that any resize operation can be reversed. This option cannot be used together with either \fI\-\-format\fR or a \fI\-\-size=SIZE\fR whose argument is different to the existing block size. .TP \fB\-R\fR, \fB\-\-rto_req\fR The option is deprecated, use the \fI\-\-fmtpinfo=FPI\fR option instead. If used, then it sets bit 6 of byte 1 in the FORMAT UNIT cdb. .TP \fB\-S\fR, \fB\-\-security\fR sets the "Security Initialization" (SI) bit in the FORMAT UNIT command's initialization pattern descriptor within the parameter list. According to SBC\-3 the default initialization pattern "shall be written using a security erasure write technique". See the NOTES section on the SCSI SANITIZE command. If this option is given then the \fI\-\-ip_def\fR option cannot be given. .TP \fB\-6\fR, \fB\-\-six\fR Use 6 byte variants of MODE SENSE and MODE SELECT. The default action is to use the 10 byte variants. Some MO drives need this option set when doing a format. .TP \fB\-s\fR, \fB\-\-size\fR=\fISIZE\fR where \fISIZE\fR is the block size (i.e. number of bytes in each block) to format the device to. The default value is whatever is currently reported by the block descriptor in a MODE SENSE command. If the block size given by this option is different from the current value then a MODE SELECT command is used to change it prior to the FORMAT UNIT command being started (as recommended in the draft standard). Many SCSI disks have 512 byte sectors by default and allow up to 16 bytes extra in a sector (i.e. 528 byte sectors). If the given size in unacceptable with the disk, most likely an "Invalid field in parameter list" message will appear in sense data (requires the use of '\-v' to decode sense data). .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). "\-vvv" gives a lot more debug output. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-w\fR, \fB\-\-wait\fR the default format action is to set the "IMMED" bit in the FORMAT UNIT command's (short) parameter header. If this option (i.e. \fI\-\-wait\fR) is given then the "IMMED" bit is not set. If \fI\-\-wait\fR is given the FORMAT UNIT command waits until the format operation completes before returning its response. This can be many hours on large disks. This utility sets a 15 hour timeout on such a FORMAT UNIT command! Some recent SSDs go to the other extreme of completing a format operation in 1.5 seconds hence waiting is not an issue. .SH LISTS The SBC\-3 draft (revision 36) defines PLIST, CLIST, DLIST and GLIST in section 4.13 on "Medium defects". Briefly, the PLIST is the "primary" list of manufacturer detected defects, the CLIST ("certification" list) contains those detected during the format operation, the DLIST is a list of defects that can be given to the format operation. The GLIST is the grown list which starts in the format process as CLIST+DLIST and can "grow" later due to automatic reallocation (see the ARRE and AWRE bits in the Read\-Write Error Recovery mode page (see sdparm(8))) and use of the SCSI REASSIGN BLOCKS command (see sg_reassign(8)). .PP The CMPLST bit (controlled by the \fI\-\-cmplst=\fR0|1 option) determines whether the existing GLIST, when the format operation is invoked, is taken into account. The sg_format utility sets the FOV bit to zero which causes DPRY=0, so the PLIST is taken into account, and DCRT=0, so the CLIST is generated and used during the format process. .PP The sg_format utility does not permit a user to provide a defect list (i.e. DLIST). .SH PROTECTION INFORMATION Protection Information (PI) is additional information held with logical blocks so that an application and/or host bus adapter can check the correctness of those logical blocks. PI is placed in one or more protection intervals beside each logical block. A protection interval contains 8 bytes made up of a 2 byte "logical block guard" (CRC), a 2 byte "logical block application guard", and a 4 byte "logical block reference tag". Devices with 512 byte logical block size typically have one protection interval appended, making its logical block data 520 bytes long. Devices with 4096 byte logical block size often have 8 protection intervals spread across its logical block data for a total size of 4160 bytes. Note that for all other purposes the logical block size is considered to be 512 and 4096 bytes respectively. .PP SBC\-3 drafts have added several "protection types" to the PI introduced in the SBC\-2 standard. SBC\-3 defines 4 protection types (types 0 to 3) with protection type 0 meaning no PI is maintained. While a device may support one or more protection types, it can only be formatted with 1 of the 4. To change a device's protection type, it must be re\-formatted. For more information see the Protection Information in section 4.22 of draft SBC\-3 revision 36. .PP A device that supports PI information (i.e. supports one or more protection types 1, 2 and 3) sets the "PROTECT" bit in its standard INQUIRY response. It also sets the SPT field in the EXTENDED INQUIRY VPD page response to indicate which protection types it supports. Given PROTECT=1 then SPT=0 implies the device supports PI type 1 only, SPT=1 implies the device supports PI types 1 and 2, and various other non\-obvious mappings up to SPT=7 which implies protection types 1, 2 and 3 are supported. The .B current protection type of a disk can be found in the "P_TYPE" and "PROT_EN" fields in the response of a READ CAPACITY (16) command (e.g. with the 'sg_readcap \-\-long' utility). .PP Given that a device supports a particular protection type, a user can then choose to format that disk with that protection type by setting the "FMTPINFO" and "Protection Field Usage" fields in the FORMAT UNIT command. Those fields correspond to the \fI\-\-fmtpinfo=FPI\fR and the \fI\-\-pfu=PFU\fR options in this utility. The list below shows the four protection types followed by the options of this utility needed to select them: .br \fB0\fR : \-\-fmtpinfo=0 \-\-pfu=0 .br \fB1\fR : \-\-fmtpinfo=2 \-\-pfu=0 .br \fB2\fR : \-\-fmtpinfo=3 \-\-pfu=0 .br \fB3\fR : \-\-fmtpinfo=3 \-\-pfu=1 .br The default value of \fIFPI\fR (in \fI\-\-fmtpinfo=FPI\fR) is 0 and the default value of \fIPFU\fR (in \fI\-\-pfu=PFU\fR) is 0. So if neither \fI\-\-fmtpinfo=FPI\fR nor \fI\-\-pfu=PFU\fR are given then protection type 0 (i.e. no protection information) is chosen. .SH NOTES The SBC\-2 standard states that the REQUEST SENSE command should be used for obtaining progress indication when the format command is underway. However, tests on a selection of disks shows that TEST UNIT READY commands yield progress indications (but not REQUEST SENSE commands). So the current version of this utility defaults to using TEST UNIT READY commands to poll the disk to find out the progress of the format. The \fI\-\-poll=PT\fR option has been added to control this. .PP When the \fI\-\-format\fR option is given without the \fI\-\-wait\fR option then the SCSI FORMAT UNIT command is issued with the IMMED bit set which causes the SCSI command to return after it has started the format operation. The \fI\-\-early\fR option will cause sg_format to exit at that point. Otherwise the \fIDEVICE\fR is polled every 60 seconds with TEST UNIT READY or REQUEST SENSE commands until it reports an "all clear" (i.e. the format operation has completed). Normally these polling commands will result in a progress indicator (expressed as a percentage) being output to the screen. If the user gets bored watching the progress report then sg_format process can be terminated (e.g. with control\-C) without affecting the format operation which continues. However a target or device reset (or a power cycle) will probably cause the device to become "format corrupt". .PP When the \fI\-\-format\fR and \fI\-\-wait\fR options are both given then this utility may take a long time to return. In this case care should be taken not to send any other SCSI commands to the disk as it may not respond leaving those commands queued behind the active format command. This may cause a timeout in the OS driver (in a lot shorter period than 15 hours applicable to some format operations). This may result in the OS resetting the disk leaving the format operation incomplete. This may leave the disk in a "format corrupt" state requiring another format to remedy the situation. .PP When the block size (i.e. the number of bytes in each block) is changed on a disk two SCSI commands must be sent: a MODE SELECT to change the block size followed by a FORMAT command. If the MODE SELECT command succeeds and the FORMAT fails then the disk may be in a state that the draft standard calls "format corrupt". A block descriptor in a subsequent MODE SENSE will report the requested new block size while a READ CAPACITY command will report the existing (i.e. different) block size. Alternatively the READ CAPACITY command may fail, reporting the device is not ready, potentially requiring a format. The solution to this situation is to do a format again (and this time the new block size does not have to be given) or change the block size back to the original size. .PP The SBC\-2 standard states that the block count can be set back to the manufacturer's maximum recommended value in a format or resize operation. This can be done by placing an address of 0xffffffff (or the 64 bit equivalent) in the appropriate block descriptor field to a MODE SELECT command. In signed (two's complement) arithmetic that value corresponds to '\-1'. So a \fI\-\-count=\fR\-1 causes the block count to be set back to the manufacturer's maximum recommended value. To see exactly which SCSI commands are being executed and parameters passed add the "\-vvv" option to the sg_format command line. .PP Short stroking is a technique to trade off capacity for performance. Rotating disk performance is usually highest on the outer tracks (i.e. lower logical block addresses) so by resizing or reformatting a disk to a smaller capacity, average performance will usually be increased. .PP Other utilities may be useful in finding information associated with formatting. These include sg_inq(8) to fetch standard INQUIRY information (e.g. the PROTECT bit) and to fetch the EXTENDED INQUIRY VPD page (e.g. RTO and GRD_CHK bits). The sdparm(8) utility can be used to access and potentially change the now obsolete format mode page. .PP scsiformat is another utility available for formatting SCSI disks with Linux. It dates from 1997 (most recent update) and may be useful for disks whose firmware is of that vintage. .PP The \fICOUNT\fR numeric argument may include a multiplicative suffix or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The SCSI SANITIZE command was introduced in SBC\-3 revision 27. It is closely related to the ATA sanitize disk feature set and can be used to remove all existing data from a disk. Sanitize is more likely to be implemented on modern disks (including SSDs) than FORMAT UNIT's security initialization feature (see the \fI\-\-security\fR option) and in some cases much faster. .PP SSDs that support thin provisioning will typically unmap all logical blocks during a format. The reason is to improve the SSD's endurance. Also thin provisioned formats typically complete faster than fully provisioned ones on the same disk (see the \fI\-\-ip_def\fR option). In either case format operations on SSDs tend to be a lot faster than they are on hard disks with spinning media. .SH EXAMPLES These examples use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP In the first example below simply find out the existing block count and size derived from two sources: a block descriptor in a MODE SELECT command response and from the response of a READ CAPACITY commands. No changes are made: .PP # sg_format /dev/sdm .PP Now a simple format, leaving the block count and size as they were previously. The FORMAT UNIT command is executed in IMMED mode and the device is polled every 60 seconds to print out a progress indication: .PP # sg_format \-\-format /dev/sdm .PP Now the same format, but waiting (passively) until the format operation is complete: .PP # sg_format \-\-format \-\-wait /dev/sdm .PP Next is a format in which the block size is changed to 520 bytes and the block count is set to the manufacturer's maximum value (for that block size). Note, not all disks support changing the block size: .PP # sg_format \-\-format \-\-size=520 /dev/sdm .PP Now a resize operation so that only the first 0x10000 (65536) blocks on a disk are accessible. The remaining blocks remain unaltered. .PP # sg_format \-\-resize \-\-count=0x10000 /dev/sdm .PP Now resize the disk back to its normal (maximum) block count: .PP # sg_format \-\-resize \-\-count=\-1 /dev/sdm .PP One reason to format a SCSI disk is to add protection information. First check which protection types are supported by a disk (by checking the SPT field in the Extended inquiry VPD page together with the Protect bit in the standard inquiry response): .PP # sg_vpd \-p ei \-l /dev/sdb .br extended INQUIRY data VPD page: .br ACTIVATE_MICROCODE=0 .br SPT=1 [protection types 1 and 2 supported] .br .... .PP Format with type 1 protection: .PP # sg_format \-\-format \-\-fmtpinfo=2 /dev/sdm .PP After a successful format with type 1 protection, READ CAPACITY(16) should show something like this: .PP # sg_readcap \-l /dev/sdm .br Read Capacity results: .br Protection: prot_en=1, p_type=0, p_i_exponent=0 [type 1 protection] .br Logical block provisioning: lbpme=0, lbprz=0 .br .... .PP To format with type 3 protection: .PP # sg_format \-\-format \-\-fmtpinfo=3 \-\-pfu=1 /dev/sdm .PP For the disk shown above this will probably fail because the Extended inquiry VPD page showed only types 1 and 2 protection are supported. .SH EXIT STATUS The exit status of sg_format is 0 when it is successful. Otherwise see the sg3_utils(8) man page. Unless the \fI\-\-wait\fR option is given, the exit status may not reflect the success of otherwise of the format. Using sg_turs(8) and sg_readcap(8) after the format operation may be wise. .SH AUTHORS Written by Grant Grundler, James Bottomley and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2014 Grant Grundler, James Bottomley and Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_turs(8), sg_requests(8), sg_inq(8), sg_modes(8), sg_vpd(8), .B sg_reassign(8), sg_readcap(8), sg3_utils(8), .B sg_sanitize(8) [all in sg3_utils], .B sdparm(8), scsiformat (old), hdparm(8) sg3_utils-1.40/doc/sg_requests.80000664000175000017500000001274712334207341015564 0ustar douggdougg.TH SG_REQUESTS "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_requests \- send one or more SCSI REQUEST SENSE commands .SH SYNOPSIS .B sg_requests [\fI\-\-desc\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-num=NUM\fR] [\fI\-\-progress\fR] [\fI\-\-raw\fR] [\fI\-\-status\fR] [\fI\-\-time\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send SCSI REQUEST SENSE command to \fIDEVICE\fR and output the parameter data response which is expected to be in sense data format. Both fixed and descriptor sense data formats are supported. .PP Multiple REQUEST SENSE commands can be sent with the \fI\-\-num=NUM\fR option. This can be used for timing purposes or monitoring the progress indication. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-desc\fR sets the DESC bit in the REQUEST SENSE SCSI cdb. The \fIDEVICE\fR should return sense data in descriptor (rather than fixed) format. This will only occur if the \fIDEVICE\fR recognizes descriptor format (SPC\-3 and later). If the device is pre SPC\-3 then setting a bit in a reserved field may cause a check condition status with an illegal request sense key, but will most likely be ignored. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response in ASCII hexadecimal. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given (or \fILEN\fR is zero) then 252 is used. The maximum value of \fILEN\fR is 255 (but SPC\-4 recommends 252). .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM\fR perform \fINUM\fR SCSI REQUEST SENSE commands, stopping when either \fINUM\fR is reached or an error occurs. The default value for \fINUM\fR is 1 . .TP \fB\-p\fR, \fB\-\-progress\fR show progress indication (a percentage) if available. If \fI\-\-number=NUM\fR is given, \fINUM\fR is greater than 1 and an initial progress indication was detected then this utility waits 30 seconds before subsequent checks. Exits when \fINUM\fR is reached or there are no more progress indications. Ignores \fI\-\-hex\fR, \fI\-\-raw\fR and \fI\-\-time\fR options. See NOTES section below. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout). .TP \fB\-s\fR, \fB\-\-status\fR if the REQUEST SENSE command finished without error (as indicated by its SCSI status) then the contents of the parameter data are analysed as sense data and the exit status is set accordingly. The default action (i.e. when this option is not given) is to ignore the contents of the parameter data for the purposes of setting the exit status. Some types of error set a sense key of "NO SENSE" with non\-zero information in the additional sense code (e.g. the FAILURE PREDICTION THRESHOLD EXCEEDED group of codes); this results in an exit status value of 10. If the sense key is "NO SENSE" and both asc and ascq are zero then the exit status is set to 0 . See the sg3_utils(8) man page for exit status values. .TP \fB\-t\fR, \fB\-\-time\fR time the SCSI REQUEST SENSE command(s) and calculate the average number of operations per second. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). Additionally the response (if received) is output in ASCII\-HEX. Use this option multiple times for greater verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES In SCSI 1 and 2 the REQUEST SENSE command was very important for error and warning processing in SCSI. The autosense capability rendered this command almost superfluous. .PP However recent SCSI drafts (e.g. SPC\-4 rev 14 and SBC\-3 rev 14) increase the utility of the REQUEST SENSE command. Idle and standby (low) power conditions can be detected with this command. .PP The REQUEST SENSE command is not marked as mandatory in SPC\-3 (i.e. for all SCSI devices) but is marked as mandatory in SBC\-2 (i.e. for disks), SSC\-3 (i.e. for tapes) and MMC\-4 (i.e. for CD/DVD/HD\-DVD/BD drives). .PP The progress indication is optionally part of the sense data. When a prior command that takes a long time to complete (and typically precludes other media access commands) is still underway, the progress indication can be used to determine how long before the device returns to its normal state. .PP The SCSI FORMAT command for disks used with the IMMED bit set is an example of an operation that takes a significant amount of time and precludes other media access during that time. The IMMED bit set instructs the FORMAT command to return control to the application client once the format has commenced (see SBC\-3). Several long duration SCSI commands associated with tape drives also use the progress indication (see SSC\-3). .PP Early standards suggested that the SCSI TEST UNIT READY command be used for polling the progress indication. More recent standards seem to suggest the SCSI REQUEST SENSE command should be used instead. .PP The \fIDEVICE\fR is opened with a read\-only flag (e.g. in Unix with the O_RDONLY flag). .SH EXIT STATUS The exit status of sg_requests is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg3_utils sg3_utils-1.40/doc/sg_sat_identify.80000664000175000017500000001265512430315266016374 0ustar douggdougg.TH SG_SAT_IDENTIFY "8" "November 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_sat_identify \- send ATA IDENTIFY DEVICE command via SCSI to ATA Translation (SAT) layer .SH SYNOPSIS .B sg_sat_identify [\fI\-\-ck_cond\fR] [\fI\-\-extend\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-indent\fR] [\fI\-\-len=\fR{16|12}] [\fI\-\-packet\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends either an ATA IDENTIFY DEVICE command or an ATA IDENTIFY PACKET DEVICE command to \fIDEVICE\fR and outputs the response. The devices that respond to these commands are ATA disks and ATAPI devices respectively. Rather than send these commands directly to the device they are sent via a SCSI transport which is assumed to contain a SCSI to ATA Translation (SAT) Layer (SATL). The SATL may be in an operating system driver, in host bus adapter firmware or in some external enclosure. .PP The SAT standard (SAT ANSI INCITS 431\-2007, prior draft: sat\-r09.pdf at www.t10.org) defines two SCSI "ATA PASS\-THROUGH" commands: one using a 16 byte "cdb" and the other with a 12 byte cdb. This utility defaults to using the 16 byte cdb variant. SAT\-2 is also a standard: SAT\-2 ANSI INCITS 465\-2010 and the draft prior to that is sat2r09.pdf . The SAT/-3 project has started and the most recent draft is sat3r01.pdf . .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-ck_cond\fR sets the CK_COND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set the SATL should yield a sense buffer containing a ATA Result descriptor irrespective of whether the command succeeded or failed. When clear the SATL should only yield a sense buffer containing a ATA Result descriptor if the command failed. .TP \fB\-e\fR, \fB\-\-extend\fR sets the EXTEND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set a 48 bit LBA command is sent to the device. This option has no effect when \fI\-\-len=12\fR. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-H\fR, \fB\-\-hex\fR outputs the ATA IDENTIFY (PACKET) DEVICE response in hex. The default action (i.e. without any '\-H' options) is to output the response in hex, grouped in 16 bit words (i.e. the ATA standard's preference). When given once, the response is output in ASCII hex bytes (i.e. the SCSI standard's preference). When given twice (i.e. '\-HH') the output is in hex, grouped in 16 bit words, the same as the default but without a header. When given thrice (i.e. '\-HHH') the output is in hex, grouped in 16 bit words, in a format that is acceptable for 'hdparm \-\-Istdin' to process. '\-HHHH' simply outputs hex data bytes, space separated, 16 per line. .TP \fB\-i\fR, \fB\-\-indent\fR outputs the World Wide Name (WWN) of the device. This should be a NAA\-5 64 bit number. It is output in hex prefixed with "0x". If not available then "0x0000000000000000" is output. The equivalent for a SCSI disk (i.e. its logical unit name) can be found with "sg_vpd \-ii". .TP \fB\-l\fR, \fB\-\-len\fR={16|12} this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands. The argument can either be 16 or 12. The default is 16. The larger cdb size is needed for 48 bit LBA addressing of ATA devices. On the other hand some SCSI transports cannot convey SCSI commands longer than 12 bytes. .TP \fB\-p\fR, \fB\-\-packet\fR send an ATA IDENTIFY PACKET DEVICE command (via the SATL). The default action is to send an ATA IDENTIFY DEVICE command. .TP \fB\-r\fR, \fB\-\-raw\fR output the ATA IDENTIFY (PACKET) DEVICE response in binary. The output should be piped to a file or another utility when this option is used. The binary is sent to stdout, and errors are sent to stderr. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string .SH NOTES Since the response to the IDENTIFY (PACKET) DEVICE command is very important for the correct use of an ATA(PI) device (and is typically the first command sent), a SATL should provide an ATA Information VPD page which contains the similar information. .PP The SCSI ATA PASS\-THROUGH (12) command's opcode is 0xa1 and it clashes with the MMC set's BLANK command used by cd/dvd writers. So a SATL in front of an ATAPI device that uses MMC (i.e. has peripheral device type 5) probably should treat opcode 0xa1 as a BLANK command and send it through to the cd/dvd drive. The ATA PASS\-THROUGH (16) command's opcode (0x85) does not clash with anything so it is a better choice. .PP Prior to Linux kernel 2.6.29 USB mass storage limited sense data to 18 bytes which made the \fB\-\-ck_cond\fR option yield strange (truncated) results. .SH EXIT STATUS The exit status of sg_sat_identify is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd(sg3_utils), sg_inq(sg3_utils), sdparm(sdparm), hdparm(hdparm) sg3_utils-1.40/doc/scsi_stop.80000664000175000017500000000261712144707462015231 0ustar douggdougg.TH SCSI_STOP "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_stop \- stop (spin down) one or more SCSI disks .SH SYNOPSIS .B scsi_stop [\fI\-\-help\fR] [\fI\-\-verbose\fR] [\fI\-\-wait\fR] \fIDEVICE\fR [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls the sg_start utility on each given \fIDEVICE\fR. The purpose is to spin down (stop) each given \fIDEVICE\fR. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .TP \fB\-w\fR, \fB\-\-wait\fR wait for the spin down (stop) on each given \fIDEVICE\fR to complete. The default action is to do each stop in immediate mode. .SH NOTES The sg_start utility calls the SCSI START STOP UNIT command and can either start (spin up) or stop (spin down) a SCSI disk depending on the given command line options. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Otherwise the exit status is that of the last sg_start utility called. See the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2009\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_start (sg3_utils) sg3_utils-1.40/doc/sg_read_block_limits.80000664000175000017500000000341012054252214017340 0ustar douggdougg.TH SG_READ_BLOCK_LIMITS "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_read_block_limits \- send SCSI READ BLOCK LIMITS command .SH SYNOPSIS .B sg_read_block_limits [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI READ BLOCK LIMITS command to \fIDEVICE\fR and outputs the response. This command is defined for tape (drives) and its description is found in the SSC documents at http://www.t10.org . .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response in hex (rather than decode it). .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary to stdout. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH EXIT STATUS The exit status of sg_read_block_limits is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH EXAMPLES It is usually okay to use no options. Here is an invocation (on the first line following the "#" command prompt) followed by some typical output: .PP # sg_read_block_limits /dev/st0 .br Read Block Limits results: .br Minimum block size: 1 byte(s) .br Maximum block size: 16777215 byte(s), 16383 KB, 15 MB .br .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg3_utils(sg3_utils) sg3_utils-1.40/doc/scsi_readcap.80000664000175000017500000000365112144707462015642 0ustar douggdougg.TH SCSI_READCAP "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_readcap \- do SCSI READ CAPACITY command on disks .SH SYNOPSIS .B scsi_readcap [\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-long\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls the sg_readcap utility on each given \fIDEVICE\fR. This will send a SCSI READ CAPACITY command to each \fIDEVICE\fR. .PP The default action of this script is to send the 10 byte cdb READ CAPACITY(10) command to each \fIDEVICE\fR. If a response indicates the number of blocks is greater than or equal to '2**32 \- 1' then the READ CAPACITY(16) is sent and its response is output. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR shortens the output to two hexadecimal numbers, both prefixed by '0x'. The first number is the number of blocks available and the second is the size of each blocks in bytes (e.g. '0x12a19eb0 0x200'). If an error is detected '0x0 0x0' is output and the script continues if there are more \fIDEVICE\fRs. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-l\fR, \fB\-\-long\fR the default is to send the READ CAPACITY(10) command (i.e. the 10 byte cdb variant). When this option is given the READ CAPACITY(16) command is sent. The latter command yields more information in its response. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Otherwise the exit status is that of the last sg_readcap utility called. See the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2009\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_readcap (sg3_utils) sg3_utils-1.40/doc/sg_rtpg.80000664000175000017500000000424712336421514014663 0ustar douggdougg.TH SG_RTPG "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_rtpg \- send SCSI REPORT TARGET PORT GROUPS command .SH SYNOPSIS .B sg_rtpg [\fI\-\-decode\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI REPORT TARGET PORT GROUPS command to \fIDEVICE\fR and outputs the response. .PP Target port group access is described in SPC\-3 and SPC\-4 found at www.t10.org . The most recent draft of SPC\-4 is revision 37 in which target port groups are described in section 5.15 . .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-decode\fR decodes the status code and asymmetric access state from each target port group descriptor returned. The default action is not to decode these values. .TP \fB\-e\fR, \fB\-\-extended\fR use extended header format for parameter data. This sets the PARAMETER DATA FORMAT field in the cdb to 1. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response in hex (rather than partially or fully decode it). .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary to stdout. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES The Report Target Port Groups command should be supported whenever the TPGS bits in a standard INQUIRY response are greater than zero. [View with sg_inq utility.] .SH EXIT STATUS The exit status of sg_rtpg is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Christophe Varoqui and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(sg3_utils) sg3_utils-1.40/doc/sg_reset_wp.80000664000175000017500000000364712423733033015541 0ustar douggdougg.TH SG_RESET_WP "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_reset_wp \- send SCSI RESET WRITE POINTER command .SH SYNOPSIS .B sg_reset_wp [\fI\-\-help\fR] [\fI\-\-reset\-all\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-zone=ID\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends a SCSI RESET WRITE POINTER command to the \fIDEVICE\fR. This command is found in the ZBC draft standard revision 1c (zbc\-r01c.pdf). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-R\fR, \fB\-\-reset\-all\fR sets the RESET ALL field in the cdb. This causes a reset write pointer operation of all open zones and full zones. When this option is given then the \fI\-\-zone=ID\fR option is ignored. Either this option or the \fI\-\-zone=ID\fR option is required. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-z\fR, \fB\-\-zone\fR=\fIID\fR where \fIID\fR is placed in the cdb's ZONE ID field. A zone id is a zone start logical block address (LBA). This causes a reset write pointer operation on the zone identified by the ZONE ID field. The default value is 0. Either this option or the \fI\-\-reset\-all\fR option is required. \fIID\fR is assumed to be in decimal unless prefixed with '0x' or has a trailing 'h' which indicate hexadecimal. .SH EXIT STATUS The exit status of sg_reset_wp is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_rep_zones(sg3_utils) sg3_utils-1.40/doc/sg_write_long.80000664000175000017500000001666212113456343016065 0ustar douggdougg.TH SG_WRITE_LONG "8" "February 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME sg_write_long \- send SCSI WRITE LONG command .SH SYNOPSIS .B sg_write_long [\fI\-\-16\fR] [\fI\-\-cor_dis\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-pblock\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wr_uncor\fR] [\fI\-\-xfer_len=BTL\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send the SCSI WRITE LONG (10 or 16 byte) command to \fIDEVICE\fR. The buffer to be written to the \fIDEVICE\fR is filled with .B 0xff bytes or read from the \fIIF\fR file. This buffer includes the logical data (e.g. 512 bytes) and the ECC bytes. .PP This utility can be used to generate a MEDIUM ERROR at a specific logical block address. This can be useful for testing error handling. Prior to such a test, the .B sg_dd utility could be used to copy the original contents of the logical block address to some safe location. After the test the .B sg_dd utility could be used to write back the original contents of the logical block address. An alternate strategy would be to read the "long" contents of the logical block address with .B sg_read_long utility prior to testing and restore it with this utility after testing. .PP .B Take care: If recoverable errors are being injected (e.g. only one or a few bits changed so that the ECC is able to correct the data) then care should be taken with the settings in the "read write error recovery" mode page. Specifically if the ARRE (for reads) and/or AWRE (for writes) are set then recovered errors will cause the lba to be reassigned (and the old location to be added to the grown defect list (PLIST)). This is not easily reversed and uses (one of the finite number of) the spare sectors set aside for this purpose. If in doubt it is probably safest to clear the ARRE and AWRE bits. These bits can be checked and modified with the sdparm utility. For example: "sdparm \-c AWRE,ARRE /dev/sda" will clear the bits until the disk is power cycled. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-S\fR, \fB\-\-16\fR send a SCSI WRITE LONG (16) command to \fIDEVICE\fR. The default action (in the absence of this option) is to send a SCSI WRITE LONG (10) command. .TP \fB\-c\fR, \fB\-\-cor_dis\fR sets the correction disabled (i.e 'COR_DIS') bit. This inhibits various other mechanisms such as automatic block reallocation, error recovery and various informational exception conditions being triggered. This bit is relatively new in SBC\-3 . .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR read data (binary) from file named \fIIF\fR and use it for the SCSI WRITE LONG command. If \fIIF\fR is "\-" then stdin is read. If this option is not given then 0xff bytes are used as fill. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the logical block address of the sector to overwrite. Defaults to lba 0 which is a dangerous block to overwrite on a disk that is in use. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'. If \fILBA\fR is larger than can fit in 32 bits then the \fI\-\-16\fR option should be used. .TP \fB\-p\fR, \fB\-\-pblock\fR sets the physical block (i.e 'PBLOCK') bit. This instructs \fIDEVICE\fR to use the given data (unless \fI\-\-wr_uncor\fR is also given) to write to the physical block specified by \fILBA\fR. The default action is to write to the logical block corresponding to the given lba. This bit is relatively new in SBC\-3 . .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-wr_uncor\fR sets the "write uncorrected" (i.e 'WR_UNCOR') bit. This instructs the \fIDEVICE\fR to flag the given lba (or the physical block that contains it if \fI\-\-pblock\fR is also given) as having an unrecoverable error associated with it. Note: no data is transferred to \fIDEVICE\fR, other than the command (i.e. the cdb). In the absence of this option, the default action is to use the provided data or 0xff bytes (\fI\-\-xfer_len=BTL\fR in length) and write it to \fIDEVICE\fR. This bit is relatively new in SBC\-3 . .TP \fB\-x\fR, \fB\-\-xfer_len\fR=\fIBTL\fR where \fIBTL\fR is the byte transfer length (default to 520). If the given value (or the default) does not match the "long" block size of the device, nothing is written to \fIDEVICE\fR and the appropriate xfer_len value may be deduced from the error response which is printed (to stderr). .SH NOTES Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The 10 byte SCSI WRITE LONG command limits the logical block address to a 32 bit quantity. For larger LBAs use the \fI\-\-16\fR option for the SCSI WRITE LONG (16) command. .SH EXAMPLES This section outlines setting up a block with corrupted data, checking the error condition, then restoring useful contents to that sector. .PP First, if the data in a sector is important, save it with the sg_read_long utility: .PP sg_read_long \-\-lba=0x1234 \-\-out=0x1234_1.img \-x \fIBTL\fR /dev/sda .PP This utility may need to be executed several time in order to determine what the correct value for \fIBTL\fR is. Next use this utility to "corrupt" that sector. That might be done with: .PP sg_write_long \-\-lba=0x1234 \-x \fIBTL\fR /dev/sda .PP This will write a sector (and ECC data) of 0xff bytes. Some disks may reject this (at least one of the author's does). Another approach is to copy the 0x1234_1.img file (to 0x1234_2.img in this example) and change some values with a hex editor. Then write the changed image with: .PP sg_write_long \-\-lba=0x1234 \-\-in=0x1234_2.img \-x \fIBTL\fR /dev/sda .PP Yet another approach is to use the \fI\-\-wr_uncor\fR option, if supported: .PP sg_write_long \-\-lba=0x1234 \-\-wr_uncor /dev/sda .PP Next we use the sg_dd utility to check that the sector is corrupted. Here is an example: .PP sg_dd if=/dev/sda blk_sgio=1 skip=0x1234 of=. bs=512 count=1 verbose=4 .PP Notice that the "blk_sgio=1" option is given. This is to make sure that the sector is read (and no others) and the error is fully reported. The "blk_sgio=1" option causes the SG_IO ioctl to be used by sg_dd rather than the block subsystem. .PP Finally we should restore sector 0x1234 to a non\-corrupted state. A sector full of zeros could be written with: .PP sg_dd if=/dev/zero of=/dev/sda blk_sgio=1 seek=0x1234 bs=512 count=1 .PP This will result in a sector (block) with 512 bytes of 0x0 without a MEDIUM ERROR since the ECC and associated data will be regenerated and thus well formed. The 'blk_sgio=1' option is even more important in this case as it may stop the block subsystem doing a read before write (since the read will most likely fail). Another approach is to write back the original contents: .PP sg_write_long \-\-lba=0x1234 \-\-in=0x1234_1.img \-x \fIBTL\fR /dev/sda .PP .SH EXIT STATUS The exit status of sg_write_long is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Saeed Bishara. Further work by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2013 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_read_long, sg_dd (both in sg3_utils), sdparm(sdparm) sg3_utils-1.40/doc/sg_ident.80000664000175000017500000001164112053021257015002 0ustar douggdougg.TH SG_IDENT "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_ident \- send SCSI REPORT/SET IDENTIFYING INFORMATION command .SH SYNOPSIS .B sg_ident [\fI\-\-ascii\fR] [\fI\-\-clear\fR] [\fI\-\-help\fR] [\fI\-\-itype=IT\fR] [\fI\-\-raw\fR] [\fI\-\-set\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI REPORT IDENTIFYING INFORMATION or SET IDENTIFYING INFORMATION command to \fIDEVICE\fR. Prior to SPC\-4 (revision 7) these commands were called REPORT DEVICE IDENTIFIER and SET DEVICE IDENTIFIER respectively. SCSI devices that support these two commands allow users to write (set) identifying information and report it back at some later time. The information is persistent (i.e. stored on some non\-volatile medium within the SCSI device that will survive a power outage). .PP Typically the space allocated for the information is limited: SPC\-4 (revision 7) states that for information type 0, the minimum length is 64 bytes and the maximum is 512 bytes. For other information types (1 to 126 inclusive) the maximum length is 256 bytes. Also information types 1 to 126 (inclusive) should contain a null terminated UTF\-8 string. The author has seen older disks that only support 16 bytes. .PP The default action when no options are given is to invoke the Report Identifying Information command with the information type defaulting to zero. Error reports are sent to stderr. By default the information is shown in ASCII\-HEX (up to 16 bytes per line) with an ASCII representation to the right with dots replacing non printable characters. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-A\fR, \fB\-\-ascii\fR invokes the Report Identifying Information command and if anything is found interprets it as ASCII (or UTF\-8 depending on the locale) and prints the information to stdout. .TP \fB\-C\fR, \fB\-\-clear\fR invokes the Set Identifying Information command with an information length of zero. This has the effect of clearing the existing information. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-itype\fR=\fIIT\fR where \fIIT\fR is the information type. Defaults to zero. The maximum value is 127 which is special and cannot be used with \fI\-\-set\fR or \fI\-\-clear\fR. The information type of 127 (if supported) causes the REPORT IDENTIFYING INFORMATION command to respond with a list of available information types and their maximum lengths in bytes. The odd numbered information types between 3 and 125 (inclusive) are not to be used (as they clash with the SCC\-2 standard). .TP \fB\-r\fR, \fB\-\-raw\fR invokes the Report Identifying information command and if anything is found sends the information (which may be binary) to stdout. Nothing else is sent to stdout however error reports, if any, are sent to stderr. .TP \fB\-S\fR, \fB\-\-set\fR first reads stdin until an EOF is detected then invokes the Set Identifying Information command to set what has been fetched from stdin as the information. The amount of data read must be between 1 and 512 bytes length (inclusive). .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .PP This utility permits users to write their own identifying information to their SCSI devices. There are several other types of descriptors (or designators) that the user cannot change. These include the SCSI INQUIRY command with its standard vendor and product identification strings and the product revision level; plus the large amount of information provided by the "Device Identification" VPD page (see sg_vpd). There is also the READ MEDIA SERIAL NUMBER command (see sg_rmsn). The MMC\-4 command set for CD and DVDs has a "media serial number" feature (0x109) [and a "logical unit serial number" feature]. These can be viewed with the sg_get_config utility. .SH EXAMPLES First, to see if there is an existing information whose format is unknown (for information type 0), use no options: .PP # sg_ident /dev/sdb .br 00 31 32 33 34 35 36 37 38 39 30 1234567890 .PP If it is ASCII then it can printed as such: .PP # sg_ident \-\-ascii /dev/sdb .br 1234567890 .PP The information can be copied to a file, cleared and then re\-asserted with this sequence: .PP # sg_ident \-\-raw /dev/sdb > t .br # sg_ident \-\-clear /dev/sdb .br # cat t | sg_ident \-\-set /dev/sdb .SH EXIT STATUS The exit status of sg_ident is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_vpd(sg3_utils), sg_rmsn(sg3_utils), sg_get_config(sg3_utils) sg3_utils-1.40/doc/sg_opcodes.80000664000175000017500000002373612404322612015342 0ustar douggdougg.TH SG_OPCODES "8" "December 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_opcodes \- report supported SCSI commands or task management functions .SH SYNOPSIS .B sg_opcodes [\fI\-\-alpha\fR] [\fI\-\-compact\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-no-inquiry\fR] [\fI\-\-opcode=OP\fR] [\fI\-\-raw\fR] [\fI\-\-rctd\fR] [\fI\-\-repd\fR] [\fI\-\-sa=SA\fR] [\fI\-\-tmf\fR] [\fI\-\-unsorted\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_opcodes [\fI\-a\fR] [\fI\-c\fR] [\fI\-n\fR] [\fI\-o=OP\fR] [\fI\-q\fR] [\fI\-R\fR] [\fI\-s=SA\fR] [\fI\-t\fR] [\fI\-u\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends a SCSI REPORT SUPPORTED OPERATION CODES or a REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS command to the \fIDEVICE\fR and then outputs the response. The default action is to report supported operation codes. In this mode it will either list all supported commands or give detailed information on a specific command identified by the \fI\-\-opcode=OP\fR option (perhaps with additional information from the \fI\-\-sa=SA\fR option). .PP The name of a SCSI command depends on its peripheral device type (e.g. a disk). The REPORT SUPPORTED OPERATION CODES and REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS commands are not supported in the MMC command set for CD and DVD devices. This utility does an INQUIRY to obtain the peripheral device type and prints out the vendor, product and revision strings. .PP A similar facility to query supported operation codes previously was available via the CmdDt bit in the SCSI INQUIRY command (see sg_inq(8)). However that facility was made obsolete and replaced by the REPORT SUPPORTED OPERATION CODES command in SPC\-3 (revision 4) during February 2002. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-alpha\fR when all supported commands are being listed there is no requirement for the device server (i.e. the \fIDEVICE\fR) to sort the list of commands. When this option is given the list of supported commands is sorted by name (alphabetically). When this option and the \fB\-\-unsorted\fR option are both _not_ given then the list of supported commands is sorted numerically (first by operation code and then by service action). .TP \fB\-c\fR, \fB\-\-compact\fR some command names, especially those associated with some service actions, are getting longer. This may cause line wrap in the one line per command mode on some terminals. When this option is given the opcode and service action fields are combined into a single field with the service action, prefixed by a comma shown directly after the opcode. If there is no service action associated with the command, then the comma and the service action are not shown after the opcode. The CDB size field is not shown when this option is given. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-H\fR, \fB\-\-hex\fR outputs the response in ASCII hexadecimal to stdout. .TP \fB\-n\fR, \fB\-\-no-inquiry\fR Prior to calling a SCSI REPORT SUPPORTED OPERATION CODES or a REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS command, a SCSI INQUIRY command is performed. The reason is to determine the peripheral device type (pdt) of the \fIDEVICE\fR as this is helpful in translating operation codes to the command names. By default this utility prints a summary of INQUIRY command response on stdout. If this option (or the \fI\-\-raw\fR option) is given then that summary is not printed on stdout. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-o\fR, \fB\-\-opcode\fR=\fIOP\fR the \fIDEVICE\fR will be queried for the given operation code ( i.e. the \fIOP\fR value) which is the first byte of a SCSI command. \fIOP\fR is decimal unless prefixed by "0x" or it has a trailing "h". \fIOP\fR should be in the range 0 to 255 (0xff) inclusive. When this option is not given then all available SCSI commands supported by the \fIDEVICE\fR are listed. .TP \fB\-r\fR, \fB\-\-raw\fR output the response in binary to stdout. Error messages and warnings, if any, are sent to stderr. .TP \fB\-R\fR, \fB\-\-rctd\fR set report command timeout descriptor (RCTD) bit in the cdb. The response may or may not contain command timeout descriptors. If available they are output. If supported there are two values: a nominal command timeout and a recommended command timeout. Both have units of seconds. A value of zero means that no timeout is indicated and this is shown in the corresponding decoded output as "\-". .TP \fB\-q\fR, \fB\-\-repd\fR set read extended parameter data (REPD) bit in the report task management functions cdb. 16 bytes rather than the default 4 bytes expected in the response. This was added in SPC\-4 (revision 26). .TP \fB\-s\fR, \fB\-\-sa\fR=\fISA\fR the \fIDEVICE\fR will be queried for a command with the given service action (i.e. the \fISA\fR value). Used in conjunction with the \fI\-\-opcode=OP\fR option. If this option is not given, \fI\-\-opcode=OP\fR is given and the command in question does have a service action then a value of 0 will be assumed. \fISA\fR is decimal and expected to be in the range 0 to 65535 (0xffff) inclusive. .TP \fB\-t\fR, \fB\-\-tmf\fR list supported task management functions. This is done with the SCSI REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS command. When this option is chosen the \fI\-\-alpha\fR, \fI\-\-opcode=OP\fR, \fI\-\-rctd\fR, \fI\-\-sa=SA\fR and \fI\-\-unsorted\fR options are ignored. .TP \fB\-u\fR, \fB\-\-unsorted\fR when all supported commands are being listed there is no requirement for the device server (i.e. the \fIDEVICE\fR) to sort the list of commands. When this option is given the list of supported commands is in the order given by the \fIDEVICE\fR. When this option is not given the supported commands are sorted numerically (first by operation code and then by service action). .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH NOTES As of SPC\-4 revision 7a the recognized task management functions are: abort set, abort task set, clear ACA, clear task set, I_T nexus reset, logical unit reset, query task, target reset and wakeup. As of SPC\-4 revision 26 target reset and wakeup have been made obsolete while query task set and query asynchronous event notification have been added. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_opcodes /dev/sda" will work in the 2.6 series kernels. .SH EXIT STATUS The exit status of sg_opcodes is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-a\fR sort command alphabetically. Equivalent to \fI\-\-alpha\fR in main description. .TP \fB\-n\fR don't print a summary of the SCSI INQUIRY response on stdout. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-o\fR=\fIOP\fR the \fIDEVICE\fR will be queried for the given operation code (i.e. \fIOP\fR) which is the first byte of a SCSI command. \fIOP\fR is hexadecimal and expected to be in the range 0 to ff inclusive. When this option is not given then all available SCSI commands supported by the \fIDEVICE\fR are listed. .TP \fB\-q\fR set the read extended parameter data (REPD) bit in report TMF cdb. Equivalent to \fI\-\-repd\fR in main description. .TP \fB\-R\fR set the report command timeout descriptor (RCTD) bit in cdb. Equivalent to \fI\-\-rctd\fR in main description. .TP \fB\-s\fR=\fISA\fR the \fIDEVICE\fR will be queried for a command with the given service action (i.e. \fISA\fR). Used in conjunction with the \fI\-o=OP\fR option. If this option is not given, \fI\-o=OP\fR is given and the command in question does have a service action then a value of 0 will be assumed. \fISA\fR is hexadecimal and expected to be in the range 0 to ffff inclusive. .TP \fB\-t\fR list supported task management functions. Equivalent to \fI\-\-tmf\fR in the main description. .TP \fB\-u\fR output all supported commands in the order given by \fIDEVICE\fR. Equivalent to \fI\-\-unsorted\fR in main description. .TP \fB\-v\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR print out version string then exit. .TP \fB\-?\fR output usage message. Ignore all other parameters. .SH EXAMPLES The examples in this page use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP To see the information about a specific command give its operation code to the '\-\-op=' option. A command line invocation is shown first followed by a typical response: .PP # sg_opcodes \-\-op=93h /dev/sdb .PP Opcode=0x93 .br Command_name: Write same(16) .br Command supported [conforming to SCSI standard] .br Usage data: 93 e2 00 00 00 00 ff ff ff ff 00 00 ff ff 00 00 .PP The next example shows the supported task management functions: .PP # sg_opcodes \-\-tmf \-n /dev/sdb .PP Task Management Functions supported by device: .br Abort task .br Abort task set .br Clear ACA .br Clear task set .br Logical unit reset .br Query task .br .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(sg3_utils) sg3_utils-1.40/doc/sg_write_verify.80000664000175000017500000002224112412560743016422 0ustar douggdougg.TH "WRITE AND VERIFY" "8" "July 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_write_and_verify \- send the SCSI WRITE AND VERIFY command .SH SYNOPSIS .B sg_write_verify [\fI\-\-16\fR] [\fI\-\-bytchk=BC\fR] [\fI\-\-dpo\fR] [\fI\-\-group=GN\fR] [\fI\-\-help\fR] [\fI\-\-ilen=ILEN\fR] [\fI\-\-in=IF\fR] \fI\-\-lba=LBA\fR [\fI\-\-num=NUM\fR] [\fI\-\-repeat\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wrprotect=WP\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Send a SCSI WRITE AND VERIFY (10) or (16) command to \fIDEVICE\fR. The data to be written is read from the \fIIF\fR file or, in its absence, a buffer full of 0xff bytes is used. The length of the data\-out buffer sent with the command is \fIILEN\fR bytes or, if that is not given, then it is the length of the \fIIF\fR file. .PP The write operation is to the \fIDEVICE\fR's medium (optionally to its cache) starting at logical block address \fILBA\fR for \fINUM\fR logical blocks. After the write to medium is performed a verify operation takes place which may viewed as a medium read (with appropriate checks) but without the data being returned. Additionally, if \fIBS\fR is set to one, the data read back from the medium in the verify operation is compared to the original data\-out buffer. .PP The relationship between the number of logical blocks to be written (i.e. \fINUM\fR) and the length (in bytes) of the data\-out buffer (i.e. \fIILEN\fR) may be simply found by multiplying the former by the logical block size. However if the \fIDEVICE\fR has protection information (PI) then it becomes a bit more complicated. Hence the calculation is left to the user with the default \fIILEN\fR, in the absence of the \fIIF\fR file, being set to \fINUM\fR * 512. .PP For sending large amounts of data to contiguous logical blocks, a single WRITE AND VERIFY command may not be appropriate (e.g. due to operating system limitations). In such cases see the REPEAT section below. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-S\fR, \fB\-\-16\fR Send a WRITE AND VERIFY(16) command. The default is to send a WRITE AND VERIFY(10) command unless \fILBA\fR or \fINUM\fR are too large for the 10 byte variant. .TP \fB\-b\fR, \fB\-\-bytchk\fR=\fIBC\fR where \fIBC\fR is the value to place in the command's BYTCHK field. Values between 0 and 3 (inclusive) are accepted. The default is value is 0 which implies only a write to the medium then a verify operation are performed. The only other value T10 defines currently is 1 which does performs an additional comparison between the data\-out buffer that was used by the write operation and the contents of the logical blocks read back from the medium. .TP \fB\-d\fR, \fB\-\-dpo\fR Set the DPO (disable page out) bit in the command. The default is to leave it clear. .TP \fB\-g\fR, \fB\-\-group\fR=\fIGN\fR where \fIGN\fR is the value to place in the command's GROUP NUMBER field. Values between 0 and 31 (inclusive) are accepted. The default is value is 0. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-I\fR, \fB\-\-ilen\fR=\fIILEN\fR where \fIILEN\fR is the number of bytes that will be placed in the data\-out buffer. If the \fIIF\fR file is given then no more than \fIILEN\fR bytes are read from that file. If the \fIIF\fR file does not contain \fIILEN\fR bytes then an error is reported. If the \fIIF\fR file is not given then a data\-out buffer with \fIILEN\fR bytes of 0xff is sent. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR read data (binary) from file named \fIIF\fR. If \fIIF\fR is "\-" then stdin is used. This data will become the data\-out buffer and will be written to the \fIDEVICE\fR's medium. If \fIBC\fR is 1 then that data\-out buffer will be held until after the verify operation and compared to the data read back from the medium. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the logical block address to start the write to medium. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'. Must be provided. .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM\fR where \fINUM\fR is the number of blocks, starting at \fILBA\fR, to write to the medium. The default value for \fINUM\fR is 1. .TP \fB\-R\fR, \fB\-\-repeat\fR this option will continue to do WRITE AND VERIFY commands until the \fIIF\fR file is exhausted. This option requires both the \fI\-\-ilen=ILEN\fR and \fI\-\-in=IF\fR options to be given. Each command starts at the next logical block address and is for no more than \fINUM\fR blocks. The last command may be shorter with the number of blocks scaled as required. If there are residue bytes a warning is sent to stderr. See the REPEAT section. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fITO\fR where \fITO\fR is the command timeout value in seconds. The default value is 60 seconds. If \fINUM\fR is large then command may require considerably more time than 60 seconds to complete. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-wrprotect\fR=\fIWP\fR set the WRPROTECT field in the cdb to \fIWP\fR. The default value is 0 which implies no protection information is sent (along with the user data) in the data\-out buffer. .SH REPEAT For data sizes around a megabyte and larger, it may be appropriate to send multiple SCSI WRITE AND VERIFY commands due to operating system limitations (e.g. pass\-through SCSI interfaces often limit the amount of data that can be passed with a SCSI command). With this utility the mechanism for doing that is the \fI\-\-repeat\fR option. .PP In this mode the \fI\-\-ilen=ILEN\fR and \fI\-\-in=IF\fR options must be given. The \fIILEN\fR and \fINUM\fR values are treated as a per SCSI command parameters. Up to \fIILEN\fR bytes will be read from the \fIIF\fR file continually until it is exhausted. If the \fIIF\fR file is stdin, reading continues until an EOF is detected. The data read from each iteration becomes the data\-out buffer for a new WRITE AND VERIFY command. .PP The last read from the file (or stdin) may read less than \fIILEN\fR bytes in which case the number of logical blocks sent to the last WRITE AND VERIFY is scaled back accordingly. If there is a residual number of bytes left after that scaling then that is reported to stderr. .PP If an error occurs then that is reported to stderr and via the exit status and the utility stops at that point. .SH NOTES Other SCSI WRITE commands have a Force Unit Access (FUA) bit but that is set (implicitly) by WRITE AND VERIFY commands hence there is no option to set it. The data\-out buffer may still additionally be placed in the \fIDEVICE\fR's cache and setting the DPO bit is a hint not to do that. .PP Normal SCSI WRITEs can be done with the ddpt and the sg_dd utilities. The SCSI WRITE SAME command can be done with the sg_write_same utility while the SCSI COMPARE AND WRITE command (sg_compare_and_write utility) offers a "test and set" facility. .PP Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .SH EXIT STATUS The exit status of sg_write_verify is 0 when it is successful. If the verify operation fails that is typically indicated with a medium error which leads to an exit status of 3. .PP If \fIBC\fR is set to 1 and the comparison it causes fails this utility will indicate the miscompare with an exit status of 14. For other exit status values see the EXIT STATUS section in the sg3_utils(8) man page. .SH EXAMPLES To start with, a simple example: write 1 block of data held in file t.bin that is 512 bytes long then write that block to LBA 0x1234 on /dev/sg4 . .PP # sg_write_verify \-\-lba=0x1234 \-\-in=t.bin /dev/sg4 .PP Since '\-\-num=' is not given then it defaults to 1. Further the \fIILEN\fR value is obtained from the file size of t.bin . To additionally do a data\-out comparison to the read back data: .PP # sg_write_verify -l 0x1234 -i t.bin --bytchk=1 /dev/sg4 .PP The ddpt command can do copies between SCSI devices using READ and WRITE commands. However, currently it has no facility to promote those WRITES to WRITE AND VERIFY commands. Using a pipe, that could be done like this: .PP # ddpt if=/dev/sg2 bs=512 bpt=8 count=11 of=- | .br sg_write_verify \-\-in=\- \-l 0x567 \-n 8 \-\-ilen=4096 \-\-repeat /dev/sg4 .PP Both ddpt and sg_write_verify are configured for segments of 8 512 byte logical blocks. Since 11 logical blocks are read then first 8 logical blocks are copied followed by a copy of the remaining 3 blocks. Since it is assumed that there is no protection information then the data\-in and data\-out buffers will be 4096 bytes each. For sg_write_verify this needs to be stated explicitly with the \-\-ilen=4096 option. .SH AUTHORS Bruno Goncalves and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B ddpt(in a package of that name), sg_compare_and_write(8), sg_dd(8), .B sg_write_same(8) sg3_utils-1.40/doc/sg_ses_microcode.80000664000175000017500000002612412424673250016527 0ustar douggdougg.TH SG_SES_MICROCODE "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_ses_microcode \- send microcode to a SCSI enclosure .SH SYNOPSIS .B sg_ses_microcode [\fI\-\-bpw=CS\fR] [\fI\-\-help\fR] [\fI\-\-id=ID\fR] [\fI\-\-in=FILE\fR] [\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-non\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-skip=SKIP\fR] [\fI\-\-subenc=MS\fR] [\fI\-\-tlength=TLEN\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility attempts to download microcode to an enclosure (or one of its sub\-enclosures) associated with the \fIDEVICE\fR. The process for doing this is defined in the SCSI Enclosure Services (SES) standards and drafts maintained by the T10 committee. .PP The process is to send one or more sequences containing a SCSI SEND DIAGNOSTIC command followed optionally by a RECEIVE DIAGNOSTIC RESULTS command. The former sends a Download microcode Control diagnostic page (dpage) and the latter fetches a Download microcode status dpage which can be viewed as a report on the former command. .PP The default action (i.e. when the \fI\-\-mode=MO\fR option is not given) is to fetch the Download microcode status dpage and decode it. This does not require the microcode (firmware) itself so the \fI\-\-in=FILE\fR option is not required. .PP The most recent reference for this utility is the draft SCSI Enclosure Services 3 (SES\-3) document T10/2149\-D Revision 7 at http://www.t10.org . Existing standards for SES and SES\-2 are ANSI INCITS 305\-1998 and ANSI INCITS 448\-2008 respectively. .PP Most other support for SES in this package (apart from downloading microcode) can be found in the sg_ses utility. Another way of downloading firmware to a SCSI device is with the WRITE BUFFER command defined in SPC\-4, see the sg_write_buffer utility. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-bpw\fR=\fICS\fR where \fICS\fR is the chunk size in bytes and should be a multiple of 4. This will be the maximum number of bytes sent per SEND DIAGNOSTIC command. So if \fICS\fR is less than the effective length of the microcode then multiple SEND DIAGNOSTIC commands are sent, each taking the next chunk from the read data and increasing the buffer offset field in the Download microcode control dpage by the appropriate amount. The default is a chunk size of 0 which is interpreted as a very large number hence only one SEND DIAGNOSTIC command will be sent. .br The number in \fICS\fR can optionally be followed by ",act" or ",activate". In this case after the microcode has been successfully sent to the \fIDEVICE\fR, an additional Download microcode control dpage with its mode set to "Activate deferred microcode" [0xf] is sent. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. If used multiple times also prints the mode names and their acronyms. .TP \fB\-i\fR, \fB\-\-id\fR=\fIID\fR this option sets the BUFFER ID field in the Download microcode control dpage. \fIID\fR is a value between 0 (default) and 255 inclusive. .TP \fB\-I\fR, \fB\-\-in\fR=\fIFILE\fR read data from file \fIFILE\fR that will be sent with the SEND DIAGNOSTIC command. If \fIFILE\fR is '\-' then stdin is read until an EOF is detected (this is the same action as \fI\-\-raw\fR). Data is read from the beginning of \fIFILE\fR except in the case when it is a regular file and the \fI\-\-skip=SKIP\fR option is given. .TP \fB\-l\fR, \fB\-\-length\fR=\fILEN\fR where \fILEN\fR is the length, in bytes, of data to be written to the device. If not given (and the length cannot be deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR) then defaults to zero. If the option is given and the length deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR is less (or no data is provided), then bytes of 0xff are used as fill bytes. .TP \fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR this option sets the MODE. \fIMO\fR is a value between 0 (which is dmc_status and the default) and 255 inclusive. Alternatively an abbreviation can be given. See the MODES section below. To list the available mode abbreviations at run time give an invalid one (e.g. '\-\-mode=xxx') or use the '\-h' option. .TP \fB\-N\fR, \fB\-\-non\fR allow for non\-standard implementations that reset their Download microcode engine after a RECEIVE DIAGNOSTIC RESULTS command with the Download microcode status dpage is sent. When this option is given sending that command and dpage combination is avoided unless an error has already occurred. .TP \fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR this option sets the BUFFER OFFSET field in the Download microcode control dpage. \fIOFF\fR is a value between 0 (default) and 2**32\-1 . It is a byte offset. .TP \fB\-s\fR, \fB\-\-skip\fR=\fISKIP\fR this option is only active when \fI\-\-in=FILE\fR is given and \fIFILE\fR is a regular file, rather than stdin. Data is read starting at byte offset \fISKIP\fR to the end of file (or the amount given by \fI\-\-length=LEN\fR). If not given the byte offset defaults to 0 (i.e. the start of the file). .TP \fB\-S\fR, \fB\-\-subenc\fR=\fISEID\fR \fISEID\fR is the subenclosure identify. It defaults to 0 which is the primary enclosure identifier. .TP \fB\-t\fR, \fB\-\-tlength\fR=\fITLEN\fR \fITLEN\fR is the total length in bytes of the microcode to be (or being) downloaded. It defaults to 0 which is okay in most cases. This option is only needed when sections of microcode and being sent in separate invocations of this utility. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH MODES Following is a list accepted by the \fIMO\fR argument of this utility. First shown is an acronym followed in square brackets by the corresponding decimal and hex values that may also be given for \fIMO\fR. .TP dmc_status [0, 0x0] Use RECEIVE DIAGNOSTIC RESULTS to fetch the Download microcode status dpage and print it out. .TP dmc_offs [6, 0x6] Download microcode with offsets and activate. .TP dmc_offs_save [7, 0x7] Download microcode with offsets, save, and activate. .TP dmc_offs_defer [14, 0xe] Download microcode with offsets, save, and defer activate. .TP activate_mc [15, 0xf] Activate deferred microcode. There is no follow-up RECEIVE DIAGNOSTIC RESULTS to fetch the Download microcode status dpage since the \fIDEVICE\fR might be resetting. .PP Apart from dmc_status, these are placed in the Download microcode mode field in the Download microcode control dpage. In the case of dmc_status the Download microcode status dpage is fetch with the RECEIVE DIAGNOSTIC RESULTS command and decoded. .SH WHEN THE DOWNLOAD FAILS Firstly, if it succeeds, this utility should stay silent and return. Typically vendors will change the "revision" string (which is 4 characters long) whenever they release new firmware. That can be seen in the response to a SCSI INQUIRY command, for example by using the sg_inq utility. It is possible that the device needs to be power cycled before the new microcode becomes active. Also if mode dmc_offs_defer [0xe] is used to download the microcode, then another invocation with activate_mc may be needed. .PP If something goes wrong, there will typically be messages printed out by this utility. The first thing to check is the microcode (firmware) file itself. Is it designed for the device model; has it been corrupted, and if downgrading (i.e. trying to re-instate older firmware), does the vendor allow that? .PP Getting new firmware on a device is a delicate operation that is not always well defined by T10's standards and drafts. One might speculate that they are deliberately vague. In testing this utility one vendor's interpretation of the standard was somewhat surprising. The \fI\-\-non\fR option was added to cope with their interpretation. So if the above suggestions don't help, try adding the \fI\-\-non\fR option. .SH NOTES This utility can handle a maximum size of 128 MB of microcode which should be sufficient for most purposes. In a system that is memory constrained, such large allocations of memory may fail. .PP The user should be aware that most operating systems have limits on the amount of data that can be sent with one SCSI command. In Linux this depends on the pass through mechanism used (e.g. block SG_IO or the sg driver) and various setting in sysfs in the Linux lk 2.6/3 series (e.g. /sys/block/sda/queue/max_sectors_kb). Devices (i.e. logical units) also typically have limits on the maximum amount of data they can handle in one command. These two limitations suggest that modes containing the word "offset" together with the \fI\-\-bpw=CS\fR option are required as firmware files get larger and larger. And \fICS\fR can be quite small, for example 4096 bytes, resulting in many SEND DIAGNOSTIC commands being sent. .PP The exact error from the non\-standard implementation was a sense key of ILLEGAL REQUEST and an asc/ascq code of 0x26,0x0 which is "Invalid field in parameter list". If that is seen try again with the \fI\-\-non\fR option. .PP Downloading incorrect microcode into a device has the ability to render that device inoperable. One would hope that the device vendor verifies the data before activating it. .PP A long (operating system) timeout of 7200 seconds is set on each SEND DIAGNOSTIC command. .PP All numbers given with options are assumed to be decimal. Alternatively numerical values can be given in hexadecimal preceded by either "0x" or "0X" (or has a trailing "h" or "H"). .SH EXAMPLES If no microcode/firmware file is given then this utility fetches and decodes the Download microcode status dpage which could possibly show another initiator in the process of updating the microcode. Even if that is happening, fetching the status page should not cause any problems: .PP sg_ses_microcode /dev/sg3 .br Download microcode status diagnostic page: .br number of secondary subenclosures: 0 .br generation code: 0x0 .br subenclosure identifier: 0 [primary] .br download microcode status: No download microcode operation in progress [0x0] .br download microcode additional status: 0x0 .br download microcode maximum size: 1048576 bytes .br download microcode expected buffer id: 0x0 .br download microcode expected buffer id offset: 0 .PP The following sends new microcode/firmware to an enclosure. Sending a 1.5 MB file in one command caused the enclosure to lock up temporarily and did not update the firmware. Breaking the firmware file into 4 KB chunks (an educated guess) was more successful: .PP sg_ses_microcode \-b 4k \-m dmc_offs_save \-I firmware.bin /dev/sg4 .PP The firmware update occurred in the following enclosure power cycle. With a modern enclosure the Extended Inquiry VPD page gives indications in which situations a firmware upgrade will take place. .SH EXIT STATUS The exit status of sg_ses_microcode is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_ses, sg_write_buffer(sg3_utils) sg3_utils-1.40/doc/sginfo.80000664000175000017500000003163512271755144014513 0ustar douggdougg.TH SGINFO "8" "January 2014" "sg3_utils\-1.38" SG3_UTILS .SH NAME sginfo \- access mode page information for a SCSI (or ATAPI) device .SH SYNOPSIS .B sginfo [\fIOPTIONS\fR] [\fIDEVICE\fR] [\fIREPLACEMENT_PARAMETERS\fR] .SH DESCRIPTION .\" Add any additional description here .PP sginfo is a port of the Linux .B scsiinfo program by Eric Youngdale. It uses SCSI generic (sg) devices; however in some cases the high level device name (i.e. sd, sr, st, osst, or hd) can also be used. The primary role of this program is to access mode page information. If permitted, mode page information can be altered. In addition information from the INQUIRY and READ DEFECTS commands are also available. .PP This utility is in legacy mode, only obvious bugs will be fixed. Options like \fI\-l\fR (to list devices) are broken in recent versions of Linux (e.g. 2.6 series and later); the lsscsi(8) utility can be used instead. Also mode pages are not being updated as http://www.t10.org adds and modifies mode page fields. Those interested in SCSI mode pages may find the .B sdparm utility more up to date and easier use, especially for changing parameters. .PP Four sets of values are maintained by a SCSI device for each mode page: current (active), default (manufacturer's supplied values), saved (values that are retained if the SCSI device is powered down), and changeable (mask indicating those values that can be changed). By default when a mode page is displayed the current values are shown. This can be overridden by "\-M" (defaults), "\-S" (saved) or "\-m" (modifiable (i.e. changeable)). .PP Many mode pages are decoded: for disks (see SBC\-2), for CD/DVDs (see MMC\-2/3/4/5), for tapes (see SSC\-2) and for enclosures (see SES\-2). Some mode pages common to all SCSI peripheral device types are defined in SPC\-4 (primary commands). A decoded mode page has its field names in the first column and the corresponding value in the second column. A "hex" mode page (and subpage) has its byte position in the first column (in hex and starting at 0x2) and the corresponding hex value in the second column. Decoded pages can be viewed with the '\-t' option or with a specific option (e.g. 'c' for the caching mode page). Naturally decoded pages must be supplied by the \fIDEVICE\fR and recognised by this program. If supported by the device, decoded pages may be modified. All mode pages (and subpages) that the device supports can be viewed in hex (and potentially modified) via the "\-u" option .PP If no options are given that will cause mode page(s) or INQUIRY data to be printed out, then a brief INQUIRY response is output. This includes the vendor, product and revision level of the device. .SH OPTIONS .TP \fB\-6\fR Perform 6 byte MODE SENSE and MODE SELECT commands; by default the 10 byte variants are used. .TP \fB\-a\fR Display some INQUIRY data and the unit serial number followed by all mode pages reported by the device. It is similar to the '\-t 0x3f' option. If the mode page is known then it is output in decoded form otherwise it is output in hexadecimal. .TP \fB\-A\fR Display some INQUIRY data and the unit serial number followed by all mode pages and all mode subpages reported by the device. It is similar to the '\-t 0x3f,0xff' option. If a mode (sub)page is known then it is output in decoded form otherwise it is output in hexadecimal. .TP \fB\-c\fR Access information in the Caching mode page. .TP \fB\-C\fR Access information in the Control mode Page. .TP \fB\-d\fR Display defect lists (default format: index). .TP \fB\-D\fR Access information in the Disconnect\-Reconnect mode page. .TP \fB\-e\fR Access information in the Error Recovery mode page. .TP \fB\-E\fR Access information in the Control Extension mode page. .TP \fB\-f\fR Access information in the Format Device mode page. .TP \fB\-F\fR\fIarg\fR Format of the defect lists: \-Flogical \- logical block addresses (32 bit) \-Flba64 \- logical block addresses (64 bit) \-Fphysical \- physical blocks \-Findex \- defect bytes from index \-Fhead \- sort by head .br Used in conjunction with "\-d" or "\-G". If a format is not given "index" is assumed. .TP \fB\-g\fR Access information in the Rigid Disk Drive Geometry mode page. .TP \fB\-G\fR Display grown defect list (default format: index). .TP \fB\-i\fR Display the response to a standard INQUIRY command. .TP \fB\-I\fR Access the Informational Exceptions mode page. .TP \fB\-l\fR Deprecated. Only use in old versions of Linux (e.g. 2.4 and earlier). Please use lsscsi(8) in the Linux 2.6 series and later. List known SCSI devices on the system. .TP \fB\-n\fR Access information in the Notch and Partition mode page. .TP \fB\-N\fR Negate (i.e. stop) mode page changes being placed in the "saved" page (by default changes go to the current and the saved page). Only active when used together with '\-R'. .TP \fB\-P\fR Access information in the Power Condition mode page. .TP \fB\-r\fR Display all raw (or primary) SCSI device names visible in the /dev directory. Examples are /dev/sda, /dev/st1 and /dev/scd2. Does not list sg device names so devices such as a SCSI enclosure which only have an sg device name are not listed. .TP \fB\-s\fR Display information in the unit serial number page which is a INQUIRY command variant. .TP \fB\-t\fR \fIPN\fR[,\fISPN\fR] Display information from mode page number \fIPN\fR (and optionally sub page number \fISPN\fR) in decoded format (if known, otherwise in hex form). \fIPN\fR is a mode page number in a decimal number from 0 to 63 inclusive. \fISPN\fR is the mode subpage number and is assumed to be 0 if not given. \fISPN\fR is a decimal number from 1 to 255 inclusive. A page number of 63 returns all pages supported by the device in ascending order except for page 0 which, if present, is last. Page 0 is vendor specific and not necessarily in mode page format. Alternatively hex values can be given for both \fIPN\fR and \fISPN\fR (both prefixed by '0x'). .TP \fB\-T\fR Trace commands to obtain more verbose output (for debugging). When used once SCSI commands are shown (in hex) and any errors from these SCSI commands are spelt out (i.e. with a decoded and raw sense buffer). When used twice, the additional data sent with mode select and the response from mode sense are shown (in hex). .TP \fB\-u\fR \fIPN\fR[,\fISPN\fR] Display information from mode page number \fIPN\fR (and optionally \fISPN\fR) in hex form. \fIPN\fR is a mode page number in a decimal number from 0 to 63 inclusive. \fISPN\fR is the mode subpage number and is assumed to be 0 if not given. \fISPN\fR is a decimal number from 1 to 255 inclusive. A page number of 63 returns all pages supported by the device in ascending order except for page 0 which, if present, is last. Page 0 is vendor specific and not necessarily in mode page format. Alternatively hex values can be given for both \fIPN\fR and \fISPN\fR (both prefixed by '0x'). For example 63 and 0x3f are equivalent. .TP \fB\-v\fR Display version string then exit. [N.B. This option increases verbosity for most other utilities in this package as outlined in 'man 8 sg3_utils'. This odd usage is for backward compatibility with the scsiinfo utility.] .TP \fB\-V\fR Access information in the Verify Error Recovery mode page. [N.B. This option prints the version string then exits in most other utilities in this package as outlined in 'man 8 sg3_utils'. This odd usage is for backward compatibility with the scsiinfo utility.] .TP \fB\-z\fR do a single fetch for mode pages (over\-estimating the expected length of the returned response). The default action is to do a double fetch, the first fetch is to find the response length that could be returned. Devices that closely adhere to SCSI standards should not require this option, some real world devices do require it. .SH ADVANCED OPTIONS Only one of the following three options can be specified. None of these three implies the current values are returned. .TP \fB\-m\fR Display modifiable fields instead of current values .TP \fB\-M\fR Display manufacturer's defaults instead of current values .TP \fB\-S\fR Display saved defaults instead of current values .PP The following are advanced options, not generally suited for most users: .TP \fB\-X\fR Display output values in a list. Make them suitable for editing and being given back to the '\-R' (replace command). .TP \fB\\-R\fR Replace parameters \- best used with \-X (expert use only) .SH CHANGING MODE PAGE PARAMETERS Firstly you should know what you are doing before changing existing parameters. Taking the control page as an example, first list it out normally (e.g. "sginfo \-C /dev/sda") and decide which parameter is to be changed (note its position relative to the other lines output). Then execute the same sginfo command with the "\-X" option added; this will output the parameter values in a single row in the same relative positions as the previous command. Now execute "sginfo \-CXR /dev/sda ..." with the "..." replaced by the single row of values output by the previous command, with the relevant parameter changed. Here is a simplified example: .PP $ sginfo \-C /dev/sda .br Control mode page (0xa) .br \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .br TST 0 .br D_SENSE 0 .br GLTSD 1 .br RLEC 0 .PP [Actually the Control page has more parameters that shown above.] Next output those parameters in single line form: .PP $ sginfo \-CX /dev/sda .br 0 0 1 0 .PP Let us assume that the GLTSD bit is to be cleared. The command that will clear it is: .PP $ sginfo \-CXR /dev/sda 0 0 0 0 .PP The same number of parameters output by the "\-CX" command needs to be placed at the end of the "\-CXR" command line (after the device name). Now check that the change took effect: .PP $ sginfo \-C /dev/sda .br Control mode page (0xa) .br \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .br TST 0 .br D_SENSE 0 .br GLTSD 0 .br RLEC 0 .PP When a mode page is "replaced" the default action is to change both the current page and the saved page. [For some reason versions of sginfo and scsiinfo prior to 2.0 did not change the "saved" page.] To change only the current mode page but not the corresponding saved page use the "\-N" option. .PP .SH GENERATING SCRIPT FILES AND HEX PAGES The "\-aX" or "\-AX" option generates output suitable for a script file. Mode pages are output in list format (after the INQUIRY and serial number) one page per line. To facilitate running the output as (part of) a script file to assert chosen mode page values, each line is prefixed by "sginfo \-t \fIPN\fR[,\fISPN\fR] \-XR ". When such a script file is run, it will have the effect of re\-asserting the mode page values to what they were when the "\-aX" generated the output. .PP All mode pages (and subpages) supported by the device can be accessed via the \-t and \-u options. To see all mode pages supported by the device use "\-u 63". [To see all mode pages and all subpages use "\-u 63,255".] To list the control mode page in hex (mode page index in the first column and the corresponding byte value in the second column) use "\-u 0xa". Mode pages (subpage code == 0) start at index position 2 while subpages start at index position 4. If the "\-Xu ..." option is used then a list a hex values each value prefixed by "@" is output. Mode (sub)page values can then be modified with the "\-RXu ..." option. .PP .SH RESTRICTIONS The SCSI MODE SENSE command yields block descriptors as well as a mode page(s). This utility ignores block descriptors and does not display them. The "disable block descriptor" switch (DBD) in the MODE SENSE command is not set since some devices yield errors when it is set. When mode page values are being changed (the "\-R" option), the same block descriptor obtained by reading the mode page (i.e. via a MODE SENSE command) is sent back when the mode page is written (i.e. via a MODE SELECT command). .PP .SH REFERENCES SCSI (draft) standards can be found at http://www.t10.org . The relevant documents are SPC\-4 (mode pages common to all device types), SBC\-2 (direct access devices [e.g. disks]), MMC\-4 (CDs and DVDs) and SSC\-2 (tapes). .PP .SH AUTHORS Written by Eric Youngdale, Michael Weller, Douglas Gilbert, Kurt Garloff, Thomas Steudten .PP .SH HISTORY scsiinfo version 1.0 was released by Eric Youngdale on 1st November 1993. The most recent version of scsiinfo is version 1.7 with the last patches by Michael Weller. sginfo is derived from scsiinfo and uses the sg interface to get around the 4 KB buffer limit in scsiinfo that cramped the display of defect lists especially. sginfo was written by Douglas Gilbert with patches from Kurt Garloff. This manpage corresponds with version 2.25 of sginfo. .PP This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B lsscsi(lsscsi), scsiinfo(internet); sg_modes, sg_inq, sg_vpd (sg3_utils), .B sdparm(sdparm) sg3_utils-1.40/doc/scsi_ready.80000664000175000017500000000260712144707462015347 0ustar douggdougg.TH SCSI_READY "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_ready \- do SCSI TEST UNIT READY on devices .SH SYNOPSIS .B scsi_ready [\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls the sg_turs utility on each given \fIDEVICE\fR. This will send a SCSI TEST UNIT READY command to each \fIDEVICE\fR. Disks, tape drives and DVD/BD players amongst others may respond to this SCSI command. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR for each \fIDEVICE\fR given output a line containing either ' ready' or ' device not ready'. If \fIDEVICE\fR is not found or there is another serious error then an error message will appear instead. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Otherwise the exit status is that of the last sg_turs utility called. See the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2009\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_turs (sg3_utils) sg3_utils-1.40/doc/sg_luns.80000664000175000017500000002537212345113227014671 0ustar douggdougg.TH SG_LUNS "8" "June" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_luns \- send SCSI REPORT LUNS command or decode given LUN .SH SYNOPSIS .B sg_luns [\fI\-\-decode\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-linux\fR] [\fI\-\-lu_cong\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-quiet\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-select=SR\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_luns \fI\-\-test=ALUN\fR [\fI\-\-hex\fR] [\fI\-\-lu_cong\fR] [\fI\-\-verbose\fR] .SH DESCRIPTION .\" Add any additional description here .PP In the first form shown in the SYNOPSIS this utility sends the SCSI REPORT LUNS command to the \fIDEVICE\fR and outputs the response. The response should be a list of LUNs ("a LUN inventory") for the I_T nexus associated with the \fIDEVICE\fR. Roughly speaking that is all LUNs that share the target device that the REPORT LUNS command is sent through. In the SPC\-3 and SPC\-4 SCSI standards support for the REPORT LUNS command is mandatory. .PP When the \fI\-\-test=ALUN\fR option is given (the second form in the SYNOPSIS), then the \fIALUN\fR value is decoded as outlined in SAM\-3, SAM\-4 and SAM\-5 (revision 13, section 4.7) . .PP Where required below the first form shown in the SYNOPSIS is called "device mode" and the second form is called "test mode". .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-decode\fR decode LUNs into their component parts, as described in the LUN section of SAM\-3, SAM\-4 and SAM\-5. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR [device mode] when given once this utility will output the SCSI response (i.e. the data\-out buffer) to the REPORT LUNS command in ASCII hex then exit. When given twice it causes \fI\-\-decode\fR to output component fields in hex rather than decimal. .br [test mode] when this option is given, then decoded component fields of \fIALUN\fR are output in hex. .TP \fB\-l\fR, \fB\-\-linux\fR this option is only available in Linux. After the T10 representation of each 64 bit LUN (in 16 hexadecimal digits), if this option is given then to the right, in square brackets, is the Linux LUN integer in decimal. If the \fI\-\-hex\fR option is given twice (e.g. \-HH) as well then the Linux LUN integer is output in hexadecimal. .TP \fB\-L\fR, \fB\-\-lu_cong\fR this option is only considered with \fI\-\-decode\fR. When given once then the list of LUNs is decoded as if the LU_CONG bit was set in each LU's coresponding INQUIRY response. When given twice the list of LUNs is decoded as if the LU_CONG bit was clear in each LU's coresponding INQUIRY response. When this option is not given and \fI\-\-decode\fR is given then an INQUIRY is sent to the \fIDEVICE\fR and the setting of its LU_CONG bit is used to decode the list of LUNs. .br [test mode] decode \fIALUN\fR as if the LU_CONG bit is set in its corresponding standard INQUIRY response. In other words treat \fIALUN\fR as if it is a conglomerate LUN. If not given (or given twice) then decode \fIALUN\fR as if the LU_CONG bit is clear. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given (or \fILEN\fR is zero) then 8192 is used. The maximum allowed value of \fILEN\fR is 1048576. .TP \fB\-q\fR, \fB\-\-quiet\fR output only the ASCII hex rendering of each report LUN, one per line. Without the \fI\-\-quiet\fR option, there is header information printed before the LUN listing. .TP \fB\-r\fR, \fB\-\-raw\fR output the SCSI response (i.e. the data-out buffer) in binary (to stdout). .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-s\fR, \fB\-\-select\fR=\fISR\fR \fISR\fR is placed in the SELECT REPORT field of the SCSI REPORT LUNS command. The default value is 0. Hexadecimal values may be given with a leading "0x" or a trailing "h". For detailed information see the REPORT LUNS command in SPC (most recent is SPC\-4 revision 37 in section 6.33). To simplify, for the I_T nexus associated with the \fIDEVICE\fR, the meanings of the \fISR\fR values defined to date for SPC\-4 are: .br \fB0\fR : most luns excluding well known logical unit numbers .br \fB1\fR : well known logical unit numbers .br \fB2\fR : all luns accessible to this I_T nexus .br \fB0x10\fR : only accessible administrative luns .br \fB0x11\fR : administrative luns plus non-conglomerate luns (see SPC\-4) .br \fB0x12\fR : if \fIDEVICE\fR is an administrative LU, then report its .br lun plus its subsidiary luns .PP For \fISR\fR values 0x10 and 0x11, the \fIDEVICE\fR must be either LUN 0 or the REPORT LUNS well known logical unit. Values between 0xf8 and 0xff (inclusive) are vendor specific, other values are reserved. This utility will accept any value between 0 and 255 (0xff) for \fISR\fR . .TP \fB\-t\fR, \fB\-\-test\fR=\fIALUN\fR \fIALUN\fR is assumed to be a hexadecimal number in ASCII hex or the letter 'L' followed by a decimal number (see below). The hexadecimal number can be up to 64 bits in size (i.e. 16 hexadecimal digits) and is padded to the right if less than 16 hexadecimal digits are given (e.g. \fI\-\-test=0122003a\fR represents T10 LUN 0122003a00000000). \fIALUN\fR may be prefixed by '0x' or '0X' (e.g. the previous example could have been \fI\-\-test=0x0122003a\fR). \fIALUN\fR may also be given with spaces or tabs between each byte (or other grouping) but then \fIALUN\fR would need to be surrounded by single or double quotes. In the decimal number case (i.e. following a 'L') that number is assumed to be a Linux "word flipped" LUN which is converted into a T10 LUN representation and printed. In both cases the number is interpreted as a LUN and decoded as if the \fI\-\-decode\fR option had been given. Also when \fIALUN\fR is a hexadecimal number it can have a trailing 'L' in which case the corresponding Linux "word flipped" LUN value is output. The LUN is decoded in all cases. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES The SCSI REPORT LUNS command is important for Logical Unit (LU) discovery. After a target device is discovered (usually via some transport specific mechanism), a REPORT LUNS command should either be sent to LUN 0 (which is Peripheral device addressing method with bus_id=0 and target/lun=0) or to the REPORT LUNS well known LUN (i.e. 0xc101000000000000). SAM\-5 requires that one of these responds with an inventory of LUNS that are contained in this target device. .PP In test mode, if the \fI\-\-hex\fR option is given once then in the decoded output, some of the component fields are printed in hex with leading zeros. The leading zeros are to indicate the size of the component field. For example: in the Peripheral device addressing method (16 bits overall), the bus ID is 6 bits wide and the target/LUN field is 8 bits wide; so both are shown with two hex digits (e.g. bus_id=0x02, target=0x3a). .SH EXAMPLES Typically by the time user space programs get to run, SCSI LUs have been discovered. In Linux the lsscsi utility lists the LUs that are currently present. The LUN of a device (LU) is the fourth element in the tuple at the beginning of each line. Below we see a target (or "I_T Nexus": "6:0:0") has two LUNS: 1 and 49409. If 49409 is converted into T10 LUN format it is 0xc101000000000000 which is the REPORT LUNS well known LUN. .PP # lsscsi \-g .br [6:0:0:1] disk Linux scsi_debug 0004 /dev/sdb /dev/sg1 .br [6:0:0:2] disk Linux scsi_debug 0004 /dev/sdc /dev/sg2 .br [6:0:0:49409]wlun Linux scsi_debug 0004 \- /dev/sg3 .PP We could send a REPORT LUNS command (with \fISR\fR 0x0, 0x1 or 0x2) to any of those file device nodes and get the same result. Below we use /dev/sg1 : .PP # sg_luns /dev/sg1 .br Lun list length = 16 which imples 2 lun entry .br Report luns [select_report=0x0]: .br 0001000000000000 .br 0002000000000000 .PP That is a bit noisy so cut down the clutter with \fI\-\-quiet\fR: .PP # sg_luns \-q /dev/sg1 .br 0001000000000000 .br 0002000000000000 .PP Now decode that LUN into its component parts: .PP # sg_luns \-d \-q /dev/sg1 .br 0001000000000000 .br Peripheral device addressing: lun=1 .br 0002000000000000 .br Peripheral device addressing: lun=2 .PP Now use \fI\-\-select=1\fR to find out if there are any well known LUNs: .PP # sg_luns \-q \-s 1 /dev/sg1 .br c101000000000000 .PP So how many LUNs do we have all together (associated with the current I_T Nexus): .PP # sg_luns \-q \-s 2 /dev/sg1 .br 0001000000000000 .br 0002000000000000 .br c101000000000000 .PP # sg_luns \-q \-s 2 \-d /dev/sg1 .br 0001000000000000 .br Peripheral device addressing: lun=1 .br 0002000000000000 .br Peripheral device addressing: lun=1 .br c101000000000000 .br REPORT LUNS well known logical unit .PP The following example uses the \fI\-\-linux\fR option and is not available in other operating systems. The extra number in square brackets is the Linux version of T10 LUN shown at the start of the line. .PP # sg_luns \-q \-s 2 \-l /dev/sg1 .br 0001000000000000 [1] .br 0002000000000000 [2] .br c101000000000000 [49409] .PP Now we use the \fI\-\-test=\fR option to decode LUNS input on the command line (rather than send a REPORT LUNS command and act on the response): .PP # sg_luns \-\-test=0002000000000000 .br Decoded LUN: .br Peripheral device addressing: lun=2 .PP # sg_luns \-\-test="c1 01" .br Decoded LUN: .br REPORT LUNS well known logical unit .PP # sg_luns \-t 0x023a004b \-H .br Decoded LUN: .br Peripheral device addressing: bus_id=0x02, target=0x3a .br >>Second level addressing: .br Peripheral device addressing: lun=0x4b .PP The next example is Linux specific as we try to find out what the Linux LUN 49409 translates to in the T10 world: .PP # sg_luns \-\-test=L49409 .br 64 bit LUN in T10 preferred (hex) format: c1 01 00 00 00 00 00 00 .br Decoded LUN: .br REPORT LUNS well known logical unit .PP And the mapping between T10 and Linux LUN representations can be done the other way: .PP # sg_luns \-t c101L .br Linux 'word flipped' integer LUN representation: 49409 .br Decoded LUN: .br REPORT LUNS well known logical unit .br .SH EXIT STATUS The exit status of sg_luns is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(8) sg3_utils-1.40/doc/sg_write_same.80000664000175000017500000003601012375500134016036 0ustar douggdougg.TH SG_WRITE_SAME "8" "August 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_write_same \- send SCSI WRITE SAME command .SH SYNOPSIS .B sg_write_same [\fI\-\-10\fR] [\fI\-\-16\fR] [\fI\-\-32\fR] [\fI\-\-anchor\fR] [\fI\-\-grpnum=GN\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-lbdata\fR] [\fI\-\-pbdata\fR] [\fI\-\-num=NUM\fR] [\fI\-\-ndob\fR] [\fI\-\-timeout=TO\fR] [\fI\-\-unmap\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-wrprotect=WPR\fR] [\fI\-\-xferlen=LEN\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here Send the SCSI WRITE SAME (10, 16 or 32 byte) command to \fIDEVICE\fR. This command writes the given block \fINUM\fR times to consecutive blocks on the \fIDEVICE\fR starting at logical block address \fILBA\fR. .PP SBC\-3 revision 35d introduced a "no data-out buffer" (NDOB) bit which, if set, bypasses the requirement to send a single block of data to the \fIDEVICE\fR together with the command. Only WRITE SAME (16 and 32 byte) support the NDOB bit. .PP The length of the block to be written multiple times is obtained from either the \fILEN\fR argument, or the length of the given input file \fIIF\fR, or by calling READ CAPACITY(16) on \fIDEVICE\fR. The contents of the block to be written are obtained from the input file \fIIF\fR or zeros are used. If READ CAPACITY(16) is called (which implies \fIIF\fR was not given) and the PROT_EN bit is set then an extra 8 bytes (i.e. more than the logical block size) of 0xff are sent. If READ CAPACITY(16) fails then READ CAPACITY(10) is used to determine the block size. .PP If neither \fI\-\-10\fR, \fI\-\-16\fR nor \fI\-\-32\fR is given then WRITE SAME(10) is sent unless one of the following conditions is met. If \fILBA\fR (plus \fINUM\fR) exceeds 32 bits, \fINUM\fR exceeds 65535, or the \fI\-\-unmap\fR option is given then WRITE SAME(16) is sent. The \fI\-\-10\fR, \fI\-\-16\fR and \fI\-\-32\fR options are mutually exclusive. .PP In SBC\-3 revision 26 the UNMAP and ANCHOR bits were added to the WRITE SAME (10) command. Since the UNMAP bit has been in WRITE SAME (16) and WRITE SAME (32) since SBC\-3 revision 18, the lower of the two (i.e. WRITE SAME (16)) is the default when the \fI\-\-unmap\fR option is given. To send WRITE SAME (10) use the \fI\-\-10\fR option. .PP .B Take care: The WRITE SAME(10, 16 and 32) commands interpret a \fINUM\fR of zero as write to the end of \fIDEVICE\fR. This utility defaults \fINUM\fR to 1 . The WRITE SAME commands have no IMMED bit so if \fINUM\fR is large (or zero) then an invocation of this utility could take a long time, potentially as long as a FORMAT UNIT command. In such situations the command timeout value \fITO\fR may need to be increased from its default value of 60 seconds. In SBC\-3 revision 26 the WSNZ (write same no zero) bit was added to the Block Limits VPD page [0xB0]. If set the WRITE SAME commands will not accept a \fINUM\fR of zero. The same SBC\-3 revision added the "Maximum Write Same Length" field to the Block Limits VPD page. .PP The Logical Block Provisioning VPD page [0xB2] contains the LBWS and LBW10 bits. If LBWS is set then WRITE SAME (16) supports the UNMAP bit. If LBWS10 is set then WRITE SAME (10) supports the UNMAP bit. If either LBWS or LBWS10 is set and the WRITE SAME (32) is supported then WRITE SAME (32) supports the UNMAP bit. This is as of SBC\-3 revision 26. .PP As a precaution against an accidental 'sg_write_same /dev/sda' (for example) overwriting LBA 0 on /dev/sda with zeros, at least one of the \fI\-\-in=IF\fR, \fI\-\-lba=LBA\fR or \fI\-\-num=NUM\fR options must be given. Obviously this utility can destroy a lot of user data so check the options carefully. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-R\fR, \fB\-\-10\fR send a SCSI WRITE SAME (10) command to \fIDEVICE\fR. The ability to set the \fI\-\-unmap\fR (and \fI\-\-anchor\fR) options to this command was added in SBC\-3 revision 26. .TP \fB\-S\fR, \fB\-\-16\fR send a SCSI WRITE SAME (16) command to \fIDEVICE\fR. .TP \fB\-T\fR, \fB\-\-32\fR send a SCSI WRITE SAME (32) command to \fIDEVICE\fR. .TP \fB\-a\fR, \fB\-\-anchor\fR sets the ANCHOR bit in the cdb. Introduced in SBC\-3 revision 22. That draft requires the \fI\-\-unmap\fR option to also be specified. .TP \fB\-g\fR, \fB\-\-grpnum\fR=\fIGN\fR sets the 'Group number' field to \fIGN\fR. Defaults to a value of zero. \fIGN\fR should be a value between 0 and 31. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR read data (binary) from file named \fIIF\fR and use it as the data out buffer for the SCSI WRITE SAME command. The length of the data out buffer is \fI\-\-xferlen=LEN\fR or, if that is not given, the length of the \fIIF\fR file. If \fIIF\fR is "\-" then stdin is read. If this option is not given then 0x00 bytes are used as fill with the length of the data out buffer obtained from \fI\-\-xferlen=LEN\fR or by calling READ CAPACITY(16 or 10). If the response to READ CAPACITY(16) has the PROT_EN bit set then data out buffer size is modified accordingly with the last 8 bytes set to 0xff. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the logical block address to start the WRITE SAME command. Defaults to lba 0 which is a dangerous block to overwrite on a disk that is in use. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h'. .TP \fB\-L\fR, \fB\-\-lbdata\fR sets the LBDATA bit in the WRITE SAME cdb. .TP \fB\-N\fR, \fB\-\-ndob\fR sets the NDOB bit in the WRITE SAME (16 and 32 byte) commands. Default is to clear this bit. When this option is given then \fI\-\-in=IF\fR is not allowed and \fI\-\-xferlen=LEN\fR can only be given if \fILEN\fR is 0 . .TP \fB\-n\fR, \fB\-\-num\fR=\fINUM\fR where \fINUM\fR is the number of blocks, starting at \fILBA\fR, to write the data out buffer to. The default value for \fINUM\fR is 1. The value corresponds to the 'Number of logical blocks' field in the WRITE SAME cdb. Note that a value of 0 in \fINUM\fR is interpreted as write the data out buffer on every block starting at \fILBA\fR to the end of the \fIDEVICE\fR. .TP \fB\-P\fR, \fB\-\-pbdata\fR sets the PBDATA bit in the WRITE SAME cdb. .TP \fB\-t\fR, \fB\-\-timeout\fR=\fITO\fR where \fITO\fR is the command timeout value in seconds. The default value is 60 seconds. If \fINUM\fR is large (or zero) a WRITE SAME command may require considerably more time than 60 seconds to complete. .TP \fB\-U\fR, \fB\-\-unmap\fR sets the UNMAP bit in the WRITE SAME(10, 16 and 32) cdb. See UNMAP section below. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR output version string then exit. .TP \fB\-w\fR, \fB\-\-wrprotect\fR=\fIWPR\fR sets the "Write protect" field in the WRITE SAME cdb to \fIWPR\fR. The default value is zero. \fIWPR\fR should be a value between 0 and 7. When \fIWPR\fR is 1 or greater, and the disk's protection type is 1 or greater, then 8 extra bytes of protection information are expected or generated (to place in the command's data out buffer). .TP \fB\-x\fR, \fB\-\-xferlen\fR=\fILEN\fR where \fILEN\fR is the data out buffer length. Defaults to the length of the \fIIF\fR file or, if that is not given, then the READ CAPACITY(16 or 10) command is used to find the 'Logical block length in bytes'. That figure may be increased by 8 bytes if the \fIDEVICE\fR's protection type is 1 or greater and the WRPROTECT field (see \fI\-\-wrprotect=WPR\fR) is 1 or greater. If both this option and the \fIIF\fR option are given and \fILEN\fR exceeds the length of the \fIIF\fR file then \fILEN\fR is the data out buffer length with zeros used as pad bytes. .SH UNMAP Logical block provisioning is a new term introduced in SBC\-3 revision 25 for the ability to mark blocks as unused. For large storage arrays, it is a way to provision less physical storage than the READ CAPACITY command reports is available, potentially allocating more physical storage when WRITE commands require it. For flash memory (e.g. SSD drives) it is a way of potentially saving power (and perhaps access time) when it is known large sections (or almost all) of the flash memory is not in use. SSDs need wear levelling algorithms to have acceptable endurance and typically over provision to simplify those algorithms; hence they typically contain more physical flash storage than their logical size would dictate. .PP Support for logical block provisioning is indicated by the LBPME bit being set in the READ CAPACITY(16) command response (see the sg_readcap utility). That implies at least one of the UNMAP or WRITE SAME(16) commands is implemented. If the UNMAP command is implemented then the "Maximum unmap LBA count" and "Maximum unmap block descriptor count" fields in the Block Limits VPD page should both be greater than zero. The READ CAPACITY(16) command response also contains a LBPRZ bit which if set means that if unmapped blocks are read then zeros will be returned for the data (and if protection information is active, 0xff bytes are returned for that). In SBC\-3 revision 27 the same LBPRZ bit was added to the Logical Block Provisioning VPD page. .PP In SBC\-3 revision 25 the LBPU and ANC_SUP bits where added to the Logical Block Provisioning VPD page. When LBPU is set it indicates that the device supports the UNMAP command (see the sg_unmap utility). When the ANC_SUP bit is set it indicates the device supports anchored LBAs. .PP When the UNMAP bit is set in the cdb then the data out buffer is also sent. Additionally the data section of that data out buffer should be full of 0x0 bytes while the data protection block, 8 bytes at the end if present, should be set to 0xff bytes. If these conditions are not met and the LBPRZ bit is set then the UNMAP bit is ignored and the data out buffer is written to the \fIDEVICE\fR as if the UNMAP bit was zero. In the absence of the \fI\-\-in=IF\fR option, this utility will attempt build a data out buffer that meets the requirements for the UNMAP bit in the cdb to be acted on by the \fIDEVICE\fR. .PP Logical blocks may also be unmapped by the SCSI UNMAP and FORMAT UNIT commands (see the sg_unmap and sg_format utilities). .PP The unmap capability in SCSI is closely related to the ATA DATA SET MANAGEMENT command with the "Trim" bit set. That ATA trim capability does not interact well with SATA command queueing known as NCQ. T13 have introduced a new command called the SFQ DATA SET MANAGEMENT command also with a the "Trim" bit to address that problem. The SCSI WRITE SAME with the UNMAP bit set and the UNMAP commands do not have any problems with SCSI queueing. .SH NOTES Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP In Linux at this time the sg driver does not support cdb sizes greater than 16 bytes. [This restriction will be removed in lk 3.17 .] Hence a device node like /dev/sg1 which is associated with the sg driver will fail with this utility if the \fI\-\-32\fR option is given (or implied by other options). The bsg driver with device nodes like /dev/bsg/6:0:0:1 does support cdb sizes greater than 16 bytes. .SH EXIT STATUS The exit status of sg_write_same is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH EXAMPLES One simple usage is to write blocks of zero from (and including) a given LBA: .PP sg_write_same \-\-lba=0x1234 \-\-num=63 /dev/sdc .PP Since \fI\-\-xferlen=LEN\fR has not been given, then this utility will call the READ CAPACITY command on /dev/sdc to determine the number of bytes in a logical block. Let us assume that is 512 bytes. Since \fI\-\-in=IF\fR is not given a block of zeros is assumed. So 63 blocks of zeros (each block containing 512 bytes) will be written from (and including) LBA 0x1234 . Note that only one block of zeros is passed to the SCSI WRITE SAME command in the data out buffer (as required by SBC\-3). .PP A similar example follows but in this case the blocks are "unmapped" ("trimmed" in ATA speak) rather than zeroed: .PP sg_write_same \-\-unmap \-L 0x1234 \-n 63 /dev/sdc .PP Note that if the LBPRZ bit in the READ CAPACITY(16) response is set (i.e. LPPRZ is an acronym for logical block provisioning read zeros) then these two examples do the same thing, at least seen from the point of view of subsequent reads. .PP This utility can also be used to write protection information (PI) on disks formatted with a protection type greater than zero. PI is 8 bytes of extra data appended to the user data of a logical block: the first two bytes are a CRC (the "guard"), the next two bytes are the "application tag" and the last four bytes are the "reference tag". With protection types 1 and 2 if the application tag is 0xffff then the guard should not be checked (against the user data). .PP In this example we assume the logical block size (of the user data) is 512 bytes and the disk has been formatted with protection type 1. Since we are going to modify LBA 2468 then we take a copy of it first: .PP dd if=/dev/sdb skip=2468 bs=512 of=2468.bin count=1 .PP The following command line sets the user data to zeros and the PI to 8 0xFF bytes on LBA 2468: .PP sg_write_same \-\-lba=2468 /dev/sdb .PP Reading back that block should be successful because the application tag is 0xffff which suppresses the guard (CRC) check (which would otherwise be wrong): .PP dd if=/dev/sdb skip=2468 bs=512 of=/dev/null count=1 .PP Now an attempt is made to create a binary file with zeros in the user data, 0x0000 in the application tag and 0xff bytes in the other two PI fields. It is awkward to create 0xff bytes in a file (in Unix) as the "tr" command below shows: .PP dd if=/dev/zero bs=1 count=512 of=ud.bin .br tr "\\000" "\\377" < /dev/zero | dd bs=1 of=ff_s.bin count=8 .br cat ud.bin ff_s.bin > lb.bin .br dd if=/dev/zero bs=1 count=2 seek=514 conv=notrunc of=lb.bin .PP The resulting file can be viewed with 'hexdump \-C lb.bin' and should contain 520 bytes. Now that file can be written to LBA 2468 as follows: .PP sg_write_same \-\-lba=2468 wrprotect=3 \-\-in=lb.bin /dev/sdb .PP Note the \fI\-\-wrprotect=3\fR rather than being set to 1, since we want the WRITE SAME command to succeed even though the PI data now indicates the user data is corrupted. When an attempt is made to read the LBA, an error should occur: .PP dd if=/dev/sdb skip=2468 bs=512 of=/dev/null count=1 .PP dd errors are not very expressive, if dmesg is checked there should be a line something like this: "[sdb] Add. Sense: Logical block guard check failed". The block can be corrected by doing a "sg_write_same \-\-lba=1234 /dev/sdb" again or restoring the original contents of that LBA: .PP dd if=2468.bin bs=512 seek=2468 of=/dev/sdb conv=notrunc count=1 .PP Hopefully the dd command would never try to truncate the output file when it is a block device. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_format,sg_get_lba_status,sg_readcap,sg_vpd,sg_unmap(sg3_utils) sg3_utils-1.40/doc/sg_wr_mode.80000664000175000017500000002244412053021257015336 0ustar douggdougg.TH SG_WR_MODE "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_wr_mode \- write (modify) SCSI mode page .SH SYNOPSIS .B sg_wr_mode [\fI\-\-contents=H,H...\fR] [\fI\-\-dbd\fR] [\fI\-\-force\fR] [\fI\-\-help\fR] [\fI\-\-len=\fR10|6\fR] [\fI\-\-mask=M,M...\fR] [\fI\-\-page=PG[,SPG]\fR] [\fI\-\-save\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Writes a modified mode page to \fIDEVICE\fR. Uses the SCSI MODE SENSE (6 or 10 byte variant) command to fetch the existing mode data which includes a mode page (or subpage). It then combines that with the contents, potentially masked, and writes the modified mode page with the SCSI MODE SELECT (6 or 10 byte variant) command. This utility does not modify the block descriptor(s); if any block descriptors are fetched by the MODE SENSE command then the same block descriptors are written back with the following MODE SELECT command. .PP If a contents argument is not given then the various components (i.e. header, block descriptor(s) and mode page) of the "current" values of the existing mode page are printed out. In this case the mode page is not altered on the device. .PP If the contents are specified, and a mask is not specified, then the contents must match the existing mode page in various aspects unless the \fI\-\-force\fR option is given. These include length, mode page code and subpage code if applicable. If all is well then the contents string is written to \fIDEVICE\fR as the new mode page. .PP If both contents and mask strings are specified then only bit positions in the contents corresponding to set bits in the mask are taken while the existing mode page supplies bit positions corresponding to clear bits. When a mask is given then the mask and/or the contents may be shorter than the existing mode page. If the mask is shorter than the contents then the remaining bytes are taken from the contents. If the contents are shorter than the existing mode page then the remaining bytes are taken from the existing mod page. .PP The force option allows the contents string to be written as the new mode page without any prior checks on the existing mode page. This should only be required for vendor specific mode pages. The existing mode data is ignored apart from the block descriptors which can be suppressed with the \fI\-\-dbd\fR option if need be. .PP Changing individual fields in a mode page is probably more easily done with the sdparm utility. Fields can be identified by acronym or by a numerical descriptor. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-contents\fR=\fIH,H...\fR where \fIH,H...\fR is a string of comma separated hex numbers each of which should resolve to a byte value (i.e. 0 to ff inclusive). A (single) space separated string of hex numbers is also allowed but the list needs to be in quotes. This is the new contents of the mode page to be written to \fIDEVICE\fR, potentially filtered by the mask string. .TP \fB\-c\fR, \fB\-\-contents\fR=- reads contents string from stdin. The hex numbers in the string may be comma, space, tab or linefeed (newline) separated. If a line contains "#" then the remaining characters on that line are ignored. Otherwise each non separator character should resolve to a byte value (i.e. 0 to ff inclusive). This forms the new contents of the mode page to be written to \fIDEVICE\fR, potentially filtered by the mask string. .TP \fB\-d\fR, \fB\-\-dbd\fR disable block descriptors (DBD flag in cdb). Some device types include block descriptors in the mode data returned by a MODE SENSE command. If so the same block descriptors are written by the MODE SELECT command. This option instructs the MODE SENSE command not to return any block descriptors. This would be a sensible default for this utility apart from the fact that not all SCSI devices support the DBD bit in the cdb. .TP \fB\-f\fR, \fB\-\-force\fR force the contents string to be taken as the new mode page, or at least doesn't do checks on the existing mode page. Note that \fIDEVICE\fR may still reject the new contents for the mode page. Cannot be given with the \fI\-\-mask=M,M...\fR option. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-l\fR, \fB\-\-len\fR=10 | 6 length of the SCSI commands (cdb) sent to \fIDEVICE\fR. The default is 10 so 10 byte MODE SENSE and MODE SELECT commands are issued. Some old devices don't support the 10 byte variants hence this option. .TP \fB\-m\fR, \fB\-\-mask\fR=\fIM,M...\fR where \fIM,M...\fR is a string of comma separated hex numbers each of which should resolve to a byte value (i.e. 0 to ff inclusive). A (single) space separated string of hex numbers is also allowed but the list needs to be in quotes. The mask chooses (bit by bit) whether the new mode page comes from the contents (mask bit set) or from the existing mode page (mask bit clear). If the mask string is shorter than the contents string then the remaining bytes are taken from the contents string. If the contents string is shorter than the existing mode page then the remaining bytes are taken from the existing mode page (i.e. they are left unaltered). .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR where \fIPG\fR is the page code value to fetch and modify. The page code is in hex and should be between 0 and 3e inclusive. Notice that page code 3f to fetch all mode pages is disallowed. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG,SPG\fR where \fIPG\fR is the page code value and \fISPG\fR is the subpage code value to fetch and modify. Both values are in hex. The subpage code should be between 0 and fe inclusive. Notice that subpage code ff to fetch all mode subpages (for a given mode page or all mode pages in the case of 3f,ff) is disallowed. .TP \fB\-s\fR, \fB\-\-save\fR changes the "saved" mode page when MODE SELECT is successful. By default (i.e. when \fI\-\-save\fR is not used) only the "current" mode page values are changed when MODE SELECT is successful. In this case the new mode page will stay in effect until the device is reset (e.g. power cycled). When it restarts the "saved" values for the mode page will be re\-instated. So to make changes permanent use the \fI\-\-save\fR option. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES This utility does not check whether the contents string is trying to modify parts of the mode page which are changeable. The device should do that and if some part is not changeable then it should report: "Invalid field in parameter list". .PP Some mode pages are not saveable. If so an attempt to use the \fI\-\-save\fR option should cause an error to be reported from the device: "Illegal field in cdb". .PP The device is required to do various checks before it accepts a new mode page. If these checks fail then the mode page is not altered and either a "parameter list length error" or an "invalid field in parameter list" error is returned by the device in the sense data. .PP The recommended way to modify a mode page is to read it with a MODE SENSE, modify some part of it then write it back to the device with a MODE SELECT command. For example, reading an existing mode page can be accomplished with 'sg_modes \-p=1a \-r /dev/sdb > mp_1a.txt' (the power condition mode page). The mp_1a.txt file can be edited and then used as the contents string to this utility (e.g. 'sg_wr_mode \-p 1a \-s \-c \- /dev/sdb < mp_1a.txt'). .PP Two fields differ between what is read from the device with MODE SENSE and what is written to the device with MODE SELECT: the mode data length is reserved (i.e. zero(es)) in a MODE SELECT command while the PS bit ((sub)page byte 0 bit 7) in each mode (sub)page is reserved (zero) in a MODE SELECT command. The PS bit given in the contents string is zeroed unless the \fI\-\-force\fR option is selected. .SH EXAMPLES This utility can be used together with the sg_modes utility. To re\-instate the default mode page values (i.e. the mode page values chosen by the manufacturer of the device) as both the current and saved mode page values the following sequence could be used: .PP $ sg_modes \-\-control=2 \-\-page=1a \-r /dev/sda > t .br $ sg_wr_mode \-\-page=1a \-\-contents=\- \-\-save /dev/sda < t .PP Next is an example of using a mask to modify the "idle condition counter" of the "power condition" mode page (0x1a) from 0x28 to 0x37. Note that the change is not saved so the "idle condition counter" will revert to 0x28 after the next power cycle. The output from sg_modes is abridged. .PP $ sg_modes \-\-page=1a /dev/hdc .br >> Power condition (mmc), page_control: current .br 00 1a 0a 00 03 00 00 00 28 00 00 01 2c .PP $ sg_wr_mode \-p 1a \-c 0,0,0,0,0,0,0,37 \-m 0,0,0,0,0,0,0,ff /dev/hdc .PP $ sg_modes \-p 1a /dev/hdc .br >> Power condition (mmc), page_control: current .br 00 1a 0a 00 03 00 00 00 37 00 00 01 2c .SH EXIT STATUS The exit status of sg_wr_mode is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sdparm(sdparm), sg_modes(sg3_utils), sginfo(sg3_utils) sg3_utils-1.40/doc/sg_get_lba_status.80000664000175000017500000000736112334207341016705 0ustar douggdougg.TH SG_GET_LBA_STATUS "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_get_lba_status \- send SCSI GET LBA STATUS command .SH SYNOPSIS .B sg_get_lba_status [\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send the SCSI GET LBA STATUS command to the \fIDEVICE\fR and outputs the response. This command was introduced in (draft) SBC\-3 revision 20 and devices that support logical block provisioning should support this command. .PP The default action is to decode the response into one LBA status descriptor per line output to stdout. The descriptor LBA is output in hex (prefixed by '0x') and the number of blocks is output in decimal followed by the provisioning status in decimal. The provisioning status can be in the range 0 to 15 of which only 0 (mapped), 1 (unmapped) and 2 (anchored) are used currently. The amount of output can be reduced by the \fI\-\-brief\fR option. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-brief\fR when use once then one LBA status descriptor per line is output to stdout. Each line has this format: "0x 0x ". So the descriptor's starting LBA and number of blocks are output in hex and the provisioning status in decimal. When used twice (e.g. '\-bb' or '\-\-brief \-\-brief') then the provisioning status of the given \fILBA\fR (or LBA 0 if the \fI\-\-lba\fR option is not given) is output to stdout. A check is made that the given \fILBA\fR lies in the range of the first returned LBA status descriptor (as it should according to SBC\-3 revision 20) and warnings are sent to stderr if it doesn't. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output response to this command in ASCII hex. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the starting Logical Block Address (LBA) to check the provisioning status for. Note that the \fIDEVICE\fR chooses how many following blocks that it will return provisioning status for. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given then 24 is used. 24 is enough space for the response header and one LBA status descriptor. \fILEN\fR should be 8 plus a multiple of 16 (e.g. 24, 40, and 56 are suitable). .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary (to stdout). .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). Additional output caused by this option is sent to stderr. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES In SBC\-3 revision 25 the calculation associated with the Parameter Data Length field in the response was modified. Prior to that the byte offset was 8 and in revision 25 it was changed to 4. .PP For a discussion of logical block provisioning see section 4.7 of sbc3r29.pdf at http://www.t10.org (or the corresponding section of a later draft). .SH EXIT STATUS The exit status of sg_get_lba_status is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2009\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_write_same(8), sg_unmap(8) sg3_utils-1.40/doc/sg_turs.80000664000175000017500000001133412334207341014675 0ustar douggdougg.TH SG_TURS "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_turs \- send one or more SCSI TEST UNIT READY commands .SH SYNOPSIS .B sg_turs [\fI\-\-help\fR] [\fI\-\-number=NUM\fR] [\fI\-\-progress\fR] [\fI\-\-time\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_turs [\fI\-n=NUM\fR] [\fI\-p\fR] [\fI\-t\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends one or more SCSI TEST UNIT READY commands to the \fIDEVICE\fR. This may be useful for timing the per command overhead. Note that TEST UNIT READY has no associated data, just a 6 byte command and a returned SCSI status value. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-n\fR, \fB\-\-number\fR=\fINUM\fR performs TEST UNIT READY \fINUM\fR times. If not given defaults to 1. These suffix multipliers are permitted: c C *1; w W *2; b B *512; k K KiB *1,024; KB *1,000; m M MiB *1,048,576; MB *1,000,000; g G GiB *1,073,741,824; and GB *1,000,000,000 . Also a suffix of the form "x" multiplies the leading number by . Alternatively a hex number may be given, prefixed by either '0x' or has a trailing 'h'. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-progress\fR show progress indication (a percentage) if available. If \fI\-\-number=NUM\fR is given, \fINUM\fR is greater than 1 and an initial progress indication was detected then this utility waits 30 seconds before subsequent checks. Exits when \fINUM\fR is reached or there are no more progress indications. Ignores \fI\-\-time\fR option. See NOTES section below. .TP \fB\-t\fR, \fB\-\-time\fR after completing the requested number of TEST UNIT READY commands, outputs the total duration and the average number of commands executed per second. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print version string then exit. .SH NOTES The progress indication is optionally part of the sense data. When a prior command that takes a long time to complete (and typically precludes other media access commands) is still underway, the progress indication can be used to determine how long before the device returns to its normal state. .PP The SCSI FORMAT command for disks used with the IMMED bit set is an example of an operation that takes a significant amount of time and precludes other media access during that time. The IMMED bit set instructs the FORMAT command to return control to the application client once the format has commenced (see SBC\-3). Several long duration SCSI commands associated with tape drives also use the progress indication (see SSC\-3). .PP The \fIDEVICE\fR is opened with a read\-only flag (e.g. in Unix with the O_RDONLY flag). .PP Early standards suggested that the SCSI TEST UNIT READY command be used for polling the progress indication. More recent standards seem to suggest the SCSI REQUEST SENSE command should be used instead. .SH EXIT STATUS The exit status of sg_turs is 0 when it is successful (e.g. in the case of a mechanical disk, it is spun up and ready to accept commands). For this utility the other exit status of interest is 2 corresponding to the "not ready" sense key. For other exit status values see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-n\fR=\fINUM\fR performs TEST UNIT READY \fINUM\fR times. If not given defaults to 1. Equivalent to \fI\-\-number=NUM\fR in the main description. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-p\fR show progress indication (a percentage) if available. Equivalent to \fI\-\-progress\fR in the main description. .TP \fB\-t\fR after completing the requested number of TEST UNIT READY commands, outputs the total duration and the average number of commands executed per second. Equivalent to \fI\-\-time\fR in the main description. .TP \fB\-v\fR increase level of verbosity. .TP \fB\-V\fR print out version string then exit. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2000\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq, sg_request (sg3_utils) sg3_utils-1.40/doc/sg_readcap.80000664000175000017500000001637012333156560015311 0ustar douggdougg.TH SG_READCAP "8" "May 2014" "sg3_utils\-1.39" SG3_UTILS .SH NAME sg_readcap \- send SCSI READ CAPACITY command .SH SYNOPSIS .B sg_readcap [\fI\-\-16\fR] [\fI\-\-brief\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-long\fR] [\fI\-\-pmi\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_readcap [\fI\-16\fR] [\fI\-b\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-lba=LBA\fR] [\fI\-pmi\fR] [\fI\-r\fR] [\fI\-R\fR] [\fI\-v\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP The normal action of the SCSI READ CAPACITY command is to fetch the number of blocks (and block size) from the \fIDEVICE\fR. .PP The SCSI READ CAPACITY command (both 10 and 16 byte cdbs) actually yield the block address of the last block and the block size. The number of blocks is thus one plus the block address of the last block (as blocks are counted origin zero (i.e. starting at block zero)). This is the source of many "off by one" errors. .PP The READ CAPACITY(16) response provides additional information not found in the READ CAPACITY(10) response. This includes protection and logical block provisioning information, plus the number of logical blocks per physical block. So even though the media size may not exceed what READ CAPACITY(10) can show, it may still be useful to examine the response to READ CAPACITY(16). Sadly there are horrible SCSI command set implementations in the wild that crash when the READ CAPACITY(16) command is sent to them. .PP Device capacity is the product of the number of blocks by the block size. This utility outputs this figure in bytes, MiB (1048576 bytes per MiB) and GB (1000000000 bytes per GB). .PP If sg_readcap is called without the \fI\-\-long\fR option then the 10 byte cdb version (i.e. READ CAPACITY (10)) is sent to the \fIDEVICE\fR. If the number of blocks in the response is reported as 0xffffffff (i.e. (2**32 \- 1) ) and the \fI\-\-hex\fR option has not been given, then READ CAPACITY (16) is called and its response is output. .PP This utility supports two command line syntaxes, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP .TP \fB\-\-16\fR Use the 16 byte cdb variant of the READ CAPACITY command. See the '\-\-long' option. \fB\-b\fR, \fB\-\-brief\fR outputs two hex numbers (prefixed with '0x' and space separated) to stdout. The first number is the maximum number of blocks on the device (which is one plus the lba of the last accessible block). The second number is the size in bytes of each block. If the operation fails then "0x0 0x0" is written to stdout. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the response to the READ CAPACITY command (either the 10 or 16 byte cdb variant) in ASCII hexadecimal on stdout. .TP \fB\-L\fR, \fB\-\-lba\fR=\fILBA\fR used in conjunction with \fI\-\-pmi\fR option. This variant of READ CAPACITY will yield the last block address after \fILBA\fR prior to a delay. For a disk, given a \fILBA\fR it yields the highest numbered block on the same cylinder (i.e. before the heads need to move). \fILBA\fR is assumed to be decimal unless prefixed by "0x" or it has a trailing "h". Defaults to 0. This option was made obsolete in SBC\-3 revision 26. .TP \fB\-l\fR, \fB\-\-long\fR Use the 16 byte cdb variant of the READ CAPACITY command. The default action is to use the 10 byte cdb variant which limits the maximum block address to (2**32 \- 2). When a 10 byte cdb READ CAPACITY command is used on a device whose size is too large then a last block address of 0xffffffff is returned (if the device complies with SBC\-2 or later). .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-pmi\fR partial medium indicator: for finding the next block address prior to some delay (e.g. head movement). In the absence of this option, the total number of blocks and the block size of the device are output. Used in conjunction with the \fI\-\-lba=LBA\fR option. This option was made obsolete in SBC\-3 revision 26. .TP \fB\-r\fR, \fB\-\-raw\fR output response in binary to stdout. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default for READ CAPACITY(16) is to open it read\-write. The default for READ CAPACITY(10) is to open it read\-only so this option does not change anything for this case. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR outputs version string then exits. .SH NOTES In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_readcap /dev/sda" and "sg_readcap /dev/hdd" (if /dev/hdd is a ATAPI CD/DVD device) will work in the 2.6 series kernels. .SH EXIT STATUS The exit status of sg_readcap is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-16\fR Use the 16 byte cdb variant of the READ CAPACITY command. Equivalent to \fI\-\-long\fR in the main description. .TP \fB\-b\fR utility outputs two hex numbers (prefixed with '0x' and space separated) to stdout. The first number is the maximum number of blocks on the device (which is one plus the lba of the last accessible block). The second number is the size of each block. If the operation fails then "0x0 0x0" is written to stdout. Equivalent to \fI\-\-brief\fR in the main description. .TP \fB\-h\fR output the usage message then exit. Giving the \fI\-?\fR option also outputs the usage message then exits. .TP \fB\-H\fR output the response to the READ CAPACITY command (either the 10 or 16 byte cdb variant) in ASCII hexadecimal on stdout. .TP \fB\-lba\fR=\fILBA\fR used in conjunction with \fI\-pmi\fR option. This variant of READ CAPACITY will yield the last block address after \fILBA\fR prior to a delay. Equivalent to \fI\-\-lba=LBA\fR in the main description. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-pmi\fR partial medium indicator: for finding the next block address prior to some delay (e.g. head movement). In the absence of this switch, the total number of blocks and the block size of the device are output. Equivalent to \fI\-\-pmi\fR in the main description. .TP \fB\-r\fR output response in binary (to stdout). .TP \fB\-R\fR Equivalent to \fI\-\-readonly\fR in the main description. .TP \fB\-v\fR verbose: print out cdb of issued commands prior to execution. '\-vv' and '\-vvv' are also accepted yielding greater verbosity. .TP \fB\-V\fR outputs version string then exits. .SH AUTHORS Written by Douglas Gilbert .SH COPYRIGHT Copyright \(co 1999\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq(sg3_utils) sg3_utils-1.40/doc/sg_dd.80000664000175000017500000005464312163345600014302 0ustar douggdougg.TH SG_DD "8" "June 2013" "sg3_utils\-1.37" SG3_UTILS .SH NAME sg_dd \- copy data to and from files and devices, especially SCSI devices .SH SYNOPSIS .B sg_dd [\fIbs=BS\fR] [\fIconv=CONV\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR] [\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .PP [\fIblk_sgio=\fR{0|1}] [\fIbpt=BPT\fR] [\fIcdbsz=\fR{6|10|12|16}] [\fIcoe=\fR{0|1|2|3}] [\fIcoe_limit=CL\fR] [\fIdio=\fR{0|1}] [\fIodir=\fR{0|1}] [\fIof2=OFILE2\fR] [\fIretries=RETR\fR] [\fIsync=\fR{0|1}] [\fItime=\fR{0|1}] [\fIverbose=VERB\fR] [\fI\-V\fR] .SH DESCRIPTION .\" Add any additional description here .PP Copy data to and from any files. Specialized for "files" that are Linux SCSI generic (sg) devices, raw devices or other devices that support the SG_IO ioctl (which are only found in the lk 2.6 series). Similar syntax and semantics to .B dd(1) command. .PP The first group in the synopsis above are "standard" Unix .B dd(1) operands. The second group are extra options added by this utility. Both groups are defined below. .PP This utility is only supported on Linux whereas most other utilities in the sg3_utils package have been ported to other operating systems. A utility called "ddpt" has similar syntax and functionality to sg_dd. ddpt drops some Linux specific features while adding some other generic features. This allows ddpt to be ported to other operating systems. .SH OPTIONS .TP \fBblk_sgio\fR={0|1} when set to 0, block devices (e.g. /dev/sda) are treated like normal files (i.e. .B read(2) and .B write(2) are used for IO). When set to 1, block devices are assumed to accept the SG_IO ioctl and SCSI commands are issued for IO. This is only supported for 2.6 series kernels. Note that ATAPI devices (e.g. cd/dvd players) use the SCSI command set but ATA disks do not (unless there is a protocol conversion as often occurs in the USB mass storage class). If the input or output device is a block device partition (e.g. /dev/sda3) then setting this option causes the partition information to be ignored (since access is directly to the underlying device). Default is 0. See the 'sgio' flag. .TP \fBbpt\fR=\fIBPT\fR each IO transaction will be made using \fIBPT\fR blocks (or less if near the end of the copy). Default is 128 for block sizes less that 2048 bytes, otherwise the default is 32. So for bs=512 the reads and writes will each convey 64 KiB of data by default (less if near the end of the transfer or memory restrictions). When cd/dvd drives are accessed, the block size is typically 2048 bytes and bpt defaults to 32 which again implies 64 KiB transfers. The block layer when the blk_sgio=1 option is used has relatively low upper limits for transfer sizes (compared to sg device nodes, see /sys/block//queue/max_sectors_kb ). .TP \fBbs\fR=\fIBS\fR where \fIBS\fR .B must be the block size of the physical device (if either the input or output files are accessed via SCSI commands). Note that this differs from .B dd(1) which permits \fIBS\fR to be an integral multiple. Default is 512 which is usually correct for disks but incorrect for cdroms (which normally have 2048 byte blocks). For this utility the maximum size of each individual IO operation is \fIBS\fR * \fIBPT\fR bytes. .TP \fBcdbsz\fR={6|10|12|16} size of SCSI READ and/or WRITE commands issued on sg device names (or block devices when 'iflag=sgio' and/or 'oflag=sgio' is given). Default is 10 byte SCSI command blocks (unless calculations indicate that a 4 byte block number may be exceeded or \fIBPT\fR is greater than 16 bits (65535), in which case it defaults to 16 byte SCSI commands). .TP \fBcoe\fR={0|1|2|3} set to 1 or more for continue on error. Only applies to errors on sg devices or block devices with the 'sgio' flag set. Thus errors on other files will stop sg_dd. Default is 0 which implies stop on any error. See the 'coe' flag for more information. .TP \fBcoe_limit\fR=\fICL\fR where \fICL\fR is the maximum number of consecutive bad blocks stepped over (due to "coe>0") on reads before the copy terminates. This only applies when \fIIFILE\fR is accessed via the SG_IO ioctl. The default is 0 which is interpreted as no limit. This option is meant to stop the copy soon after unrecorded media is detected while still offering "continue on error" capability. .TP \fBconv\fR=\fBsparse\fR see the CONVERSIONS section below. .TP \fBcount\fR=\fICOUNT\fR copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices report from SCSI READ CAPACITY commands or that block devices (or their partitions) report. Normal files are not probed for their size. If \fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e. not explicitly given) then the derived count is scaled back so that the copy will not overrun the device. If the file name is a block device partition and \fICOUNT\fR is not given then the size of the partition rather than the size of the whole device is used. If \fICOUNT\fR is not given (or \fIcount=\-1\fR) and cannot be derived then an error message is issued and no copy takes place. .TP \fBdio\fR={0|1} default is 0 which selects indirect (buffered) IO on sg devices. Value of 1 attempts direct IO which, if not available, falls back to indirect IO and notes this at completion. If direct IO is selected and /proc/scsi/sg/allow_dio has the value of 0 then a warning is issued (and indirect IO is performed). For finer grain control use 'iflag=dio' or 'oflag=dio'. .TP \fBibs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBif\fR=\fIIFILE\fR read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR is given. .TP \fBiflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIIFILE\fR and are ignored when \fIIFILE\fR is stdin. .TP \fBobs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBodir\fR={0|1} when set to one opens block devices (e.g. /dev/sda) with the O_DIRECT flag. User memory buffers are aligned to the page size when set. The default is 0 (i.e. the O_DIRECT flag is not used). Has no effect on sg, normal or raw files. If blk_sgio is also set then both are honoured: block devices are opened with the O_DIRECT flag and SCSI commands are issued via the SG_IO ioctl. .TP \fBof\fR=\fIOFILE\fR write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed. If \fIOFILE\fR is '.' (period) then it is treated the same way as /dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it is _not_ truncated; it is overwritten from the start of \fIOFILE\fR unless 'oflag=append' or \fISEEK\fR is given. .TP \fBof2\fR=\fIOFILE2\fR write output to \fIOFILE2\fR. The default action is not to do this additional write (i.e. when this option is not given). \fIOFILE2\fR is assumed to be a normal file or a fifo (i.e. a named pipe). \fIOFILE2\fR is opened for writing, created if necessary, and closed at the end of the transfer. If \fIOFILE2\fR is a fifo (named pipe) then some other command should be consuming that data (e.g. 'md5sum OFILE2'), otherwise this utility will block. .TP \fBoflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIOFILE\fR and are ignored when \fIOFILE\fR is /dev/null, '.' (period), or stdout. .TP \fBretries\fR=\fIRETR\fR sometimes retries at the host are useful, for example when there is a transport error. When \fIRETR\fR is greater than zero then SCSI READs and WRITEs are retried on error, \fIRETR\fR times. Default value is zero. .TP \fBseek\fR=\fISEEK\fR start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR. Default is block 0 (i.e. start of file). .TP \fBskip\fR=\fISKIP\fR start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR. Default is block 0 (i.e. start of file). .TP \fBsync\fR={0|1} when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the transfer. Only active when \fIOFILE\fR is a sg device file name or a block device and 'blk_sgio=1' is given. .TP \fBtime\fR={0|1} when 1, times transfer and does throughput calculation, outputting the results (to stderr) at completion. When 0 (default) doesn't perform timing. .TP \fBverbose\fR=\fIVERB\fR as \fIVERB\fR increases so does the amount of debug output sent to stderr. Default value is zero which yields the minimum amount of debug output. A value of 1 reports extra information that is not repetitive. A value 2 reports cdbs and responses for SCSI commands that are not repetitive (i.e. other that READ and WRITE). Error processing is not considered repetitive. Values of 3 and 4 yield output for all SCSI commands (and Unix read() and write() calls) so there can be a lot of output. This only occurs for scsi generic (sg) devices and block devices when the 'blk_sgio=1' option is set. .TP \fB\-\-help\fR outputs usage message and exits. .TP \fB\-\-version\fR outputs version number information and exits. .TP \fB\-V\fR outputs version number information and exits. .SH CONVERSIONS One or more conversions can be given to the "conv=" option. If more than one is given, they should be comma separated. sg_dd does not perform the traditional dd conversions (e.g. ASCII to EBCDIC). Recently added conversions overlap somewhat with the flags so some conversions are now supported by sg_dd. .TP noerror this conversion is very close to "iflag=coe" and is treated as such. See the "coe" flag. Note that an error on \fIOFILE\fR will stop the copy. .TP notrunc this conversion is accepted for compatibilty with dd and ignored since the default action of this utility is not to truncate \fIOFILE\fR. .TP null has no affect, just a placeholder. .TP sparse FreeBSD supports "conv=sparse" so the same syntax is supported in sg_dd. See "sparse" in the FLAGS sections for more information. .TP sync is ignored by sg_dd. With dd it means supply zero fill (rather than skip) and is typically used like this "conv=noerror,sync" to have the same functionality as sg_dd's "iflag=coe". .SH FLAGS Here is a list of flags and their meanings: .TP append causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For regular files this will lead to data appended to the end of any existing data. Cannot be used together with the \fIseek=SEEK\fR option as they conflict. The default action of this utility is to overwrite any existing data from the beginning of the file or, if \fISEEK\fR is given, starting at block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g. a disk) will usually be ignored or may cause an error to be reported. .TP coe continue on error. Only active for sg devices and block devices that have the 'sgio' flag set. 'iflag=coe oflag=coe' and 'coe=1' are equivalent. Use this flag twice (e.g. 'iflag=coe,coe') to have the same action as the 'coe=2'. A medium, hardware or blank check error while reading will re\-read blocks prior to the bad block, then try to recover the bad block, supplying zeros if that fails, and finally reread the blocks after the bad block. A medium, hardware or blank check error while writing is noted and ignored. The recovery of the bad block when reading uses the SCSI READ LONG command if 'coe' given twice or more (also with the command line option 'coe=2'). Further, the READ LONG will set its CORRCT bit if 'coe' given thrice. SCSI disks may automatically try and remap faulty sectors (see the AWRE and ARRE in the read write error recovery mode page (the sdparm utility can access and possibly change these attributes)). Errors occurring on other files types will stop sg_dd. Error messages are sent to stderr. This flag is similar o 'conv=noerror,sync' in the .B dd(1) utility. See note about READ LONG below. .TP dio request the sg device node associated with this flag does direct IO. If direct IO is not available, falls back to indirect IO and notes this at completion. If direct IO is selected and /proc/scsi/sg/allow_dio has the value of 0 then a warning is issued (and indirect IO is performed). .TP direct causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. This flag requires some memory alignment on IO. Hence user memory buffers are aligned to the page size. Has no effect on sg, normal or raw files. If 'iflag=sgio' and/or 'oflag=sgio' is also set then both are honoured: block devices are opened with the O_DIRECT flag and SCSI commands are issued via the SG_IO ioctl. .TP dpo set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not supported for 6 byte cdb variants of READ and WRITE. Indicates that data is unlikely to be required to stay in device (e.g. disk) cache. May speed media copy and/or cause a media copy to have less impact on other device users. .TP dsync causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. The 'd' is prepended to lower confusion with the 'sync=0|1' option which has another action (i.e. a synchronisation to media at the end of the transfer). .TP excl causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. .TP flock after opening the associated file (i.e. \fIIFILE\fR and/or \fIOFILE\fR) an attempt is made to get an advisory exclusive lock with the flock() system call. The flock arguments are "FLOCK_EX | FLOCK_NB" which will cause the lock to be taken if available else a "temporarily unavailable" error is generated. An exit status of 90 is produced in the latter case and no copy is done. .TP fua causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE commands. This only has an effect with sg devices or block devices that have the 'sgio' flag set. The 6 byte variants of the SCSI READ and WRITE commands do not support the FUA bit. .TP nocache use posix_fadvise() to advise corresponding file there is no need to fill the file buffer with recently read or written blocks. .TP null has no affect, just a placeholder. .TP sgio causes block devices to be accessed via the SG_IO ioctl rather than standard UNIX read() and write() commands. When the SG_IO ioctl is used the SCSI READ and WRITE commands are used directly to move data. sg devices always use the SG_IO ioctl. This flag offers finer grain control compared to the otherwise identical 'blk_sgio=1' option. .TP sparse after each \fIBS\fR * \fIBPT\fR byte segment is read from the input, it is checked for being all zeros. If so, nothing is written to the output file unless this is the last segment of the transfer. This flag is only active with the oflag option. It cannot be used when the output is not seekable (e.g. stdout). It is ignored if the output file is /dev/null . Note that this utility does not remove the \fIOFILE\fR prior to starting to write to it. Hence it may be advantageous to manually remove the \fIOFILE\fR if it is large prior to using oflag=sparse. The last segment is always written so regular files will show the same length and so programs like md5sum and sha1sum will generate the same value regardless of whether oflag=sparse is given or not. This option may be used when the \fIOFILE\fR is a raw device but is probably only useful if the device is known to contain zeros (e.g. a SCSI disk after a FORMAT command). .SH RETIRED OPTIONS Here are some retired options that are still present: .TP append=0 | 1 when set, equivalent to 'oflag=append'. When clear the action is to overwrite the existing file (if it exists); this is the default. See the 'append' flag. .TP fua=0 | 1 | 2 | 3 force unit access bit. When 3, fua is set on both \fIIFILE\fR and \fIOFILE\fR; when 2, fua is set on \fIIFILE\fR;, when 1, fua is set on \fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag. .SH NOTES Block devices (e.g. /dev/sda and /dev/hda) can be given for \fIIFILE\fR. If neither '\-iflag=direct', 'iflag=sgio' nor 'blk_sgio=1' is given then normal block IO involving buffering and caching is performed. If only '\-iflag=direct' is given then the buffering and caching is bypassed (this is applicable to both SCSI devices and ATA disks). If 'iflag=sgio' or 'blk_sgio=1' is given then the SG_IO ioctl is used on the given file causing SCSI commands to be sent to the device and that also bypasses most of the actions performed by the block layer (this is only applicable to SCSI devices, not ATA disks). The same applies for block devices given for \fIOFILE\fR. .PP Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR arguments can take 64 bit values (i.e. very big numbers). Other values are limited to what can fit in a signed 32 bit number. .PP Data usually gets to the user space in a 2 stage process: first the SCSI adapter DMAs into kernel buffers and then the sg driver copies this data into user memory (write operations reverse this sequence). This is called "indirect IO" and there is a 'dio' option to select "direct IO" which will DMA directly into user memory. Due to some issues "direct IO" is disabled in the sg driver and needs a configuration change to activate it. This is typically done with 'echo 1 > /proc/scsi/sg/allow_dio'. .PP All informative, warning and error output is sent to stderr so that dd's output file can be stdout and remain unpolluted. If no options are given, then the usage message is output and nothing else happens. .PP Even if READ LONG succeeds on a "bad" block when 'coe=2' (or 'coe=3') is given, the recovered data may not be useful. There are no guarantees that the user data will appear "as is" in the first 512 bytes. .PP A raw device must be bound to a block device prior to using sg_dd. See .B raw(8) for more information about binding raw devices. To be safe, the sg device mapping to SCSI block devices should be checked with 'cat /proc/scsi/scsi', or sg_map before use. .PP Disk partition information can often be found with .B fdisk(8) [the "\-ul" argument is useful in this respect]. .PP For sg devices (and block devices when blk_sgio=1 is given) this utility issues SCSI READ and WRITE (SBC) commands which are appropriate for disks and reading from CD/DVD/HD\-DVD/BD drives. Those commands are not formatted correctly for tape devices so sg_dd should not be used on tape devices. If the largest block address of the requested transfer exceeds a 32 bit block number (i.e 0xffff) then a warning is issued and the sg device is accessed via SCSI READ(16) and WRITE(16) commands. .PP The attributes of a block device (partition) are ignored when 'blk_sgio=1' is used. Hence the whole device is read (rather than just the second partition) by this invocation: .PP sg_dd if=/dev/sdb2 blk_sgio=1 of=t bs=512 .SH EXAMPLES .PP Looks quite similar in usage to dd: .PP sg_dd if=/dev/sg0 of=t bs=512 count=1MB .PP This will copy 1 million 512 byte blocks from the device associated with /dev/sg0 (which should have 512 byte blocks) to a file called t. Assuming /dev/sda and /dev/sg0 are the same device then the above is equivalent to: .PP dd if=/dev/sda iflag=direct of=t bs=512 count=1000000 .PP although dd's speed may improve if bs was larger and count was suitably reduced. The use of the 'iflag=direct' option bypasses the buffering and caching that is usually done on a block device. .PP Using a raw device to do something similar on a ATA disk: .PP raw /dev/raw/raw1 /dev/hda .br sg_dd if=/dev/raw/raw1 of=t bs=512 count=1MB .PP To copy a SCSI disk partition to an ATA disk partition: .PP raw /dev/raw/raw2 /dev/hda3 .br sg_dd if=/dev/sg0 skip=10123456 of=/dev/raw/raw2 bs=512 .PP This assumes a valid partition is found on the SCSI disk at the given skip block address (past the 5 GB point of that disk) and that the partition goes to the end of the SCSI disk. An explicit count is probably a safer option. The partition is copied to /dev/hda3 which is an offset into the ATA disk /dev/hda . The exact number of blocks read from /dev/sg0 are written to /dev/hda (i.e. no padding). .PP To time a streaming read of the first 1 GB (2 ** 30 bytes) on a disk this utility could be used: .PP sg_dd if=/dev/sg0 of=/dev/null bs=512 count=2m time=1 .PP On completion this will output a line like: "time to transfer data was 18.779506 secs, 57.18 MB/sec". The "MB/sec" in this case is 1,000,000 bytes per second. .PP The 'of2=' option can be used to copy data and take a md5sum of it without needing to re\-read the data: .PP mkfifo fif .br md5sum fif & .br sg_dd if=/dev/sg3 iflag=coe of=sg3.img oflag=sparse of2=fif bs=512 .PP This will image /dev/sg3 (e.g. an unmounted disk) and place the contents in the (sparse) file sg3.img . Without re\-reading the data it will also perform a md5sum calculation on the image. .SH SIGNALS The signal handling has been borrowed from dd: SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred and the records in + out counts; then they have their default action. SIGUSR1 causes the same information to be output yet the copy continues. All output caused by signals is sent to stderr. .SH EXIT STATUS The exit status of sg_dd is 0 when it is successful. Otherwise see the sg3_utils(8) man page. Since this utility works at a higher level than individual commands, and there are 'coe' and 'retries' flags, individual SCSI command failures do not necessary cause the process to exit. .PP An additional exit status of 90 is generated if the flock flag is given and some other process holds the advisory exclusive lock. .SH AUTHORS Written by Douglas Gilbert and Peter Allworth. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2013 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" There is a web page discussing sg_dd at http://sg.danny.cz/sg/sg_dd.html .PP A POSIX threads version of this utility called .B sgp_dd is in the sg3_utils package. Another version from that package is called .B sgm_dd and it uses memory mapped IO to speed transfers from sg devices. .PP The lmbench package contains .B lmdd which is also interesting. For moving data to and from tapes see .B dt which is found at http://www.scsifaq.org/RMiller_Tools/index.html .PP To change mode parameters that effect a SCSI device's caching and error recovery see .B sdparm(sdparm) .PP To verify the data on the media or to verify it against some other copy of the data see .B sg_verify(sg3_utils) .PP See also .B raw(8), dd(1), ddrescue(GNU), ddpt sg3_utils-1.40/doc/sgp_dd.80000664000175000017500000003144312053021257014450 0ustar douggdougg.TH SGP_DD "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sgp_dd \- copy data to and from files and devices, especially SCSI devices .SH SYNOPSIS .B sgp_dd [\fIbs=BS\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR] [\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .PP [\fIbpt=BPT\fR] [\fIcoe=\fR0|1] [\fIcdbsz=\fR6|10|12|16] [\fIdeb=VERB\fR] [\fIdio=\fR0|1] [\fIsync=\fR0|1] [\fIthr=THR\fR] [\fItime=\fR0|1] [\fIverbose=VERB\fR] .SH DESCRIPTION .\" Add any additional description here .PP Copy data to and from any files. Specialised for "files" that are Linux SCSI generic (sg) and raw devices. Similar syntax and semantics to .B dd(1) but does not perform any conversions. Uses POSIX threads to increase the amount of parallelism. This improves speed in some cases. .PP The first group in the synopsis above are "standard" Unix .B dd(1) operands. The second group are extra options added by this utility. Both groups are defined below. .SH OPTIONS .TP \fBbpt\fR=\fIBPT\fR each IO transaction will be made using \fIBPT\fR blocks (or less if near the end of the copy). Default is 128 for block sizes less that 2048 bytes, otherwise the default is 32. So for bs=512 the reads and writes will each convey 64 KiB of data by default (less if near the end of the transfer or memory restrictions). When cd/dvd drives are accessed, the block size is typically 2048 bytes and bpt defaults to 32 which again implies 64 KiB transfers. .TP \fBbs\fR=\fIBS\fR where \fIBS\fR .B must be the block size of the physical device. Note that this differs from .B dd(1) which permits 'bs' to be an integral multiple of the actual device block size. Default is 512 which is usually correct for disks but incorrect for cdroms (which normally have 2048 byte blocks). .TP \fBcdbsz\fR=6 | 10 | 12 | 16 size of SCSI READ and/or WRITE commands issued on sg device names. Default is 10 byte SCSI command blocks (unless calculations indicate that a 4 byte block number may be exceeded, in which case it defaults to 16 byte SCSI commands). .TP \fBcoe\fR=0 | 1 set to 1 for continue on error. Only applies to errors on sg devices. Thus errors on other files will stop sgp_dd. Default is 0 which implies stop on any error. See the 'coe' flag for more information. .TP \fBcount\fR=\fICOUNT\fR copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the minimum (of \fIIFILE\fR and \fIOFILE\fR) number of blocks that sg devices report from SCSI READ CAPACITY commands or that block devices (or their partitions) report. Normal files are not probed for their size. If \fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is deduced (i.e. not explicitly given) then that count is scaled back so that the copy will not overrun the device. If the file name is a block device partition and \fICOUNT\fR is not given then the size of the partition rather than the size of the whole device is used. If \fICOUNT\fR is not given and cannot be deduced then an error message is issued and no copy takes place. .TP \fBdeb\fR=\fIVERB\fR outputs debug information. If \fIVERB\fR is 0 (default) then there is minimal debug information and as \fIVERB\fR increases so does the amount of debug (max debug output when \fIVERB\fR is 9). .TP \fBdio\fR=0 | 1 default is 0 which selects indirect IO. Value of 1 attempts direct IO which, if not available, falls back to indirect IO and notes this at completion. If direct IO is selected and /proc/scsi/sg/allow_dio has the value of 0 then a warning is issued (and indirect IO is performed) For finer grain control use 'iflag=dio' or 'oflag=dio'. .TP \fBibs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBif\fR=\fIIFILE\fR read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR is given. .TP \fBiflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIIFILE\fR and are ignored when \fIIFILE\fR is stdin. .TP \fBobs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBof\fR=\fIOFILE\fR write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed. If \fIOFILE\fR is '.' (period) then it is treated the same way as /dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it is _not_ truncated; it is overwritten from the start of \fIOFILE\fR unless 'oflag=append' or \fISEEK\fR is given. .TP \fBoflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIOFILE\fR and are ignored when \fIOFILE\fR is /dev/null, '.' (period), or stdout. .TP \fBseek\fR=\fISEEK\fR start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR. Default is block 0 (i.e. start of file). .TP \fBskip\fR=\fISKIP\fR start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR. Default is block 0 (i.e. start of file). .TP \fBsync\fR=0 | 1 when 1, does SYNCHRONIZE CACHE command on \fIOFILE\fR at the end of the transfer. Only active when \fIOFILE\fR is a sg device file name. .TP \fBthr\fR=\fITHR\fR where \fITHR\fR is the number or worker threads (default 4) that attempt to copy in parallel. Minimum is 1 and maximum is 16. .TP \fBtime\fR=0 | 1 when 1, the transfer is timed and throughput calculation is performed, outputting the results (to stderr) at completion. When 0 (default) no timing is performed. .TP \fBverbose\fR=\fIVERB\fR increase verbosity. Same as \fIdeb=VERB\fR. Added for compatibility with sg_dd and sgm_dd. .TP \fB\-\-help\fR outputs usage message and exits. .TP \fB\-\-version\fR outputs version number information and exits. .SH FLAGS Here is a list of flags and their meanings: .TP append causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For normal files this will lead to data appended to the end of any existing data. Cannot be used together with the \fIseek=SEEK\fR option as they conflict. The default action of this utility is to overwrite any existing data from the beginning of the file or, if \fISEEK\fR is given, starting at block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g. a disk) will usually be ignored or may cause an error to be reported. .TP coe continue on error. When given with 'iflag=', an error that is detected in a single SCSI command (typically 'bpt' blocks) is noted (by an error message sent to stderr), then zeros are substituted into the buffer for the corresponding write operation and the copy continues. Note that the .B sg_dd utility is more sophisticated in such error situations when 'iflag=coe'. When given with 'oflag=', any error reported by a SCSI WRITE command is reported to stderr and the copy continues (as if nothing went wrong). .TP dio request the sg device node associated with this flag does direct IO. If direct IO is not available, falls back to indirect IO and notes this at completion. If direct IO is selected and /proc/scsi/sg/allow_dio has the value of 0 then a warning is issued (and indirect IO is performed). .TP direct causes the O_DIRECT flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. This flag requires some memory alignment on IO. Hence user memory buffers are aligned to the page size. Has no effect on sg, normal or raw files. .TP dpo set the DPO bit (disable page out) in SCSI READ and WRITE commands. Not supported for 6 byte cdb variants of READ and WRITE. Indicates that data is unlikely to be required to stay in device (e.g. disk) cache. May speed media copy and/or cause a media copy to have less impact on other device users. .TP dsync causes the O_SYNC flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. The 'd' is prepended to lower confusion with the 'sync=0|1' option which has another action (i.e. a synchronisation to media at the end of the transfer). .TP excl causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. .TP fua causes the FUA (force unit access) bit to be set in SCSI READ and/or WRITE commands. This only has effect with sg devices. The 6 byte variants of the SCSI READ and WRITE commands do not support the FUA bit. Only active for sg device file names. .TP null has no affect, just a placeholder. .SH RETIRED OPTIONS Here are some retired options that are still present: .TP coe=0 | 1 continue on error is 0 (off) by default. When it is 1, it is equivalent to 'iflag=coe oflag=coe' described in the FLAGS section above. Similar to 'conv=noerror,sync' in .B dd(1) utility. Default is 0 which implies stop on error. More advanced coe=1 processing on reads is performed by the sg_dd utility. .TP .TP fua=0 | 1 | 2 | 3 force unit access bit. When 3, fua is set on both \fIIFILE\fR and \fIOFILE\fR; when 2, fua is set on \fIIFILE\fR;, when 1, fua is set on \fIOFILE\fR; when 0 (default), fua is cleared on both. See the 'fua' flag. .SH NOTES A raw device must be bound to a block device prior to using sgp_dd. See .B raw(8) for more information about binding raw devices. To be safe, the sg device mapping to SCSI block devices should be checked with 'cat /proc/scsi/scsi' before use. .PP Raw device partition information can often be found with .B fdisk(8) [the "\-ul" argument is useful in this respect]. .PP Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR arguments can take 64 bit values (i.e. very big numbers). Other values are limited to what can fit in a signed 32 bit number. .PP Data usually gets to the user space in a 2 stage process: first the SCSI adapter DMAs into kernel buffers and then the sg driver copies this data into user memory (write operations reverse this sequence). This is called "indirect IO" and there is a 'dio' option to select "direct IO" which will DMA directly into user memory. Due to some issues "direct IO" is disabled in the sg driver and needs a configuration change to activate it. .PP All informative, warning and error output is sent to stderr so that dd's output file can be stdout and remain unpolluted. If no options are given, then the usage message is output and nothing else happens. .PP Why use sgp_dd? Because in some cases it is twice as fast as dd (mainly with sg devices, raw devices give some improvement). Another reason is that big copies fill the block device caches which has a negative impact on other machine activity. .SH SIGNALS The signal handling has been borrowed from dd: SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred and the records in + out counts; then they have their default action. SIGUSR1 causes the same information to be output yet the copy continues. All output caused by signals is sent to stderr. .SH EXAMPLES .PP Looks quite similar in usage to dd: .PP sgp_dd if=/dev/sg0 of=t bs=512 count=1MB .PP This will copy 1 million 512 byte blocks from the device associated with /dev/sg0 (which should have 512 byte blocks) to a file called t. Assuming /dev/sda and /dev/sg0 are the same device then the above is equivalent to: .PP dd if=/dev/sda of=t bs=512 count=1000000 .PP although dd's speed may improve if bs was larger and count was correspondingly scaled. Using a raw device to do something similar on a ATA disk: .PP raw /dev/raw/raw1 /dev/hda .br sgp_dd if=/dev/raw/raw1 of=t bs=512 count=1MB .PP To copy a SCSI disk partition to an ATA disk partition: .PP raw /dev/raw/raw2 /dev/hda3 .br sgp_dd if=/dev/sg0 skip=10123456 of=/dev/raw/raw2 bs=512 .PP This assumes a valid partition is found on the SCSI disk at the given skip block address (past the 5 GB point of that disk) and that the partition goes to the end of the SCSI disk. An explicit count is probably a safer option. .PP To do a fast copy from one SCSI disk to another one with similar geometry (stepping over errors on the source disk): .PP sgp_dd if=/dev/sg0 of=/dev/sg1 bs=512 coe=1 .SH EXIT STATUS The exit status of sgp_dd is 0 when it is successful. Otherwise see the sg3_utils(8) man page. Since this utility works at a higher level than individual commands, and there are 'coe' and 'retries' flags, individual SCSI command failures do not necessary cause the process to exit. .SH AUTHORS Written by Douglas Gilbert and Peter Allworth. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2012 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" A simpler, non\-threaded version of this utility but with more advanced "continue on error" logic is called .B sg_dd and is also found in the sg3_utils package. The lmbench package contains .B lmdd which is also interesting. .B raw(8), dd(1) sg3_utils-1.40/doc/scsi_mandat.80000664000175000017500000000302112144707462015476 0ustar douggdougg.TH SCSI_MANDAT "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_mandat \- check SCSI device support for mandatory commands .SH SYNOPSIS .B scsi_mandat [\fI\-\-help\fR] [\fI\-\-log\fR] [\fI\-\-quiet\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls several SCSI commands on the given \fIDEVICE\fR. These SCSI commands are considered mandatory (although that varies a little depending on which standard/draft the \fIDEVICE\fR complies with). The results of each test and a pass/fail count are output. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-L\fR, \fB\-\-log\fR the output to stderr (from each SCSI command executed) is appended to a file called 'scsi_mandat.err' in the current working directory. .TP \fB\-q\fR, \fB\-\-quiet\fR the amount of output is reduced and typically only the pass/fail count is output. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .SH EXIT STATUS The exit status of this script is the number of "bad" errors found. So an exit status of 0 means all mandatory SCSI commands worked as expected. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2011\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_inq,sg_luns,sg_turs,sg_requests,sg_vpd,sg_senddiag (sg3_utils) sg3_utils-1.40/doc/sg_write_buffer.80000664000175000017500000002253212416757223016377 0ustar douggdougg.TH SG_WRITE_BUFFER "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_write_buffer \- send SCSI WRITE BUFFER commands .SH SYNOPSIS .B sg_write_buffer [\fI\-\-bpw=CS\fR] [\fI\-\-help\fR] [\fI\-\-id=ID\fR] [\fI\-\-in=FILE\fR] [\fI\-\-length=LEN\fR] [\fI\-\-mode=MO\fR] [\fI\-\-offset=OFF\fR] [\fI\-\-raw\fR] [\fI\-\-skip=SKIP\fR] [\fI\-\-specific=MS\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends one or more SCSI WRITE BUFFER commands to \fIDEVICE\fR, along with data provided by the user. In some cases no data is required, or data can be read from the file given in the \fI\-\-in=FILE\fR option, or data is read from stdin when either \fI\-\-raw\fR or \fI\-\-in=\-\fR is given. .PP Some WRITE BUFFER command variants do not have associated data to send to the device. For example "activate_mc" activates deferred microcode that was sent via prior WRITE BUFFER commands. There is a different method used to download microcode to SES devices, see the sg_ses_microcode utility. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-b\fR, \fB\-\-bpw\fR=\fICS\fR where \fICS\fR is the chunk size in bytes. This will be the maximum number of bytes sent per WRITE BUFFER command. So if \fICS\fR is less than the effective length then multiple WRITE BUFFER commands are sent, each taking the next chunk from the read data and increasing the buffer offset field in the WRITE BUFFER command by the appropriate amount. The default is a chunk size of 0 which is interpreted as a very large number hence only one WRITE BUFFER command will be sent. This option should only be used with modes that "download microcode, with offsets ..."; namely either mode 0x6, 0x7, 0xd or 0xe. .br The number in \fICS\fR can optionally be followed by ",act" or ",activate". In this case after WRITE BUFFER commands have been sent until the effective length is exhausted another WRITE BUFFER command with its mode set to "Activate deferred microcode mode" [mode 0xf] is sent. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. If used multiple times also prints the mode names and their acronyms. .TP \fB\-i\fR, \fB\-\-id\fR=\fIID\fR this option sets the buffer id field in the cdb. \fIID\fR is a value between 0 (default) and 255 inclusive. .TP \fB\-I\fR, \fB\-\-in\fR=\fIFILE\fR read data from file \fIFILE\fR that will be sent with the WRITE BUFFER command. If \fIFILE\fR is '\-' then stdin is read until an EOF is detected (this is the same action as \fI\-\-raw\fR). Data is read from the beginning of \fIFILE\fR except in the case when it is a regular file and the \fI\-\-skip=SKIP\fR option is given. .TP \fB\-l\fR, \fB\-\-length\fR=\fILEN\fR where \fILEN\fR is the length, in bytes, of data to be written to the device. If not given (and the length cannot be deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR) then defaults to zero. If the option is given and the length deduced from \fI\-\-in=FILE\fR or \fI\-\-raw\fR is less (or no data is provided), then bytes of 0xff are used as fill bytes. .TP \fB\-m\fR, \fB\-\-mode\fR=\fIMO\fR this option sets the MODE field in the cdb. \fIMO\fR is a value between 0 (default) and 31 inclusive. Alternatively an abbreviation can be given. See the MODES section below. To list the available mode abbreviations at run time give an invalid one (e.g. '\-\-mode=xxx') or use the '\-hh' option. .TP \fB\-o\fR, \fB\-\-offset\fR=\fIOFF\fR this option sets the BUFFER OFFSET field in the cdb. \fIOFF\fR is a value between 0 (default) and 2**24\-1 . It is a byte offset. .TP \fB\-r\fR, \fB\-\-raw\fR read data from stdin until an EOF is detected. This data is sent with the WRITE BUFFER command to \fIDEVICE\fR. The action of this option is the same as using '\-\-in=\-'. .TP \fB\-s\fR, \fB\-\-skip\fR=\fISKIP\fR this option is only active when \fI\-\-in=FILE\fR is given and \fIFILE\fR is a regular file, rather than stdin. Data is read starting at byte offset \fISKIP\fR to the end of file (or the amount given by \fI\-\-length=LEN\fR). If not given the byte offset defaults to 0 (i.e. the start of the file). .TP \fB\-S\fR, \fB\-\-specific\fR=\fIMS\fR \fIMS\fR is the MODE SPECIFIC field in the cdb. This is a 3\-bit field so the values 0 to 7 are accepted. This field was introduced in SPC\-4 revision 32 and can be used to specify additional events that activate deferred microcode (when \fIMO\fR is 0xD). .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH MODES Following is a list of WRITE BUFFER command settings for the MODE field. First is an acronym accepted by the \fIMO\fR argument of this utility. Following the acronym in square brackets are the corresponding decimal and hex values that may also be given for \fIMO\fR. The following are listed in numerical order. .TP hd [0, 0x0] Combined header and data (obsolete in SPC\-4). .TP vendor [1, 0x1] Vendor specific. .TP data [2, 0x2] Data (was called "Write Data" in SPC\-3). .TP dmc [4, 0x4] Download microcode and activate (was called "Download microcode" in SPC\-3). .TP dmc_save [5, 0x5] Download microcode, save, and activate (was called "Download microcode and save" in SPC\-3). .TP dmc_offs [6, 0x6] Download microcode with offsets and activate (was called "Download microcode with offsets" in SPC\-3). .TP dmc_offs_save [7, 0x7] Download microcode with offsets, save, and activate (was called "Download microcode with offsets and save" in SPC\-3). .TP echo [10, 0xa] Write data to echo buffer (was called "Echo buffer" in SPC\-3). .TP dmc_offs_ev_defer [13, 0xd] Download microcode with offsets, select activation events, save, and defer activate (introduced in SPC\-4). .TP dmc_offs_defer [14, 0xe] Download microcode with offsets, save, and defer activate (introduced in SPC\-4). .TP activate_mc [15, 0xf] Activate deferred microcode (introduced in SPC\-4). .TP en_ex [26, 0x1A] Enable expander communications protocol and Echo buffer (obsolete in SPC\-4). .TP dis_ex [27, 0x1B] Disable expander communications protocol (obsolete in SPC\-4). .TP deh [28, 0x1C] Download application client error history (was called "Download application log" in SPC\-3). .SH NOTES If no \fI\-\-length=LEN\fR is given this utility reads up to 8 MiB of data from the given file \fIFILE\fR (or stdin). If a larger amount of data is required then the \fI\-\-length=LEN\fR option should be given. .PP The user should be aware that most operating systems have limits on the amount of data that can be sent with one SCSI command. In Linux this depends on the pass through mechanism used (e.g. block SG_IO or the sg driver) and various setting in sysfs in the Linux lk 2.6/3 series (e.g. /sys/block/sda/queue/max_sectors_kb). Devices (i.e. logical units) also typically have limits on the maximum amount of data they can handle in one command. These two limitations suggest that modes containing the word "offset" together with the \fI\-\-bpw=CS\fR option are required as firmware files get larger and larger. And \fICS\fR can be quite small, for example 4096 bytes, resulting in many WRITE BUFFER commands being sent. .PP Attempting to download a microcode/firmware file that is too large may cause an error to occur in the pass-through layer (i.e. before the SCSI command is issued). In Linux such error reports can be obscure as in "pass through os error invalid argument". FreeBSD reports such errors well to the machine's console but returns a cryptic error message to this utility. .PP Downloading incorrect microcode into a device has the ability to render that device inoperable. One would hope that the device vendor verifies the data before activating it. If the SCSI WRITE BUFFER command is given values in its cdb (e.g. \fILEN\fR) that are inappropriate (e.g. too large) then the device should respond with a sense key of ILLEGAL REQUEST and an additional sense code of INVALID FIELD in CDB. If a WRITE BUFFER command (or a sequence of them) fails due to device vendor verification checks then it should respond with a sense key of ILLEGAL REQUEST and an additional sense code of COMMAND SEQUENCE ERROR. .PP Each WRITE BUFFER command is assigned a timeout of 120 seconds. .PP All numbers given with options are assumed to be decimal. Alternatively numerical values can be given in hexadecimal preceded by either "0x" or "0X" (or has a trailing "h" or "H"). .SH EXAMPLES The following sends new firmware to an enclosure. Sending a 1.5 MB file in one WRITE BUFFER command caused the enclosure to lock up temporarily and did not update the firmware. Breaking the firmware file into 4 KB chunks (an educated guess) was more successful: .PP sg_write_buffer \-b 4k \-m dmc_offs_save \-I firmware.bin /dev/sg4 .PP The firmware update occurred in the following enclosure power cycle. With a modern enclosure the Extended Inquiry VPD page gives indications in which situations a firmware upgrade will take place. .SH EXIT STATUS The exit status of sg_write_buffer is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Luben Tuikov and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2006\-2014 Luben Tuikov and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_read_buffer, sg_ses_microcode(sg3_utils) sg3_utils-1.40/doc/sg_reassign.80000664000175000017500000001661112264146446015530 0ustar douggdougg.TH SG_REASSIGN "8" "January 2014" "sg3_utils\-1.38" SG3_UTILS .SH NAME sg_reassign \- send SCSI REASSIGN BLOCKS command .SH SYNOPSIS .B sg_reassign [\fI\-\-address=A,A...\fR] [\fI\-\-dummy\fR] [\fI\-\-eight=0|1\fR] [\fI\-\-grown\fR] [\fI\-\-help\fR] [\fI\-\-longlist=0|1\fR] [\fI\-\-primary\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send a SCSI REASSIGN BLOCKS command to \fIDEVICE\fR. Alternatively this utility can find the number of element in a "grown" or "primary" defect list with a SCSI READ DEFECT DATA (10) command. These SCSI commands are defined in SBC\-2 for direct access devices (e.g. a disk). Reassign blocks is designed to change the physical location of a logical block that is known or suspected to be defective to another area on the media. Disks are typically formatted with blocks held in reserve for this situation. .PP If neither the \fI\-\-grown\fR nor \fI\-\-primary\fR option is supplied then one or more addresses need to be given. If the address (or all of the addresses) fit into 4 bytes and '\-\-eight=1' is not given then the parameter block passed to \fIDEVICE\fR is made up of 4 byte logical block addresses. If any of the addresses need more than 4 bytes to represent (i.e. >= 2**32) or '\-\-eight=1' is given then the parameter block passed to \fIDEVICE\fR is made up of 8 byte logical block addresses. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-a\fR, \fB\-\-address\fR=\fIA,A...\fR where \fIA,A...\fR is a string of comma separated numbers. Each number is interpreted as decimal unless prefixed by '0x' or '0X' (or it has a trailing 'h' or 'H'). If multiple logical block addresses are given they must be separated by a comma or a (single) space. A string that contains any space separators needs to be quoted. At least one address must be given. .TP \fB\-a\fR, \fB\-\-address\fR=\- reads one or more logical block addresses from stdin. These may be comma, space, tab or linefeed (newline) separated. If a line contains "#" then the remaining characters on that line are ignored. Otherwise each non separator sequence of characters should resolve to a decimal number unless prefixed by '0x' or '0X' (or has a trailing 'h'). At least one address must be given. Lines should not be longer than 1023 bytes. .TP \fB\-d\fR, \fB\-\-dummy\fR prepare for but do not execute the SCSI REASSIGN BLOCKS command. Since the REASSIGN BLOCKS command is essentially irreversible, paranoid users may wish to check the invocation of this utility before reassigning defective blocks on a disk. Useful with '\-vv' for those who wish to view the parameter block that will accompany the command. .TP \fB\-e\fR, \fB\-\-eight\fR=0 | 1 when value is 1 then it sets the 'LONGLBA' flag in the command indicating that the addresses in the associated parameter block are 8 byte quantities. When value is 0 then it clears the 'LONGLBA' flag in the command indicating that the addresses in the associated parameter block are 4 byte quantities. If this option is not given then 4 byte quantities are assumed unless one of the address is too large. .TP \fB\-g\fR, \fB\-\-grown\fR use the SCSI READ DEFECT DATA (10) command to determine the number of elements in the "grown defect list". When this option is given there is no reassignment of blocks (i.e. this utility is passive). When this option is given then the \fI\-\-address=\fR option is not permitted. See the discussion below concerning the relationship between reassigned blocks and the grown defect list. This list is sometimes referred to as the GLIST. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-l\fR, \fB\-\-longlist\fR=0 | 1 sets the REASSIGN BLOCKS cdb field of the same name to the given value. Only 1000 addresses are permitted so there should be no need to specify a value of 1. The short list variant restricts the parameter block length to 2 ** 16 bytes (i.e. about 16000 4 byte addresses or 8000 8 byte addresses). Added for completeness. .TP \fB\-p\fR, \fB\-\-primary\fR use the SCSI READ DEFECT DATA (10) command to determine the number of elements in the "primary defect list" which is established during the manufacturing process. When this option is given there is no reassignment of blocks (i.e. this utility is passive). When this option is given then the \fI\-\-address=\fR option is not permitted. This list is sometimes referred to as the PLIST. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES Note that if the ARRE field (for reads) and/or the AWRE field (for writes) are set in the "Read Write Error Recovery" mode page then recoverable read and/or write errors cause automatic reassignment of the defective block. The PER bit in the same mode page controls whether a RECOVERED ERROR sense key is reported on not (PER=1 implies do report). Irrespective of the ARRE, AWRE or PER field settings, the error counter log pages reflect any errors (recovered or otherwise). Whenever a block is reassigned, a new entry is added in the "grown" defect list. Apart from doing selftests (see sg_senddiag or smartmontools) regularly, monitoring the grown defect list of a disk is a reasonable metric of its health. If the grown list starts growing quickly that is an ominous sign. The best grown defect lists are empty ones. The number of elements in the grown defect list can be viewed with the \fI\-\-grown\fR option. The contents of the grown defect list can be viewed with the 'sginfo \-G' utility. .PP If an unrecoverable error is detected at a logical block address then REASSIGN BLOCKS is needed to reassign the block. Also if the ARRE and/or AWRE fields are clear and a recoverable error is detected then the logical block in question may be reassigned with this utility (otherwise the error counter log pages will continually be incremented for each recovered access). .PP The number of blocks held in reserve for the purposes of REASSIGN BLOCKS is vendor specific and may well be limited to the zone within the media where the original (defective) block lay. When this number is exhausted subsequent invocations of this utility may result in a sense key of hardware error and an additional sense of 'No defect spare location available'. The next step would be to reformat the disk (or get a replacement). .PP The SBC\-2 draft standard (revision 16) notes that when multiple addresses are given to the SCSI REASSIGN BLOCKS command and there is some failure at one of the later addresses then all addresses prior to that have already be reassigned. Care should be taken in such a case. Re\-executing the command with the same addresses will cause the earlier addresses to be reassigned again. At some stage the disk will run out of reserved locations. So unless a large number of addresses are involved it may be safer to reassign them one address at a time. .SH EXIT STATUS The exit status of sg_reassign is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2005\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_format,sginfo,sg_senddiag(all in sg3_utils), sdparm(sdparm), .B smartmontools(internet, sourceforge) sg3_utils-1.40/doc/sg_reset.80000664000175000017500000001367512422552302015032 0ustar douggdougg.TH SG_RESET "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_reset \- sends SCSI device, target, bus or host reset; or checks reset state .SH SYNOPSIS .B sg_reset [\fI\-\-bus\fR] [\fI\-\-device\fR] [\fI\-\-help\fR] [\fI\-\-host\fR] [\fI\-\-no-esc\fR] [\fI\-\-target\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP The sg_reset utility with no options (just a \fIDEVICE\fR) reports on the reset state (e.g. if a reset is underway) of the \fIDEVICE\fR. When given a \fI\-\-device\fR, \fI\-\-target\fR, \fI\-\-bus\fR or \fI\-\-host\fR option it requests a device, target, bus or host reset respectively. .PP A device reset is applied to the Logical Unit (LU) corresponding to \fIDEVICE\fR. It is most likely implemented by a Low level Driver (LLD) in Linux as a LOGICAL UNIT RESET task management function. .PP The ability to reset a SCSI target was added in Linux kernel 2.6.27 . A LLD may send Low level Drivers (LLDs) the I_T NEXUS RESET task management function. Alternatively it may use a transport mechanism to do the same thing (e.g. a hard reset on the link containing a SAS target). .PP In the Linux kernel 2.6 and 3 series this utility can be called on sd, sr (cd/dvd), st or sg device nodes; if the user has appropriate permissions. .PP Users of this utility can check whether a reset recovery is already underway before trying to send a new reset with this utility. Calling this utility with no options, just the \fIDEVICE\fR, will do such a check. .SH OPTIONS .TP \fB\-b\fR, \fB\-\-bus\fR attempt a SCSI bus reset. A bus reset is a SCSI Parallel Interface (SPI) concept not found in modern transports. A recent LLD may implement it as a series of resets on targets that might be considered as siblings to the target on the \fIDEVICE\fR path. .TP \fB\-d\fR, \fB\-\-device\fR attempt a SCSI device reset. This would typically involve sending a LOGICAL UNIT RESET task management function to \fIDEVICE\fR. .TP \fB\-h\fR, \fB\-\-help\fR print the usage message then exit. .TP \fB\-H\fR, \fB\-\-host\fR attempt a host reset. The "host" in this context is often called a Host Bus Adapter (HBA) and contains one or more SCSI initiators. .TP \fB\-N\fR, \fB\-\-no\-esc\fR without this option, if a device reset (\fI\-\-device\fR) fails then it will escalate to a target reset. And if a target reset (\fI\-\-target\fR) fails then it will escalate to a bus reset. And if a bus reset (\fI\-\-bus\fR) fails then it will escalate to a host reset. With this option only the requested reset is attempted. An alternate option name of \fI\-\-no-escalate\fR is also accepted. .TP \fB\-t\fR, \fB\-\-target\fR attempt a SCSI target reset. A SCSI target contains one or more LUs. This would typically involve sending a I_T NEXUS RESET task management function to \fIDEVICE\fR There may be a transport action that is equivalent (e.g. in SAS a hard reset on the link that contains the target). .TP \fB\-v\fR, \fB\-\-verbose\fR increase the degree of verbosity (debug messages). .TP \fB\-V\fR, \fB\-\-version\fR prints the version string then exits. .SH NOTES The error recovery code within the Linux kernel (SCSI mid\-level) when faced with a SCSI command timing out and no response from the device (LU) does the following. First it tries a device reset and if that is not successful tries a target reset. If that is not successful it tries a bus reset. If that is not successful it tries a host reset. The "device,target,bus,host" order is the reset escalation that the \fI\-\-no-esc\fR option attempts to stop. In large storage configurations the escalation may be (very) undesirable. .PP This utility calls the SG_SCSI_RESET ioctl and as of lk 3.10.7 the \fI\-\-no-esc\fR option is not supported. Patches to implement this functionality may be accepted in lk 3.18 or 3.19 . .PP SAM\-4 and 5 define a hard reset, a LOGICAL UNIT RESET and a I_T NEXUS RESET. A hard reset is defined to be a power on condition, a microcode change or a transport reset event. LOGICAL UNIT RESET and I_T NEXUS RESET can be requested via task management functions (and support for LOGICAL UNIT RESET is mandatory). In Linux the SCSI subsystem leaves it up to the LLDs as to exactly what type (if any) of reset is performed. The "bus reset" is SCSI Parallel Interface (SPI) concept that may not map well to recent SCSI transports so it may be a dummy operation. A "host reset" attempts to re\-initialize the HBA that the request passes through en route to the \fIDEVICE\fR. Note that a "host reset" and a "bus reset" may cause collateral damage. .PP This utility does not allow individual SCSI commands to be aborted. SAM\-4 defines ABORT TASK and ABORT TASK SET task management functions for that. .PP Prior to SAM\-3 there was a TARGET RESET task management function. And in SAM\-4 I_T NEXUS RESET appeared which seems closely related: the "I_T" stands for Initiator\-Target. .PP Transports may have their own types of resets not supported by this utility. For example SAS has a link reset in which both ends of a physical link (e.g. between a SAS expander and a SAS tape drive) renegotiate their connection. .PP Prior to version 0.57 of this utility the command line had short options only (e.g. \fI\-d\fR but not \fI\-\-device\fR). Also \fI\-h\fR invoked a host reset while in the current version \fI\-h\fR is equivalent to \fI\-\-help\fR and both \fI\-H\fR and \fI\-\-host\fR invoke a host reset. For backward compatibility define the environment variable SG3_UTILS_OLD_OPTS or SG_RESET_OLD_OPTS . In this case \fI\-h\fR will invoke a host reset and the output will be verbose as it was previously (equivalent to using the \fI\-\-verbose\fR option now). For example: .PP SG_RESET_OLD_OPTS=1 sg_reset -h /dev/sg1 .br sg_reset: starting host reset .br sg_reset: completed host reset .SH AUTHORS Written by Douglas Gilbert. .SH COPYRIGHT Copyright \(co 1999\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. sg3_utils-1.40/doc/sg_test_rwbuf.80000664000175000017500000000727512053021257016073 0ustar douggdougg.TH SG_TEST_RWBUF "8" "November 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_test_rwbuf \- test a SCSI host adapter by issuing dummy writes and reads .SH SYNOPSIS .B sg_test_rwbuf [\fI\-\-addrd=AR\fR] [\fI\-\-addwr=AW\fR] [\fI\-\-help\fR] [\fI\-\-quick\fR] \fI\-\-size=SZ\fR [\fI\-\-times=NUM\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP or an older deprecated format .B sg_test_rwbuf \fIDEVICE\fR \fISZ\fR [\fIAW\fR] [\fIAR\fR] .SH DESCRIPTION .\" Add any additional description here .PP sg_test_rwbuf writes and reads back \fISZ\fR bytes to the internal buffer of \fIDEVICE\fR (e.g. /dev/sda or /dev/sg0). A pseudo random pattern is written to the data buffer on the device then read back. If the same pattern is found 'Success' is reported. If they do not match (checksums unequal) then this is reported and up to 24 bytes from the first point of mismatch are reported; the first line shows what was written and the second line shows what was received. For testing purposes, you can ask it to write \fIAW\fR or read \fIAR\fR additional bytes. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-r\fR, \fB\-\-addrd\fR=\fIAR\fR Read an additional \fIAR\fR bytes (than indicated by \fISZ\fR) from the data buffer. Checksum is performed over the first \fISZ\fR bytes. .TP \fB\-w\fR, \fB\-\-addwr\fR=\fIAW\fR Write an additional \fIAW\fR bytes (than indicated by \fISZ\fR) of zeros into the data buffer. Checksum is generated over the first \fISZ\fR bytes. .TP \fB\-h\fR, \fB\-\-help\fR Print out a usage message the exit. .TP \fB\-q\fR, \fB\-\-quick\fR Perform a READ BUFFER descriptor command to find out the available data buffer length and offset, print them out then exit (without testing with write/read sequences). .TP \fB\-s\fR, \fB\-\-size\fR=\fISZ\fR where \fISZ\fR is the size of buffer in bytes to be written then read and checked. This number needs to be less than or equal to the size of the device's data buffer which can be seen from the \fI\-\-quick\fR option. Either this option or the \fI\-\-quick\fR option should be given. .TP \fB\-t\fR, \fB\-\-times\fR=\fINUM\fR where \fINUM\fR is the number of times to repeat the write/read to buffer test. Default value is 1 . .TP \fB\-v\fR, \fB\-\-verbose\fR increase verbosity of output. .TP \fB\-V\fR, \fB\-\-version\fR print version number (and data of last change) then exit. .SH NOTES The microcode in a SCSI device is _not_ modified by doing a WRITE BUFFER command with its mode set to "data" (0x2) as done by this utility. Therefore this utility is safe in that respect. [Mode values 0x4, 0x5, 0x6 and 0x7 are the dangerous ones :\-)] .PP \fBWARNING\fR: If you access the device at the same time (e.g. because it's a hard disk with a mounted file system on it) the device's buffer may be used by the device itself for other data at the same time, and overwriting it may or may not cause data corruption! \fBHOWEVER\fR the SPC\-3 draft standard does state in its WRITE BUFFER command: "This command shall not alter any medium of the logical unit when data mode ... is specified". This implies that it _is_ safe to use this utility with devices that have mounted file systems on them. Following this theme further, a disk with active mounted file systems may cause the data read back to be different (due to caching activity) to what was written and hence a checksum error. .SH EXIT STATUS The exit status of sg_test_rwbuf is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert and K. Garloff .SH COPYRIGHT Copyright \(co 2000\-2012 Douglas Gilbert, Kurt Garloff .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. sg3_utils-1.40/doc/sg_sat_set_features.80000664000175000017500000001230112430315266017236 0ustar douggdougg.TH SG_SAT_SET_FEATURES "8" "November 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_sat_set_features \- use ATA SET FEATURES command via a SCSI to ATA Translation (SAT) layer .SH SYNOPSIS .B sg_sat_set_features [\fI\-\-count=CO\fR] [\fI\-\-ck_cond\fR] [\fI--extended\fR] [\fI\-\-feature=FEA\fR] [\fI\-\-help\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-len=\fR{16|12}] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends an ATA SET FEATURES command to the \fIDEVICE\fR. This command is used to change settings of ATA non\-packet (i.e. disks) and packet devices (e.g. cd/dvd drives). Rather than send the SET FEATURES command directly to the device it is sent via a SCSI transport which is assumed to contain a SCSI to ATA Translation (SAT) Layer (SATL). The SATL may be in an operating system driver, in host bus adapter firmware or in some external enclosure. .PP The SAT standard (SAT ANSI INCITS 431\-2007, prior draft: sat\-r09.pdf at www.t10.org) defines two SCSI "ATA PASS\-THROUGH" commands: one using a 16 byte "cdb" and the other with a 12 byte cdb. This utility defaults to using the 16 byte cdb variant. SAT\-2 is also a standard: SAT\-2 ANSI INCITS 465\-2010 and the draft prior to that is sat2r09.pdf . The SAT-3 project has started and the most recent draft is sat3r05b.pdf . .PP The features can be read using the sg_sat_identify utility which uses either the ATA IDENTIFY DEVICE (for non\-packet devices) or the IDENTIFY PACKET DEVICE (for packet devices) command. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-c\fR, \fB\-\-count\fR=\fICO\fR the number \fICO\fR is placed in the "count" field in the ATA SET FEATURES command. Only some subcommands (a term used for the value placed in the "feature" field) require the count field to be set. The default value placed in the "count" field is 0. .TP \fB\-C\fR, \fB\-\-ck_cond\fR sets the CK_COND bit in the ATA PASS\-THROUGH SCSI cdb. The default setting is clear (i.e. 0). When set the SATL should yield a sense buffer containing a ATA Result descriptor irrespective of whether the ATA command succeeded or failed. When clear the SATL should only yield a sense buffer containing a ATA Result descriptor if the ATA command failed. .TP \fB\-e\fR, \fB\-\-extended\fR allow for extended LBA numbers (i.e. larger than 32 bits). This value is enabled automatically for large LBA numbers, but can be enabled explicitly even for low LBA numbers with this option. .TP \fB\-f\fR, \fB\-\-feature\fR=\fIFEA\fR the value \fIFEA\fR is placed in the "feature" field in the ATA SET FEATURES command. The term "subcommand" is sometimes used for this value. The default value placed in the "feature" field is 0 which is reserved and hence should not change anything. Two common examples are 2h to enable the write cache and 82h to disable it. .TP \fB\-h\fR, \fB\-\-help\fR outputs the usage message summarizing command line options then exits. Ignores \fIDEVICE\fR if given. .TP \fB\-L\fR, \fB\-\-lba\fR=\fILBA\fR the number \fILBA\fR is placed in the "lba" field of the ATA SET FEATURES command. Only some sub\-commands (a term used for the value placed in the "feature" field) require the lba field to be set. This value is typically not a "logical block address" as the acronym might imply. The default value placed in the "lba" field is 0. The maximum value allowed for \fILBA\fR is 0xfffffffe (or 0xffffff if \fI\-\-len=\fR12). .TP \fB\-l\fR, \fB\-\-len\fR={16|12} this is the length of the SCSI cdb used for the ATA PASS\-THROUGH commands. The argument can either be 16 or 12. The default is 16. Some SCSI transports cannot convey SCSI commands longer than 12 bytes. .TP \fB\-r\fR, \fB\-\-readonly\fR causes the \fIDEVICE\fR to be opened with the read\-only flag (O_RDONLY in Unix). The default action is to open \fIDEVICE\fR with the read\-write flag (O_RDWR in Unix). In some cases sending power management commands to ATA disks are defeated by OS actions on the close() if the \fIDEVICE\fR was opened with the read\-write flag (e.g. the OS might think it needs to flush something to disk). .TP \fB\-v\fR, \fB\-\-verbose\fR increases the level or verbosity. .TP \fB\-V\fR, \fB\-\-version\fR print out version string .SH NOTES In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 and 3 series block devices (e.g. disks and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda" will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char" device names may be used as well (e.g. "/dev/st0m"). Prior to lk 2.6.29 USB mass storage limited sense data to 18 bytes which made the \fB\-\-ck_cond\fR option yield strange (truncated) results. .SH EXIT STATUS The exit status of sg_sat_set_features is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2007\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_sat_identify(sg3_utils), sg_inq(sg3_utils), sdparm(sdparm), .B hdparm(hdparm) sg3_utils-1.40/doc/sg_read_long.80000664000175000017500000001007211523627125015635 0ustar douggdougg.TH SG_READ_LONG "8" "April 2010" "sg3_utils\-1.30" SG3_UTILS .SH NAME sg_read_long \- send a SCSI READ LONG command .SH SYNOPSIS .B sg_read_long [\fI\-\-16\fR] [\fI\-\-correct\fR] [\fI\-\-help\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-out=OF\fR] [\fI\-\-pblock\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-xfer_len=BTL\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Send SCSI READ LONG command to \fIDEVICE\fR. The read buffer is output in hex and ASCII to stdout or placed in a file. Note that the data returned includes the logical block data (typically 512 bytes for a disk) plus ECC information (whose format is proprietary) plus optionally other proprietary data. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-S\fR, \fB\-\-16\fR uses a SCSI READ LONG(16) command. The default action is to use a SCSI READ LONG(10) command. The READ LONG(10) command has a 32 bit field for the lba while READ LONG(16) has a 64 bit field. .TP \fB\-c\fR, \fB\-\-correct\fR sets the 'CORRCT' bit in the SCSI READ LONG command. When set the data is corrected by the ECC before being transferred back to this utility. The default is to leave the 'CORRCT' bit clear in which case the data is not corrected. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR is the logical block address of the sector to read. Assumed to be in decimal unless prefixed with '0x' (or has a trailing 'h'). Defaults to lba 0. If the lba is larger than can fit in 32 bits then the \fI\-\-16\fR option should be used. .TP \fB\-o\fR, \fB\-\-out\fR=\fIOF\fR instead of outputting ASCII hex to stdout, send it in binary to the file called \fIOF\fR. If '\-' is given for \fIOF\fR then the (binary) output is sent to stdout. Note that all informative and error output is sent to stderr. .TP \fB\-p\fR, \fB\-\-pblock\fR sets the 'PBLOCK' bit in the SCSI READ LONG command. When set the physical block (plus ECC data) containing the requested logical block address is read. The default is to leave the 'PBLOCK' bit clear in which case the logical block (plus any ECC data) is read. .TP \fB\-r\fR, \fB\-\-readonly\fR opens the DEVICE read\-only rather than read\-write which is the default. The Linux sg driver needs read\-write access for the SCSI READ LONG command but other access methods may require read\-only access. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-x\fR, \fB\-\-xfer_len\fR=\fIBTL\fR where \fIBTL\fR is the byte transfer length (default to 520). If the given value (or the default) does not match the "long" block size of the device, the appropriate \fIBTL\fR is deduced from the error response and printed (to stderr). The idea is that the user will retry this utility with the correct transfer length. .SH NOTES If a defective block is found and its contents, if any, has been retrieved then "sg_reassign" could be used to map out the defective block. Associated with such an action the number of elements in the "grown" defect list could be monitored (with "sg_reassign \-\-grown") as the disk could be nearing the end of its useful lifetime. .PP Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP As a data point, Fujitsu uses a 54 byte ECC (per block) which is capable of correcting up to a single burst error or 216 bits "on the fly". [Information obtained from MAV20xxrc product manual.] .SH EXIT STATUS The exit status of sg_read_long is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2010 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_reassign, sg_write_long, sg_dd sg3_utils-1.40/doc/scsi_temperature.80000664000175000017500000000225212144707462016574 0ustar douggdougg.TH SCSI_TEMPERATURE "8" "May 2011" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_temperature \- fetch the temperature of a SCSI device .SH SYNOPSIS .B scsi_temperature [\fI\-\-help\fR] [\fI\-\-verbose\fR] \fIDEVICE\fR [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls the sg_logs utility on each given \fIDEVICE\fR in order to find the device's temperature. The Temperature log page is checked first and if it is not available then the Informational Exceptions log page is checked. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Otherwise the exit status is that of the last sg_logs utility called. See the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2011\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_logs (sg3_utils) sg3_utils-1.40/doc/sg_rep_zones.80000664000175000017500000000566612423733033015720 0ustar douggdougg.TH SG_REP_ZONES "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_rep_zones \- send SCSI REPORT ZONES command .SH SYNOPSIS .B sg_rep_zones [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-readonly\fR] [\fI\-\-report=OPT\fR] [\fI\-\-start=LBA\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends a SCSI REPORT ZONES command to \fIDEVICE\fR and outputs the data returned. This command is found in the ZBC draft standard, revision 1c (zbc\-r01c.pdf). .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR output the response in hexadecimal to stdout. When used once the whole response is output in ASCII hexadecimal with a leading address (starting at 0) on each line. When used twice each zone descriptor in the response is output separately in hexadecimal. When used thrice the whole response is output in hexadecimal with no leading address (on each line). .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the (maximum) response length in bytes. It is placed in the cdb's "allocation length" field. If not given (or \fILEN\fR is zero) then 8192 is used. The maximum allowed value of \fILEN\fR is 1048576. .TP \fB\-r\fR, \fB\-\-raw\fR output the SCSI response (i.e. the data-out buffer) in binary (to stdout). .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-o\fR, \fB\-\-report\fR=\fIOPT\fR where \fIOPT\fR will become the contents of the REPORTING OPTION field in the cdb. The default value is 0 which means report a list or all zones. Some other values are 1 for list full zones; 2 for list all open zones; 3 for list all empty zones; 4 for list all read only zones; 5 for list all offline zones; 6 for list all zones with the RESET bit set; and 7 for list all zones with the NON_SEQ bit set. .TP \fB\-s\fR, \fB\-\-start\fR=\fILBA\fR where \fILBA\fR is at the start or within the first zone to be reported. The default value is 0. If \fILBA\fR is not a zone start LBA then the preceding zone start LBA is used for reporting. Assumed to be in decimal unless prefixed with '0x' or has a trailing 'h' which indicate hexadecimal. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH EXIT STATUS The exit status of sg_rep_zones is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_reset_wp(sg3_utils) sg3_utils-1.40/doc/sg_copy_results.80000664000175000017500000001143412404322612016431 0ustar douggdougg.TH SG_COPY_RESULTS "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_copy_results \- send SCSI RECEIVE COPY RESULTS command (XCOPY related) .SH SYNOPSIS .B sg_copy_results [\fI\-\-failed\fR|\fI\-\-params\fR|\fI\-\-receive\fR|\fI\-\-status\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-list_id=ID\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-xfer_len=BTL\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility is designed to query the status of the SCSI Extended Copy (XCOPY) facility (see SPC\-3 revision 23 sections 6.3 and 6.17), present in some modern storage arrays. This utility sends a SCSI RECEIVE COPY RESULTS command to the given \fIDEVICE\fR and displays the response. .PP During the draft stages of SPC\-4 the T10 committee has expanded the XCOPY command so that it now has two variants: "LID1" (for a List Identifier length of 1 byte) and "LID4" (for a List Identifier length of 4 bytes). This utility supports the older, LID1 variant which is also found in SPC\-3 and earlier. While the LID1 variant in SPC\-4 is command level (binary) compatible with XCOPY as defined in SPC\-3, some of the command naming has changed. This utility uses the older, SPC\-3 XCOPY names. .PP The command has four distinct modes of operation, distinguished by the service action field: .TP \fBCOPY STATUS [SPC\-4: RECEIVE COPY STATUS(LID1)]\fR Displays the current status of the EXTENDED COPY command identified by the list id field. .TP \fBRECEIVE DATA [SPC\-4: RECEIVE COPY DATA(LID1)]\fR Return the held data read by the EXTENDED COPY command identified by the list id field. This option is only meaningful if the respective segment descriptor are supported. .TP \fBOPERATING PARAMETERS [SPC\-4: RECEIVE COPY OPERATING PARAMETERS]\fR Return copy manager operating parameters. This option is also useful to determine if the SCSI Extended Copy facility is supported. .TP \fBFAILED SEGMENT DETAILS [SPC\-4: RECEIVE COPY FAILURE DETAILS(LID1)]\fR Return copy target device sense data and other information about any failed segments. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-f\fR, \fB\-\-failed\fR sets the service action field to FAILED SEGMENT DETAILS [4]. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR prints out the response buffer in hex. .TP \fB\-l\fR, \fB\-\-list_id\fR=\fIID\fR sets the list identifier field to \fIID\fR (default: 0). .TP \fB\-p\fR, \fB\-\-params\fR sets the service action field to OPERATING PARAMETERS [3]. This is the default. .TP \fB\-R\fR, \fB\-\-readonly\fR open the \fIDEVICE\fR read\-only (e.g. in Unix with the O_RDONLY flag). The default is to open it read\-write. .TP \fB\-r\fR, \fB\-\-receive\fR sets the service action field to RECEIVE DATA [1]. .TP \fB\-s\fR, \fB\-\-status\fR sets the service action field to COPY STATUS [0]. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-x\fR, \fB\-\-xfer_len\fR=\fIBTL\fR sets the allocation length field to \fIBTL\fR. It is the byte transfer length and is the maximum (byte) size of the response. \fIBTL\fR must be less than 10000 and defaults to 520. .SH NOTES Decoding of \fIRECEIVE DATA\fR service action is not implemented. .PP In a similar way the functionality of sg_xcopy has been ported to the more general ddpt utility (and package), the functionality of this utility has been ported to the ddptctl utility. .SH EXAMPLES Query the operating parameters for a device: .PP # sg_copy_results \-p /dev/sdo .br Receive copy results (report operating parameters): Supports no list identifier: no Maximum target descriptor count: 2 Maximum segment descriptor count: 1 Maximum descriptor list length: 92 bytes Maximum segment length: 33553920 bytes Inline data not supported Held data limit: 0 bytes Maximum stream device transfer size: 0 bytes Total concurrent copies: 0 Maximum concurrent copies: 255 Data segment granularity: 512 bytes Inline data granularity: 1 bytes Held data granularity: 1 bytes Implemented descriptor list: Segment descriptor 0x02: Copy from block device to block device Target descriptor 0xe4: Identification descriptor .SH EXIT STATUS The exit status of sg_copy_results is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2012\-2014 Hannes Reinecke and Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_xcopy(sg3_utils), ddpt,ddptctl(ddpt) sg3_utils-1.40/doc/sg_inq.80000664000175000017500000004775212357543201014507 0ustar douggdougg.TH SG_INQ "8" "July 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_inq \- issue SCSI INQUIRY command and/or decode its response .SH SYNOPSIS .B sg_inq [\fI\-\-ata\fR] [\fI\-\-block=0|1\fR] [\fI\-\-cmddt\fR] [\fI\-\-descriptors\fR] [\fI\-\-export\fR] [\fI\-\-extended\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-id\fR] [\fI\-\-inhex=FN\fR] [\fI\-\-len=LEN\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-raw\fR] [\fI\-\-vendor\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-vpd\fR] \fIDEVICE\fR .PP .B sg_inq [\fI\-36\fR] [\fI\-a\fR] [\fI\-A\fR] [\fI\-b\fR] [\fI\-\-B=0|1\fR] [\fI\-c\fR] [\fI\-cl\fR] [\fI\-d\fR] [\fI\-e\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-i\fR] [\fI\-I=FN\fR] [\fI\-l=LEN\fR] [\fI\-m\fR] [\fI\-M\fR] [\fI\-o=OPCODE_PG\fR] [\fI\-p=VPD_PG\fR] [\fI\-P\fR] [\fI\-r\fR] [\fI\-s\fR] [\fI\-u\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-x\fR] [\fI\-36\fR] [\fI\-?\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility, when \fIDEVICE\fR is given, sends a SCSI INQUIRY command to it then outputs the response. All SCSI devices are meant to respond to a "standard" INQUIRY command with at least a 36 byte response (in SCSI 2 and higher). An INQUIRY is termed as "standard" when both the EVPD and CmdDt (now obsolete) bits are clear. .PP Alternatively the \fI\-\-inhex=FN\fR option can be given. In this case \fIFN\fR is assumed to be a file name ('\-' for stdin) containing ASCII hexadecimal representing an INQUIRY response. .PP This utility supports two command line syntaxes. The preferred one is shown first in the synopsis and is described in the main OPTIONS section. A later section titled OLDER COMMAND LINE OPTIONS describes the second group of options. .PP An important "non\-standard" INQUIRY page is the Device Identification Vital Product Data (VPD) page [0x83]. Since SPC\-3, support for this page is mandatory. The \fI\-\-id\fR option decodes this page. New VPD page information is no longer being added to this utility. To get information on new VPD pages see the sg_vpd(8) or sdparm(8) utilities. .PP In Linux, if the \fIDEVICE\fR exists and the SCSI INQUIRY fails (e.g. because the SG_IO ioctl is not supported) then an ATA IDENTIFY (PACKET) DEVICE is tried. If it succeeds then device identification strings are output. The \fI\-\-raw\fR and \fI\-\-hex\fR options can be used to manipulate the output. If the \fI\-\-ata\fR option is given then the SCSI INQUIRY is not performed and the \fIDEVICE\fR is assumed to be ATA (or ATAPI). .PP The reference document used for interpreting an INQUIRY is T10/1713\-D Revision 37 (SPC\-4, 17 May 2014) found at http://www.t10.org . Obsolete and reserved items in the standard INQUIRY response output are displayed in brackets. The reference document for the ATA IDENTIFY (PACKET) DEVICE command is ATA8\-ACS found at http://www.t13.org . .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-a\fR, \fB\-\-ata\fR Assume given \fIDEVICE\fR is an ATA or ATAPI device which can receive ATA commands from the host operating system. Skip the SCSI INQUIRY command and use either the ATA IDENTIFY DEVICE command (for non-packet devices) or the ATA IDENTIFY PACKET DEVICE command. To show the response in hex, add a '\-\-verbose' option. This option is only available in Linux. .TP \fB\-B\fR, \fB\-\-block\fR=\fI0|1\fR this option controls how the file handle to the \fIDEVICE\fR is opened. If this argument is 0 then the open is non\-blocking. If the argument is 1 then the open is blocking. In Unix a non\-blocking open is indicated by a O_NONBLOCK flag while a blocking open is indicated by the absence of that flag. The default value depends on the operating system and the type of \fIDEVICE\fR node. For Linux pass\-throughs (i.e. the sg and bsg drivers) the default is 0. .TP \fB\-c\fR, \fB\-\-cmddt\fR set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used in conjunction with the \fI\-\-page=PG\fR option where \fIPG\fR specifies the SCSI command opcode to query. When used twice (e.g. '\-cc') this utility forms a list by looping over all 256 opcodes (0 to 255 inclusive) only outputting a line for found commands. The CmdDt bit is now obsolete. It has been replaced by the REPORT SUPPORTED OPERATION CODES command, see the sg_opcodes(8) utility. .TP \fB\-d\fR, \fB\-\-descriptors\fR decodes and prints the version descriptors found in a standard INQUIRY response. There are up to 8 of them. Version descriptors indicate which versions of standards and/or drafts the \fIDEVICE\fR complies with. The normal components of a standard INQUIRY are output (typically from the first 36 bytes of the response) followed by the version descriptors if any. .TP \fB\-e\fR see entry below for \fI\-\-vpd\fR. .TP \fB\-u\fR, \fB\-\-export\fR prints out information obtained from the device. The output can be modified by selecting a VPD page with \fIPG\fR (from \fI\-\-page=PG\fR). If the device identification VPD page 0x83 is given it prints out information in the form: "SCSI_IDENT__=" to stdout. If the device serial number VPD page 0x80 is given it prints out information in the form: "SCSI_SERIAL=". Other VPD pages are not supported. If no VPD page is given it prints out information in the form: "SCSI_VENDOR=", "SCSI_MODEL=", and "SCSI_REVISION=", taken from the standard inquiry. This may be useful for tools like udev(7) in Linux. .TP \fB\-E\fR, \fB\-x\fR, \fB\-\-extended\fR prints the extended INQUIRY VPD page [0x86]. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. When used twice, after the usage message, there is a list of available abbreviations than can be given to the \fI\-\-page=PG\fR option. .TP \fB\-H\fR, \fB\-\-hex\fR rather than decode a standard INQUIRY response, a VPD page or command support data; print out the response in hex to stdout. Error messages and warnings are typically output to stderr. When used twice with the ATA Information VPD page [0x89] decodes the start of the response then outputs the ATA IDENTIFY (PACKET) DEVICE response in hexadecimal bytes (not 16 bit words). When used three times with the ATA Information VPD page [0x89] or the \fI\-\-ata\fR option, this utility outputs the ATA IDENTIFY (PACKET) DEVICE response in hexadecimal words suitable for input to 'hdparm \-\-Istdin'. See note below. .br To generate output suitable for placing in a file that can be used by a later invocation with the \fI\-\-inhex=FN\fR option, use the '\-HHHH' option (e.g. 'sg_inq \-p di -HHHH /dev/sg3 > dev_id.hex'). .TP \fB\-i\fR, \fB\-\-id\fR prints the device identification VPD page [0x83]. .TP \fB\-I\fR, \fB\-\-inhex\fR=\fIFN\fR \fIFN\fR is expected to be a file name (or '\-' for stdin) which contains ASCII hexadecimal or binary representing an INQUIRY (including VPD page) response. This utility will then decode that response. It is preferable to also supply the \fI\-\-page=PG\fR option, if not this utility will attempt to guess which VPD page (or standard INQUIRY) the response is associated with. The hexadecimal should be arranged as 1 or 2 digits representing a byte each of which is whitespace or comma separated. Anything from and including a hash mark to the end of line is ignored. If the \fI\-\-raw\fR option is also given then \fIFN\fR is treated as binary. .TP \fB\-l\fR, \fB\-\-len\fR=\fILEN\fR the number \fILEN\fR is the "allocation length" field in the INQUIRY cdb. This is the (maximum) length of the response to be sent by the device. The default value of \fILEN\fR is 0 which is interpreted as: first request is for 36 bytes and if necessary execute another INQUIRY if the "additional length" field in the response indicates that more than 36 bytes is available. If \fILEN\fR is greater than 0 then only one INQUIRY command is performed. See paragraph below about "36 byte INQUIRYs". .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR this option has the same action as the \fI\-\-len=LEN\fR option. It has been added for compatibility with the sg_vpd, sg_modes and sg_logs utilities. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-p\fR, \fB\-\-page\fR=\fIPG\fR the \fIPG\fR argument can be either a number of an abbreviation for a VPD page. To enumerate the available abbreviations for VPD pages use '\-hh' or a bad abbreviation (e.g, '\-\-page=xxx'). When the \fI\-\-cmddt\fR option is given (once) then \fIPG\fR is interpreted as an opcode number (so VPD page abbreviations make little sense). .br If \fIPG\fR is a negative number, then a standard INQUIRY is performed. This can be used to override some guessing logic associated with the \fI\-\-inhex=FN\fR option. .TP \fB\-r\fR, \fB\-\-raw\fR in the absence of \fI\-\-inhex=FN\fR then output response in binary. The output should be piped to a file or another utility when this option is used. The binary is sent to stdout, and errors are sent to stderr. .br if used with \fI\-\-inhex=FN\fR then the contents of \fIFN\fR is treated as binary. .TP \fB\-s\fR, \fB\-\-vendor\fR output a standard INQUIRY response's vendor specific field from offset 36 to 55 in ASCII. When used twice (i.e. '\-ss') also output the vendor specific field from offset 96 in ASCII. This is only done if the data passes some simple sanity checks. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .TP \fB\-e\fR, \fB\-\-vpd\fR set the Enable Vital Product Data (EVPD) bit (defaults to clear(0)). Used in conjunction with the \fI\-\-page=PG\fR option where \fIPG\fR specifies the VPD page number to query. If the \fI\-\-page=PG\fR is not given then \fIPG\fR defaults to zero which is the "Supported VPD pages" VPD page. .SH NOTES Some devices with weak SCSI command set implementations lock up when they receive commands they don't understand (or even response lengths that they don't expect). Such devices need to be treated carefully, use the '\-\-len=36' option. Without this option this utility will issue an initial standard INQUIRY requesting 36 bytes of response data. If the device indicates it could have supplied more data then a second INQUIRY is issued to fetch the longer response. That second command may lock up faulty devices. .PP ATA or ATAPI devices that use a SCSI to ATA Translation layer (see SAT at www.t10.org) may support the ATA Information VPD page. This returns the IDENTIFY (PACKET) DEVICE response amongst other things. The ATA Information VPD page can be fetched with '\-\-page=ai'. .PP In the INQUIRY standard response there is a 'MultiP' flag which is set when the device has 2 or more ports. Some vendors use the preceding vendor specific ('VS') bit to indicate which port is being accessed by the INQUIRY command (0 \-> relative port 1 (port "a"), 1 \-> relative port 2 (port "b")). When the 'MultiP' flag is set, the preceding vendor specific bit is shown in parentheses. SPC\-3 compliant devices should use the device identification VPD page (0x83) to show which port is being used for access and the SCSI ports VPD page (0x88) to show all available ports on the device. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. disks and ATAPI DVDs) can also be specified. For example "sg_inq /dev/sda" will work in the 2.6 series kernels. From lk 2.6.6 other SCSI "char" device names may be used as well (e.g. "/dev/st0m"). .PP The number of bytes output by \fI\-\-hex\fR and \fI\-\-raw\fR is 36 bytes or the number given to \fI\-\-len=LEN\fR (or \fI\-\-maxlen=LEN\fR). That number is reduced if the "resid" returned by the HBA indicates less bytes were sent back from \fIDEVICE\fR. .PP The \fIDEVICE\fR is opened with a read\-only flag (e.g. in Unix with the O_RDONLY flag). .SH ATA DEVICES There are two major types of ATA devices: non\-packet devices (e.g. ATA disks) and packet devices (ATAPI). The majority of ATAPI devices are CD/DVD/BD drives in which the ATAPI transport carries the MMC set (i.e. a SCSI command set). Further, both types of ATA devices can be connected to a host computer via a "SCSI" (or some other) transport. When an ATA disk is controlled via a SCSI (or non\-ATA) transport then two approaches are commonly used: tunnelling (e.g. STP in Serial Attached SCSI (SAS)) or by emulating a SCSI device (e.g. with a SCSI to ATA translation layer, see SAT at www.t10.org ). Even when the physical transport to the host computer is ATA (especially in the case of SATA) the operating system may choose to put a SAT layer in the driver "stack" (e.g. libata in Linux). .PP The main identifying command for any SCSI device is an INQUIRY. The corresponding command for an ATA non\-packet device is IDENTIFY DEVICE while for an ATA packet device it is IDENTIFY PACKET DEVICE. .PP When this utility is invoked for an ATAPI device (e.g. a CD/DVD/BD drive with "sg_inq /dev/hdc") then a SCSI INQUIRY is sent to the device and if it responds then the response to decoded and output and this utility exits. To see the response for an ATA IDENTIFY PACKET DEVICE command add the \fI\-\-ata\fR option (e.g. "sg_inq \-\-ata /dev/hdc). .PP This utility doesn't decode the response to an ATA IDENTIFY (PACKET) DEVICE command, hdparm does a good job at that. The '\-HHH' option has been added for use with either the '\-\-ata' or '\-\-page=ai' option to produce a format acceptable to "hdparm \-\-Istdin". An example: 'sg_inq \-\-ata \-HHH /dev/hdc | hdparm \-\-Istdin'. See hdparm. .SH EXIT STATUS The exit status of sg_inq is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using \fI\-\-old\fR (or \fI\-O\fR) as the first option. .TP \fB\-36\fR only requests 36 bytes of response data for an INQUIRY. Furthermore even if the device indicates in its response it can supply more data, a second (longer) INQUIRY is not performed. This is a paranoid setting. Equivalent to '\-\-len=36' in the OPTIONS section. .TP \fB\-a\fR fetch the ATA Information VPD page [0x89]. Equivalent to '\-\-page=ai' in the OPTIONS section. This page is defined in SAT (see at www.t10.org). .TP \fB\-A\fR Assume given \fIDEVICE\fR is an ATA or ATAPI device. Equivalent to \fI\-\-ata\fR in the OPTIONS section. .TP \fB\-b\fR decodes the Block Limits VPD page [0xb0]. Equivalent to '\-\-page=bl' in the OPTIONS section. This page is defined in SBC\-2 (see www.t10.org). .TP \fB\-B\fR=\fI0|1\fR equivalent to \fI\-\-block=0|1\fR in OPTIONS section. .TP \fB\-c\fR set the Command Support Data (CmdDt) bit (defaults to clear(0)). Used in conjunction with the \fI\-o=OPCODE_PG\fR option to specify the SCSI command opcode to query. Equivalent to \fI\-\-cmddt\fR in the OPTIONS section. .TP \fB\-cl\fR lists the command data for all supported commands (followed by the command name) by looping through all 256 opcodes. This option uses the CmdDt bit which is now obsolete. See the sg_opcodes(8) utility. Equivalent to '\-\-cmddt \-\-cmddt' in the OPTIONS section. .TP \fB\-d\fR decodes depending on context. If \fI\-e\fR option is given, or any option that implies \fI\-e\fR (e.g. '\-i' or '\-p=80'), then this utility attempts to decode the indicated VPD page. Otherwise the version descriptors (if any) are listed following a standard INQUIRY response. In the version descriptors sense, equivalent to \fI\-\-descriptors\fR in the OPTIONS section. .TP \fB\-e\fR enable (i.e. sets) the Vital Product Data (EVPD) bit (defaults to clear(0)). Used in conjunction with the \fI\-p=VPD_PG\fR option to specify the VPD page to fetch. If \fI\-p=VPD_PG\fR is not given then VPD page 0 (list supported VPD pages) is assumed. .TP \fB\-h\fR outputs INQUIRY response in hex rather than trying to decode it. Equivalent to \fI\-\-hex\fR in the OPTIONS section. .TP \fB\-H\fR same action as \fI\-h\fR. Equivalent to \fI\-\-hex\fR in the OPTIONS section. .TP \fB\-i\fR decodes the Device Identification VPD page [0x83]. Equivalent to \fI\-\-id\fR in the OPTIONS section. This page is made up of several "designation descriptors". If \fI\-h\fR is given then each descriptor header is decoded and the identifier itself is output in hex. To see the whole VPD 0x83 page response in hex use '\-p=83 \-h'. .TP \fB\-I\fR=\fIFN\fR equivalent to \fI\-\-inhex=FN\fR in the OPTIONS section. .TP \fB\-m\fR decodes the Management network addresses VPD page [0x85]. Equivalent to '\-\-page=mna' in the OPTIONS section. .TP \fB\-M\fR decodes the Mode page policy VPD page [0x87]. Equivalent to '\-\-page=mpp' in the OPTIONS section. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-o\fR=\fIOPCODE_PG\fR used in conjunction with the \fI\-e\fR or \fI\-c\fR option. If neither given then the \fI\-e\fR option assumed. When the \fI\-e\fR option is also given (or assumed) then the argument to this option is the VPD page number. The argument is interpreted as hexadecimal and is expected to be in the range 0 to ff inclusive. Only VPD page 0 is decoded and it lists supported VPD pages and their names (if known). To decode the mandatory device identification page (0x83) use the \fI\-i\fR option. A now obsolete usage is when the \fI\-c\fR option is given in which case the argument to this option is assumed to be a command opcode number. Recent SCSI draft standards have moved this facility to a separate command (see sg_opcodes(8)). Defaults to 0 so if \fI\-e\fR is given without this option then VPD page 0 is output. .TP \fB\-p\fR=\fIVPD_PG\fR same action as \fI\-o=OPCODE_PG\fR option described in the previous entry. Since the opcode value with the CmdDt is now obsolete, the main use of this option is to specify the VPD page number. The argument is interpreted as hexadecimal and is expected to be in the range 0 to ff inclusive. Defaults to 0 so if \fI\-e\fR is given without this option then VPD page 0 is output. .TP \fB\-P\fR decodes the Unit Path Report VPD page [0xc0] which is EMC specific. Equivalent to '\-\-page=upr' in the OPTIONS section. .TP \fB\-r\fR outputs the response in binary to stdout. Equivalent to \fI\-\-raw\fR in the OPTIONS section. Can be used twice (i.e. '\-rr' (and '\-HHH' has same effect)) and if used with the \fI\-A\fR or \fI\-a\fR option yields output with the same format as "cat /proc/ide/hd/identify" so that it can then be piped to "hdparm \-\-Istdin". .TP \fB\-s\fR decodes the SCSI Ports VPD page [0x88]. Equivalent to '\-\-page=sp' in the OPTIONS section. .TP \fB\-u\fR equivalent to '\-\-export' in the OPTIONS section. .TP \fB\-v\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR print out version string then exit. .TP \fB\-x\fR decodes the Extended INQUIRY data VPD [0x86] page. Equivalent to '\-\-page=ei' in the OPTIONS section. .TP \fB\-?\fR output usage message and exit. Ignore all other parameters. .SH EXAMPLES The examples in this page use Linux device names. For suitable device names in other supported Operating Systems see the sg3_utils(8) man page. .PP To view the standard inquiry response use without options: .PP sg_inq /dev/sda .PP Some SCSI devices include version descriptors indicating the various SCSI standards and drafts they support. They can be viewed with: .PP sg_inq \-d /dev/sda .PP Modern SCSI devices include Vital Product Data (VPD)pages which can be viewed with the SCSI INQUIRY command. To list the supported VPD pages (but not their contents) try: .PP sg_inq \-e /dev/sda .PP Some VPD pages can be read with the sg_inq utility but a newer utility called sg_vpd specializes in showing their contents. The sdparm utility can also be used to show the contents of VPD pages. .PP Further examples of sg_inq together with some typical output can be found on http://sg.danny.cz/sg/sg3_utils.html web page. .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2001\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_opcodes(8), sg_vpd(8), sdparm(8), hdparm(8), sgdiag(scsirastools) sg3_utils-1.40/doc/scsi_start.80000664000175000017500000000255012144707462015375 0ustar douggdougg.TH SCSI_START "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME scsi_start \- start one or more SCSI disks .SH SYNOPSIS .B scsi_start [\fI\-\-help\fR] [\fI\-\-verbose\fR] [\fI\-\-wait\fR] \fIDEVICE\fR [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP This bash shell script calls the sg_start utility on each given \fIDEVICE\fR. The purpose is to spin up (start) each given \fIDEVICE\fR. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-h\fR, \fB\-\-help\fR print out the usage message then exit. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level or verbosity. .TP \fB\-w\fR, \fB\-\-wait\fR wait for the spin up (start) on each given \fIDEVICE\fR to complete. The default action is to do each start in immediate mode. .SH NOTES If a large number of disks are spun up at the same time (i.e. without the \fI\-\-wait\fR option) then the power supply may be overloaded. .SH EXIT STATUS The exit status of this script is 0 when it is successful. Otherwise the exit status is that of the last sg_start utility called. See the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert .SH COPYRIGHT Copyright \(co 2009\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_start (sg3_utils) sg3_utils-1.40/doc/sg3_utils.80000664000175000017500000005424312414667052015141 0ustar douggdougg.TH SG3_UTILS "8" "October 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg3_utils \- a package of utilities for sending SCSI commands .SH SYNOPSIS .B sg_* [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-raw\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fIOTHER_OPTIONS\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP sg3_utils is a package of utilities that send SCSI commands to the given \fIDEVICE\fR via a SCSI pass through interface provided by the host operating system. .PP The names of all utilities start with "sg" and most start with "sg_" often followed by the name, or a shortening of the name, of the SCSI command that they send. For example the "sg_verify" utility sends the SCSI VERIFY command. A mapping between SCSI commands and the sg3_utils utilities that issue them is shown in the COVERAGE file. The sg_raw utility can be used to send an arbitrary SCSI command (supplied on the command line) to the given \fIDEVICE\fR. .PP sg_decode_sense can be used to decode SCSI sense data given on the command line or in a file. sg_raw \-vvv will output the T10 name of a given SCSI CDB which is most often 16 bytes or less in length. .PP SCSI draft standards can be found at http://www.t10.org . The standards themselves can be purchased from ANSI and other standards organizations. A good overview of various SCSI standards can be seen in http://www.t10.org/scsi\-3.htm with the SCSI command sets in the upper part of the diagram. SCSI commands in common with all device types can be found in SPC of which SPC\-4 is the latest major version. Block device specific commands (e.g. as used by disks) are in SBC, those for tape drives in SSC and those for CD/DVD/BD drives in MMC. .PP It is becoming more common to control ATA disks with the SCSI command set. This involves the translation of SCSI commands to their corresponding ATA equivalents (and that is an imperfect mapping in some cases). The relevant standard is called SCSI to ATA Translation (SAT and SAT\-2 are now standards at INCITS(ANSI) and ISO while SAT\-3 is at the draft stage). The logic to perform the command translation is often called a SAT Layer or SATL and may be within an operating system, in host bus adapter firmware or in an external device (e.g. associated with a SAS expander). See http://www.t10.org for more information. .PP There is some support for SCSI tape devices but not for their basic commands. The reader is referred to the "mt" utility. .PP There are two generations of command line option usage. The newer utilities (written since July 2004) use the getopt_long() function to parse command line options. With that function, each option has two representations: a short form (e.g. '\-v') and a longer form (e.g. '\-\-verbose'). If an argument is required then it follows a space (optionally) in the short form and a "=" in the longer form (e.g. in the sg_verify utility '\-l 2a6h' and '\-\-lba=2a6h' are equivalent). Note that with getopt_long(), short form options can be elided, for example: '\-all' is equivalent to '\-a \-l \-l'. The \fIDEVICE\fR argument may appear after, between or prior to any options. .PP The older utilities, such as sg_inq, had individual command line processing code typically based on a single "\-" followed by one or more characters. If an argument is needed then it follows a "=" (e.g. '\-p=1f' in sg_modes with its older interface). Various options can be elided as long as it is not ambiguous (e.g. '\-vv' to increase the verbosity). .PP Over time the command line interface of these older utilities became messy and overloaded with options. So in sg3_utils version 1.23 the command line interface of these older utilities was altered to have both a cleaner getopt_long() interface and their older interface for backward compatibility. By default these older utilities use their getopt_long() based interface. That can be overridden by defining the SG3_UTILS_OLD_OPTS environment variable or using '\-O' or '\-\-old' as the first command line option. The man pages of the older utilities documents the details. .PP Several sg3_utils utilities are based on the Unix dd command (e.g. sg_dd) and permit copying data at the level of SCSI READ and WRITE commands. sg_dd is tightly bound to Linux and hence is not ported to other OSes. A more generic utility (than sg_dd) called ddpt in a package of the same name has been ported to other OSes. .SH LINUX DEVICE NAMING Most disk block devices have names like /dev/sda, /dev/sdb, /dev/sdc, etc. SCSI disks in Linux have always had names like that but in recent Linux kernels it has become more common for many other disks (including SATA disks and USB storage devices) to be named like that. Partitions within a disk are specified by a number appended to the device name, starting at 1 (e.g. /dev/sda1 ). .PP Tape drives are named /dev/st or /dev/nst where starts at zero. Additionally one letter from this list: "lma" may be appended to the name. CD, DVD and BD readers (and writers) are named /dev/sr where start at zero. There are less used SCSI device type names, the dmesg and the lsscsi commands may help to find if any are attached to a running system. .PP There is also a SCSI device driver which offers alternate generic access to SCSI devices. It uses names of the form /dev/sg where starts at zero. The "lsscsi \-g" command may be useful in finding these and which generic name corresponds to a device type name (e.g. /dev/sg2 may correspond to /dev/sda). In the lk 2.6 series a block SCSI generic driver was introduced and its names are of the form /dev/bsg/ where h, c, t and l are numbers. Again see the lsscsi command to find the correspondence between that SCSI tuple (i.e. ) and alternate device names. .PP Prior to the Linux kernel 2.6 series these utilities could only use generic device names (e.g. /dev/sg1 ). In almost all cases in the Linux kernel 2.6 series, any device name can be used by these utilities. .PP Very little has changed in Linux device naming in the lk 3 series. .SH WINDOWS DEVICE NAMING Storage and related devices can have several device names in Windows. Probably the most common in the volume name (e.g. "D:"). There are also a "class" device names such as "PhysicalDrive", "CDROM" and "TAPE". is an integer starting at 0 allocated in ascending order as devices are discovered (and sometimes rediscovered). .PP Some storage devices have a SCSI lower level device name which starts with a SCSI (pseudo) adapter name of the form "SCSI:". To this is added sub\-addressing in the form of a "bus" number, a "target" identifier and a LUN (Logical Unit Number). The "bus" number is also known as a "PathId". These are assembled to form a device name of the form: "SCSI:,,". The trailing "," may be omitted in which case a LUN of zero is assumed. This lower level device name cannot often be used directly since Windows blocks attempts to use it if a class driver has "claimed" the device. There are SCSI device types (e.g. Automation/Drive interface type) for which there is no class driver. At least two transports ("bus types" in Windows jargon): USB and IEEE 1394 do not have a "scsi" device names of this form. .PP In keeping with DOS file system conventions, the various device names can be given in upper, lower or mixed case. Since "PhysicalDrive" is tedious to write, a shortened form of "PD" is permitted by all utilities in this package. .PP A single device (e.g. a disk) can have many device names. For example: "PD0" can also be "C:", "D:" and "SCSI0:0,1,0". The two volume names reflect that the disk has two partitions on it. Disk partitions that are not recognized by Windows are not usually given a volume name. However Vista does show a volume name for a disk which has no partitions recognized by it and when selected invites the user to format it (which may be rather unfriendly to other OSes). .PP These utilities assume a given device name is in the Win32 device namespace. To make that explicit "\\\\.\\" can be prepended to the device names mentioned in this section. Beware that backslash is an escape character in Unix like shells and the C programming language. In a shell like Msys (from MinGW) each backslash may need to be typed twice. .PP The sg_scan utility within this package lists out Windows device names in a form that is suitable for other utilities in this package to use. .SH FREEBSD DEVICE NAMING SCSI disks have block names of the form /dev/da where is an integer starting at zero. The "da" is replaced by "sa" for SCSI tape drives and "cd" for SCSI CD/DVD/BD drives. Each SCSI device has a corresponding pass\-through device name of the form /dev/pass where is an integer starting at zero. The "camcontrol devlist" command may be useful for finding out which SCSI device names are available and the correspondence between class and pass\-through names. .SH SOLARIS DEVICE NAMING SCSI device names below the /dev directory have a form like: c5t4d3s2 where the number following "c" is the controller (HBA) number, the number following "t" is the target number (from the SCSI parallel interface days) and the number following "d" is the LUN. Following the "s" is the slice number which is related to a partition and by convention "s2" is the whole disk. .PP OpenSolaris also has a c5t4d3p2 form where the number following the "p" is the partition number apart from "p0" which is the whole disk. So a whole disk may be referred to as either c5t4d3, c5t4d3s2 or c5t4d3p0 . .PP And these device names are duplicated in the /dev/dsk and /dev/rdsk directories. The former is the block device name and the latter is for "raw" (or char device) access which is what sg3_utils needs. So in OpenSolaris something of the form 'sg_inq /dev/rdsk/c5t4d3p0' should work. If it doesn't work then add a '\-vvv' option for more debug information. Trying this form 'sg_inq /dev/dsk/c5t4d3p0' (note "rdsk" changed to "dsk") will result in an "inappropriate ioctl for device" error. .PP The device names within the /dev directory are typically symbolic links to much longer topological names in the /device directory. In Solaris cd/dvd/bd drives seem to be treated as disks and so are found in the /dev/rdsk directory. Tape drives appear in the /dev/rmt directory. .PP There is also a sgen (SCSI generic) driver which by default does not attach to any device. See the /kernel/drv/sgen.conf file to control what is attached. Any attached device will have a device name of the form /dev/scsi/c5t4d3 . .PP Listing available SCSI devices in Solaris seems to be a challenge. "Use the 'format' command" advice works but seems a very dangerous way to list devices. [It does prompt again before doing any damage.] 'devfsadm \-Cv' cleans out the clutter in the /dev/rdsk directory, only leaving what is "live". The "cfgadm \-v" command looks promising. .SH EXIT STATUS To aid scripts that call these utilities, the exit status is set to indicate success (0) or failure (1 or more). Note that some of the lower values correspond to the SCSI sense key values. The exit status values are: .TP .B 0 success .TP .B 1 syntax error. Either illegal command line options, options with bad arguments or a combination of options that is not permitted. .TP .B 2 the \fIDEVICE\fR reports that it is not ready for the operation requested. The device may be in the process of becoming ready (e.g. spinning up but not at speed) so the utility may work after a wait. .TP .B 3 the \fIDEVICE\fR reports a medium or hardware error (or a blank check). For example an attempt to read a corrupted block on a disk will yield this value. .TP .B 5 the \fIDEVICE\fR reports an "illegal request" with an additional sense code other than "invalid command operation code". This is often a supported command with a field set requesting an unsupported capability. For commands that require a "service action" field this value can indicate that the command with that service action value is not supported. .TP .B 6 the \fIDEVICE\fR reports a "unit attention" condition. This usually indicates that something unrelated to the requested command has occurred (e.g. a device reset) potentially before the current SCSI command was sent. The requested command has not been executed by the device. Note that unit attention conditions are usually only reported once by a device. .TP .B 7 the \fIDEVICE\fR reports a "data protect" sense key. This implies some mechanism has blocked writes (or possibly all access to the media). .TP .B 9 the \fIDEVICE\fR reports an illegal request with an additional sense code of "invalid command operation code" which means that it doesn't support the requested command. .TP .B 10 the \fIDEVICE\fR reports a "copy aborted". This implies another command or device problem has stopped a copy operation. The EXTENDED COPY family of commands (including WRITE USING TOKEN) may return this sense key. .TP .B 11 the \fIDEVICE\fR reports an aborted command. In some cases aborted commands can be retried immediately (e.g. if the transport aborted the command due to congestion). .TP .B 14 the \fIDEVICE\fR reports a miscompare sense key. VERIFY and COMPARE AND WRITE commands may report this. .TP .B 15 the utility is unable to open, close or use the given \fIDEVICE\fR or some other file. The given file name could be incorrect or there may be permission problems. Adding the '\-v' option may give more information. .TP .B 20 the \fIDEVICE\fR reports it has a check condition but "no sense" and non\-zero information in its additional sense codes. Some polling commands (e.g. REQUEST SENSE) can receive this response. There may be useful information in the sense data such as a progress indication. .TP .B 21 the \fIDEVICE\fR reports a "recovered error". The requested command was successful. Most likely a utility will report a recovered error to stderr and continue, probably leaving the utility with an exit status of 0 . .TP .B 24 the \fIDEVICE\fR reports a SCSI status of "reservation conflict". This means access to the \fIDEVICE\fR with the current command has been blocked because another machine (HBA or SCSI "initiator") holds a reservation on this \fIDEVICE\fR. On modern SCSI systems this is related to the use of the PERSISTENT RESERVATION family of commands. .TP .B 33 the command sent to \fIDEVICE\fR has timed out. .TP .B 40 the command sent to \fIDEVICE\fR has received an "aborted command" sense key with an additional sense code of 0x10. This group is related to problems with protection information (PI or DIF). For example this error may occur when reading a block on a drive that has never been written (or is unmapped) if that drive was formatted with type 1, 2 or 3 protection. .TP .B 97 a SCSI command response failed sanity checks. .TP .B 98 the \fIDEVICE\fR reports it has a check condition but the error doesn't fit into any of the above categories. .TP .B 99 any errors that can't be categorized into values 1 to 98 may yield this value. This includes transport and operating system errors after the command has been sent to the device. .TP .B 126 the utility was found but could not be executed. That might occur if the executable does not have execute permissions. .TP .B 127 This is the exit status for utility not found. That might occur when a script calls a utility in this package but the PATH environment variable has not been properly set up, so the script cannot find the executable. .TP .B 128 + If a signal kills a utility then the exit status is 128 plus the signal number. For example if a segmentation fault occurs then a utility is typically killed by SIGSEGV which according to 'man 7 signal' has an associated signal number of 11; so the exit status will be 139 . .TP .B 255 the utility tried to yield an exit status of 255 or larger. That should not happen; given here for completeness. .PP Most of the error conditions reported above will be repeatable (an example of one that is not is "unit attention") so the utility can be run again with the '\-v' option (or several) to obtain more information. .SH COMMON OPTIONS Arguments to long options are mandatory for short options as well. In the short form an argument to an option uses zero or more spaces as a separator (i.e. the short form does not use "=" as a separator). .PP If an option takes a numeric argument then that argument is assumed to be decimal unless otherwise indicated (e.g. with a leading "0x", a trailing "h" or as noted in the usage message). .PP Some options are used uniformly in most of the utilities in this package. Those options are listed below. Note that there are some exceptions. .TP \fB\-h\fR, \fB\-?\fR, \fB\-\-help\fR output the usage message then exit. In a few older utilities the '\-h' option requests hexadecimal output. In these cases the '\-?' option will output the usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR for SCSI commands that yield a non\-trivial response, print out that response in ASCII hexadecimal. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR several important SCSI commands (e.g. INQUIRY and MODE SENSE) have response lengths that vary depending on many factors, only some of which these utilities take into account. The maximum response length is typically specified in the 'allocation length' field of the cdb. In the absence of this option, several utilities use a default allocation length (sometimes recommended in the SCSI draft standards) or a "double fetch" strategy. See sg_logs(8) for its description of a "double fetch" strategy. These techniques are imperfect and in the presence of faulty SCSI targets can cause problems (e.g. some USB mass storage devices freeze if they receive an INQUIRY allocation length other than 36). Also use of this option disables any "double fetch" strategy that may have otherwise been used. .TP \fB\-r\fR, \fB\-\-raw\fR for SCSI commands that yield a non\-trivial response, output that response in binary to stdout. If any error messages or warning are produced they are usually sent to stderr. Some utilities that consume data to send to the device along with the SCSI command, use this option to provide that data or indicate that it can be read from stdin. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). Can be used multiple times to further increase verbosity. The additional output is usually sent to stderr. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. Each utility has its own version number and date of last code change. .SH NUMERIC ARGUMENTS Many utilities have command line options that take numeric arguments. These numeric arguments can be large values (e.g. a logical block address (LBA) on a disk) and can be inconvenient to enter in the default decimal representation. So various other representations are permitted. .PP Multiplicative suffixes are accepted. They are one, two or three letter strings appended directly after the number to which they apply: .PP c C *1 .br w W *2 .br b B *512 .br k K KiB *1024 .br KB *1000 .br m M MiB *1048576 .br MB *1000000 .br g G GiB *(2^30) .br GB *(10^9) .br t T TiB *(2^40) .br TB *(10^12) .br p P PiB *(2^50) .br PB *(10^15) .PP An example is "2k" for 2048. The large tera and peta suffixes are only available for numeric arguments that might require 64 bits to represent internally. .PP A suffix of the form "x" multiplies the leading number by . An example is "2x33" for "66". The leading number cannot be "0" (zero) as that would be interpreted as a hexadecimal number (see below). .PP These multiplicative suffixes are compatible with GNU's dd command (since 2002) which claims compliance with SI and with IEC 60027\-2. .PP Alternatively numerical arguments can be given in hexadecimal. There are two syntaxes. The number can be preceded by either "0x" or "0X" as found in the C programming language. The second hexadecimal representation is a trailing "h" or "H" as found in (storage) standards. When hex numbers are given, multipliers cannot be used. For example the decimal value "256" can be given as "0x100" or "100h". .SH MICROCODE AND FIRMWARE There are two standardized methods for downloading microcode (i.e. device firmware) to a SCSI device. The more general way is with the SCSI WRITE BUFFER command, see the sg_write_buffer utility. SCSI enclosures have their own method based on the Download microcode control/status diagnostic page, see the sg_ses_microcode utility. .SH SCRIPTS, EXAMPLES and UTILS There are several bash shell scripts in the 'scripts' subdirectory that invoke compiled utilities (e.g. sg_readcap). Several of the scripts start with 'scsi_' rather than 'sg_'. One purpose of these scripts is to call the same utility (e.g. sg_readcap) on multiple devices. Most of the basic compiled utilities only allow one device as an argument. Some distributions install these scripts in a more visible directory (e.g. /usr/bin). Some of these scripts have man page entries. See the README file in the 'scripts' subdirectory. .PP There is some example C code plus examples of complex invocations in the 'examples' subdirectory. There is also a README file. The example C may be a simpler example of how to use a SCSI pass\-through in Linux than the main utilities (found in the 'src' subdirectory). This is due to the fewer abstraction layers (e.g. they don't worry the MinGW in Windows may open a file in text rather than binary mode). .PP Some utilities that the author has found useful have been placed in the 'utils' subdirectory. .SH WEB SITE There is a web page discussing this package at http://sg.danny.cz/sg/sg3_utils.html . The device naming used by this package on various operating systems is discussed at: http://sg.danny.cz/sg/device_name.html . .SH AUTHORS Written by Douglas Gilbert. Some utilities have been contributed, see the CREDITS file and individual source files (in the 'src' directory). .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 1999\-2014 Douglas Gilbert .br Some utilities are distributed under a GPL version 2 license while others, usually more recent ones, are under a FreeBSD license. The files that are common to almost all utilities and thus contain the most reusable code, namely sg_lib.[hc], sg_cmds_basic.[hc] and sg_cmds_extra.[hc] are under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sdparm(sdparm), ddpt(ddpt), lsscsi(lsscsi), dmesg(1), mt(1) sg3_utils-1.40/doc/sg_emc_trespass.80000664000175000017500000000373712065221552016401 0ustar douggdougg.TH SG_EMC_TRESPASS "8" "December 2012" "sg3_utils\-1.35" SG3_UTILS .SH NAME sg_emc_trespass \- change ownership of SCSI LUN from another Service\-Processor to this one .SH SYNOPSIS .B sg_emc_trespass [\fI\-d\fR] [\fI\-hr\fR] [\fI\-s\fR] [\fI\-V\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP sg_emc_trespass sends an EMC\-specific Trespass Command to the \fIDEVICE\fR with the selected options. This Mode Select changes the ownership of the LUN of the device from another Service\-Processor to the one the command was received on. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR outputs some extra debug information associated with executing this command .TP \fB\-hr\fR Sets the 'Honor Reservation' bit in the command. If set, the trespass will only succeed to change the ownership from the Peer SP if the Peer SP does not have an outstanding SCSI reservation for the LUN. By default, the reservation state will be ignored. .TP \fB\-s\fR Send the short version of the trespass command instead of the long version. The short version is supported on the EMC FC5300, FC4500 and FC4700. The long version (default) is supported on the CLARiiON CX and AX family arrays. .TP \fB\-V\fR print out version string then exit. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. For example "sg_start 0 /dev/sda" will work in the 2.6 series kernels. .SH EXIT STATUS The exit status of sg_emc_trespass is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHOR Written by Lars Marowsky\-Bree, based on sg_start. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2012 Lars Marowsky\-Bree, Douglas Gilbert. .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. sg3_utils-1.40/doc/sg_senddiag.80000664000175000017500000002767412407706337015506 0ustar douggdougg.TH SG_SENDDIAG "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_senddiag \- performs a SCSI SEND DIAGNOSTIC command .SH SYNOPSIS .B sg_senddiag [\fI\-\-doff\fR] [\fI\-\-extdur\fR] [\fI\-\-help\fR] [\fI\-\-hex\fR] [\fI\-\-list\fR] [\fI\-\-maxlen=LEN\fR] [\fI\-\-page=PG\fR] [\fI\-\-pf\fR] [\fI\-\-raw=H,H...\fR] [\fI\-\-raw=\-\fR] [\fI\-\-selftest=ST\fR] [\fI\-\-test\fR] [\fI\-\-uoff\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] \fIDEVICE\fR .PP .B sg_senddiag [\fI\-doff\fR] [\fI\-e\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-l\fR] [\fI\-pf\fR] [\fI\-raw=H,H...\fR] [\fI\-raw=\-\fR] [\fI\-s=ST\fR] [\fI\-t\fR] [\fI\-uoff\fR] [\fI\-v\fR] [\fI\-V\fR] [\fI\-?\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP This utility sends a SCSI SEND DIAGNOSTIC command to the \fIDEVICE\fR. It can issue self\-tests, find supported diagnostic pages or send arbitrary diagnostic pages. .PP When the \fI\-\-list\fR option and a \fIDEVICE\fR are given then the utility sends a SCSI RECEIVE DIAGNOSTIC RESULTS command to fetch the response (i.e. the page numbers of supported diagnostic pages). .PP When the \fI\-\-list\fR option is given without a \fIDEVICE\fR then a list of diagnostic page names and their numbers, known by this utility, are listed. .PP This utility supports two command line syntax\-es, the preferred one is shown first in the synopsis and explained in this section. A later section on the old command line syntax outlines the second group of options. .SH OPTIONS Arguments to long options are mandatory for short options as well. .TP \fB\-d\fR, \fB\-\-doff\fR set the Device Offline (DevOffL) bit (default is clear). Only significant when \fI\-\-test\fR option is set for the default self\-test. When set other operations on any logical units controlled by the this device server (target) may be affected (delayed) while a default self\-test is underway. .TP \fB\-e\fR, \fB\-\-extdur\fR outputs the expected extended self\-test duration. The duration is given in seconds (and minutes in parentheses). This figure is obtained from mode page 0xa (i.e. the control mode page). .TP \fB\-h\fR, \fB\-\-help\fR print usage message then exit. .TP \fB\-H\fR, \fB\-\-hex\fR outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode it. .TP \fB\-l\fR, \fB\-\-list\fR when a \fIDEVICE\fR is also given lists the names of all diagnostic pages supported by this device. The request is sent via a SEND DIAGNOSTIC command (with the "pF" bit set) and the response is fetched by a RECEIVE DIAGNOSTIC RESULTS command. When used in the absence of a \fI\-\-list\fR argument then a list of diagnostic page names and their numbers, known by this utility, are listed. .TP \fB\-m\fR, \fB\-\-maxlen\fR=\fILEN\fR where \fILEN\fR is the value placed in the parameter list length field of a SEND DIAGNOSTIC command or in the allocation length field of a RECEIVE DIAGNOSTIC RESULTS command. This only occurs when the other options imply there will be data sent or received by the command. The default value is 4096 bytes. \fILEN\fR cannot exceed 65535 or 0xffff in hexadecimal. .TP \fB\-O\fR, \fB\-\-old\fR switch to older style options. .TP \fB\-P\fR, \fB\-\-page\fR=\fIPG\fR where \fIPG\fR is the RECEIVE DIAGNOSTIC RESULTS command page code field. If this option is given the PCV bit in that command is set. When this option is given then no SEND DIAGNOSTIC command is sent (unlike \fI\-\-list\fR). If \fIPG\fR is 0 then the response is decoded as if it is the SPC Supported Diagnostic pages diagnostic page. Other \fIPG\fR values (i.e. 1 to 255) have their responses output in hex. .TP \fB\-p\fR, \fB\-\-pf\fR set Page Format (PF) bit. By default it is clear (i.e. 0) unless the list \fI\-\-list\fR option is given in which case the Page Format bit is set (as required by SPC\-3). .TP \fB\-r\fR, \fB\-\-raw\fR=\fIH,H...\fR string of comma separated hex numbers each of which should resolve to a byte value (i.e. 0 to ff inclusive). A (single) space separated string of hex bytes is also allowed but the list needs to be in quotes. This sequence forms a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely the \fI\-\-pf\fR option should also be given. .TP \fB\-r\fR, \fB\-\-raw=\-\fR reads sequence of bytes from stdin. The sequence may be comma, space, tab or linefeed (newline) separated. If a line contains "#" then the remaining characters on that line are ignored. Otherwise each non separator character should resolve to a byte value (i.e. 0 to ff inclusive). This sequence forms a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely the \fI\-\-pf\fR option should also be given. .TP \fB\-s\fR, \fB\-\-selftest\fR=\fIST\fR where \fIST\fR is the self\-test code. The default value is 0 which is inactive. Some other values: .br \fB1\fR : background short self\-test .br \fB2\fR : background extended self\-test .br \fB4\fR : aborts a (background) self\-test that is in progress .br \fB5\fR : foreground short self\-test .br \fB6\fR : foreground extended self\-test .br This option is mutually exclusive with default self\-test (i.e. can't have (\fIST\fR > 0) and \fI\-\-test\fR). .TP \fB\-t\fR, \fB\-\-test\fR sets the _default_ Self Test (SelfTest) bit. By default this is clear (0). The \fI\-\-selftest=ST\fR option should not be active together with this option. Both the \fI\-\-doff\fR and/or \fI\-\-uoff\fR options can be used with this option. .TP \fB\-u\fR, \fB\-\-uoff\fR set the Unit Offline (UnitOffL) bit (default is clear). Only significant when \fI\-\-test\fR option is set for the default self\-test. When set other operations on this logical unit may be affected (delayed) while a default self\-test is underway. Some devices (e.g. Fujitsu disks) do more tests when this bit is set. .TP \fB\-v\fR, \fB\-\-verbose\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR, \fB\-\-version\fR print out version string then exit. .SH NOTES All devices should support the default self\-test. The 'short' self\-test codes should complete in 2 minutes or less. The 'extended' self\-test codes' maximum duration is vendor specific (e.g. a little over 10 minutes with the author's disks). The foreground self\-test codes wait until they are completed while the background self\-test codes return immediately. The results of both foreground and background self\-test codes are placed in the 'self\-test results' log page (see sg_logs(8)). The SCSI command timeout for this utility is set to 60 minutes to allow for slow foreground extended self\-tests. .PP If the \fIDEVICE\fR is a disk then no file systems residing on that disk should be mounted during a foreground self\-test. The reason is that other SCSI commands may become queued behind the foreground self\-test and timeout. .PP When the \fI\-\-raw=H,H...\fR option is given then self\-tests should not be selected. However the \fB\-\-pf\fR (i.e. "page format") option should be given. The length of the diagnostic page to be sent is derived from the number of bytes given to the \fI\-\-raw=H,H...\fR option. The diagnostic page code (number) should be the first byte of the sequence (i.e. as dictated by SPC\-3 diagnostic page format). See the EXAMPLES section below. .PP Arbitrary diagnostic pages can be read (in hex) with the sg_ses(8) utility (not only those defined in SES\-2). .PP If the utility is used with no options (e.g. "sg_senddiag /dev/sg1") Then a degenerate SCSI SEND DIAGNOSTIC command is sent with zero in all its fields apart from the opcode. Some devices report this as an error while others ignore it. It is not entirely clear from SPC\-3 if it is invalid to send such a command. .PP In the 2.4 series of Linux kernels the \fIDEVICE\fR must be a SCSI generic (sg) device. In the 2.6 series block devices (e.g. SCSI disks and DVD drives) can also be specified. .PP To access SCSI enclosures see the sg_ses(8) utility. sg_ses uses the SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS commands as outlined in the SES\-2 (draft) standard. .SH EXIT STATUS The exit status of sg_senddiag is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH OLDER COMMAND LINE OPTIONS The options in this section were the only ones available prior to sg3_utils version 1.23 . In sg3_utils version 1.23 and later these older options can be selected by either setting the SG3_UTILS_OLD_OPTS environment variable or using '\-\-old' (or '\-O) as the first option. .TP \fB\-doff\fR set the Device Offline (DevOffL) bit (default is clear). Only significant when \fI\-t\fR option is set for the default self\-test. Equivalent to \fI\-\-doff\fR in the main description. .TP \fB\-e\fR outputs the expected extended self\-test duration. Equivalent to \fI\-\-extdur\fR in the main description. .TP \fB\-h\fR outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode it. .TP \fB\-H\fR outputs response from RECEIVE DIAGNOSTIC RESULTS in hex rather than decode it. .TP \fB\-l\fR when a \fIDEVICE\fR is also given lists the names of all diagnostic pages supported by this device. The request is sent via a SEND DIAGNOSTIC command (with the "pf" bit set) and the response is fetched by a RECEIVE DIAGNOSTIC RESULTS command. When used in the absence of a \fIDEVICE\fR argument then a list of diagnostic page names and their numbers, known by this utility, are listed. .TP \fB\-N\fR switch to the newer style options. .TP \fB\-pf\fR set Page Format (PF) bit. By default it is clear (i.e. 0) unless the \fI\-l\fR option is given in which case the Page Format bit is set (as required by SPC\-3). .TP \fB\-raw\fR=\fIH,H...\fR string of comma separated hex numbers each of which should resolve to a byte value (i.e. 0 to ff inclusive). This sequence forms a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely the \fI\-pf\fR option should also be given. .TP \fB\-raw=-\fR reads sequence of bytes from stdin. The sequence may be comma, space, tab or linefeed (newline) separated. If a line contains "#" then the remaining characters on that line are ignored. Otherwise each non separator character should resolve to a byte value (i.e. 0 to ff inclusive). This sequence forms a diagnostic page to be sent with the SCSI SEND DIAGNOSTIC command. Mostly likely the \fI\-pf\fR option should also be given. .TP \fB\-s\fR=\fIST\fR where \fIST\fR is the self\-test code. The default value is 0 which is inactive. A value of 1 selects a background short self\-test; 2 selects a background extended self\-test; 5 selects a foreground short self\-test; 6 selects a foreground extended test. A value of 4 will abort a (background) self\-test that is in progress. This option is mutually exclusive with default self\-test (i.e. \fI\-t\fR). .TP \fB\-t\fR sets the _default_ Self Test (SelfTest) bit. By default this is clear (0). The \fI\-s=ST\fR option should not be active together with this option. Both the \fI\-doff\fR and/or \fI\-uoff\fR options can be used with this option. .TP \fB\-uoff\fR set the Unit Offline (UnitOffL) bit (default is clear). Equivalent to \fI\-\-uoff\fR in the main description. .TP \fB\-v\fR increase level of verbosity. Can be used multiple times. .TP \fB\-V\fR print out version string then exit. .TP \fB\-?\fR output usage message. Ignore all other parameters. .SH EXAMPLES The examples sub\-directory in the sg3_utils packages contains two example scripts that turn on the CJTPAT (jitter pattern) on some SAS disks (one script for each phy). One possible invocation for phy 1 is: .PP sg_senddiag \-\-pf \-\-raw=\- /dev/sg2 < sdiag_sas_p1_cjtpat.txt .PP There is also an example script that turns on the IDLE pattern. Once a test pattern has been started it can be turned off by resetting the phy or with the STOP phy pattern function: .PP sg_senddiag \-\-pf \-\-raw=\- /dev/sg2 < sdiag_sas_p1_stop.txt .SH AUTHOR Written by Douglas Gilbert .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2003\-2014 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sg_ses(8), sg_logs(8), smartmontools(see net) sg3_utils-1.40/doc/sg_verify.80000664000175000017500000002424012206473566015220 0ustar douggdougg.TH SG_VERIFY "8" "August 2013" "sg3_utils\-1.37" SG3_UTILS .SH NAME sg_verify \- invoke SCSI VERIFY command(s) on a block device .SH SYNOPSIS .B sg_verify [\fI\-\-16\fR] [\fI\-\-bpc=BPC\fR] [\fI\-\-count=COUNT\fR] [\fI\-\-dpo\fR] [\fI\-\-ebytchk=BCH\fR] [\fI\-\-group=GN\fR] [\fI\-\-help\fR] [\fI\-\-in=IF\fR] [\fI\-\-lba=LBA\fR] [\fI\-\-ndo=NDO\fR] [\fI\-\-quiet\fR] [\fI\-\-readonly\fR] [\fI\-\-verbose\fR] [\fI\-\-version\fR] [\fI\-\-vrprotect=VRP\fR] \fIDEVICE\fR .SH DESCRIPTION .\" Add any additional description here .PP Sends one or more SCSI VERIFY (10 or 16) commands to \fIDEVICE\fR. These SCSI commands are defined in the SBC\-2 (draft) standard at http://www.t10.org and SBC\-3 drafts. .PP When \fI\-\-ndo=NDO\fR is not given then the verify starts at the logical block address given by the \fI\-\-lba=LBA\fR option and continues for \fI\-\-count=COUNT\fR blocks. No more than \fI\-\-bpc=BPC\fR blocks are verified by each VERIFY command so if necessary multiple VERIFY commands are sent. Medium verification operations are performed by the \fIDEVICE\fR (e.g. assuming each block has additional EEC data, check this against the logical block contents). No news is good news (i.e. if there are no verify errors detected then no messages are sent to stderr and the Unix exit status is 0). .PP When \fI\-\-ndo=NDO\fR is given then the \fI\-\-bpc=BPC\fR option is ignored. A single VERIFY command is issued and a comparison starts at the logical block address given by the \fI\-\-lba=LBA\fR option and continues for \fI\-\-count=COUNT\fR blocks. The VERIFY command has an associated data\-out buffer that is \fINDO\fR bytes long. The contents of the data\-out buffer are obtained from the \fIFN\fR file (if \fI\-\-in=FN\fR is given) or from stdin. A comparison takes place between data\-out buffer and the logical blocks on the \fIDEVICE\fR. If the comparison is good then no messages are sent to stderr and the Unix exit status is 0. If the comparison fails then a sense buffer with a sense key of MISCOMPARE is returned; in this case the Unix exit status will be 14. Messages will be sent to stderr associated with MISCOMPARE sense buffer unless the \fI\-\-quiet\fR option is given. .PP In SBC\-3 revision 34 the BYTCHK field in all SCSI VERIFY commands was expanded from one to two bits. That required some changes in the options of this utility, see the section below on OPTION CHANGES. .SH OPTIONS Arguments to long options are mandatory for short options as well. The options are arranged in alphabetical order based on the long option name. .TP \fB\-S\fR, \fB\-\-16\fR uses a VERIFY(16) command (default VERIFY(10)). Even without this option, using an \fI\-\-lba=LBA\fR which is too large, will cause the utility to issue a VERIFY(16) command. .TP \fB\-b\fR, \fB\-\-bpc\fR=\fIBPC\fR this option is ignored if \fI\-\-ndo=NDO\fR is given. Otherwise \fIBPC\fR specifies the maximum number of blocks that will be verified by a single SCSI VERIFY command. The default value is 128 blocks which equates to 64 KB for a disk with 512 byte blocks. If \fIBPC\fR is less than \fICOUNT\fR then multiple SCSI VERIFY commands are sent to the \fIDEVICE\fR. For the default VERIFY(10) \fIBPC\fR cannot exceed 0xffff (65,535) while for VERIFY(16) \fIBPC\fR cannot exceed 0x7fffffff (2,147,483,647). For recent block devices (disks) this value may be constrained by the maximum transfer length field in the block limits VPD page. .TP \fB\-c\fR, \fB\-\-count\fR=\fICOUNT\fR where \fICOUNT\fR specifies the number of blocks to verify. The default value is 1 . If \fICOUNT\fR is greater than \fIBPC\fR (or its default value of 128) and \fINDO\fR is not given, 0 or less then multiple SCSI VERIFY commands are sent to the device. Otherwise \fICOUNT\fR becomes the contents of the verification length field of the SCSI VERIFY command issued. The .B sg_readcap utility can be used to find the maximum number of blocks that a block device (e.g. a disk) has. .TP \fB\-d\fR, \fB\-\-dpo\fR disable page out changes the cache retention priority of blocks read on the device's cache to the lowest priority. This means that blocks read by other commands are more likely to remain in the device's cache. .TP \fB\-E\fR, \fB\-\-ebytchk\fR=\fIBCH\fR sets the BYTCHK field to \fIBCH\fR overriding the value (1) set by the \fI\-\-ndo=NDO\fR option. Values of 1, 2 or 3 are accepted for \fIBCH\fR however sbc3r34 reserves the value 2. If this option is given then \fI\-\-ndo=NDO\fR must also be given. If \fIBCH\fR is 3 then \fICOUNT\fR must be 1 and \fINDO\fR should be the size of one logical block (plus the size of some or all of the protection infomation if \fIVRP\fR is greater than 0). .TP \fB\-g\fR, \fB\-\-group\fR=\fIGN\fR where \fIGN\fR becomes the contents of the group number field in the SCSI VERIFY(16) command. The default value for \fIGN\fR is 0. Note that this option is ignored for the SCSI VERIFY(10) command. .TP \fB\-h\fR, \fB\-\-help\fR output the usage message then exit. .TP \fB\-i\fR, \fB\-\-in\fR=\fIIF\fR where \fIIF\fR is the name of a file from which \fINDO\fR bytes will be read and placed in the data\-out buffer. This is only done when the \fI\-\-ndo=NDO\fR option is given. If this option is not given then stdin is read. If \fIIF\fR is "\-" then stdin is also used. .TP \fB\-l\fR, \fB\-\-lba\fR=\fILBA\fR where \fILBA\fR specifies the logical block address of the first block to start the verify operation. \fILBA\fR is assumed to be decimal unless prefixed by '0x' or a trailing 'h' (see below). The default value is 0 (i.e. the start of the device). .TP \fB\-n\fR, \fB\-\-ndo\fR=\fINDO\fR \fINDO\fR is the number of bytes to obtain from the \fIFN\fR file (if \fI\-\-in=FN\fR is given) or from stdin. Those bytes are placed in the data\-out buffer associated with the SCSI VERIFY command and \fINDO\fR is placed in the verification length field in the cdb. The default value for \fINDO\fR is 0 and the maximum value is dependant on the OS. If the \fI\-\-ebytchk=BCH\fR option is not given then the BYTCHK field in the cdb is set to 1. .TP \fB\-q\fR, \fB\-\-quiet\fR suppress the sense buffer messages associated with a MISCOMPARE sense key that would otherwise be sent to stderr. Still set the exit status to 14 which is the sense key value indicating a MISCOMPARE . .TP \fB\-r\fR, \fB\-\-readonly\fR opens the DEVICE read\-only rather than read\-write which is the default. The Linux sg driver needs read\-write access for the SCSI VERIFY command but other access methods may require read\-only access. .TP \fB\-v\fR, \fB\-\-verbose\fR increase the level of verbosity, (i.e. debug output). .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .TP \fB\-P\fR, \fB\-\-vrprotect\fR=\fIVRP\fR where \fIVRP\fR is the value in the vrprotect field in the VERIFY command cdb. It must be a value between 0 and 7 inclusive. The default value is zero. .SH BYTCHK BYTCHK is the name of a field (two bits wide) in the VERIFY(10) and VERIFY(16) commands. When set to 1 or 3 (sbc3r34 reserves the value 2) it indicates that associated with the SCSI VERIFY command, a data\-out buffer will be sent for the device (disk) to check. Using the \fI\-\-ndo=NDO\fR option sets the BYTCHK field to 1 and \fINDO\fR is the number of bytes placed in the data\-out buffer. Those bytes are obtained from stdin or \fIIF\fR (from the \fI\-\-in=FN\fR option). The \fI\-\-ebytchk=BCH\fR option may be used to override the BYTCHK field value of 1 with \fIBCH\fR. .PP The calculation of \fINDO\fR is left up to the user. Its value depends on the logical block size (which can be found with the sg_readcap utility), the \fICOUNT\fR and the \fIVRP\fR values. If the \fIVRP\fR is greater than 0 then each logical block will contain an extra 8 bytes (at least) of protection information. .PP When the BYTCHK field is 0 then the verification process done by the device (disk) is vendor specific. It typically involves checking each block on the disk against its error correction codes (ECC) which is additional data also held on the disk. .PP Many Operating Systems put limits on the maximum size of the data\-out (and data\-in) buffer. For Linux at one time the limit was less than 1 MB but has been increased somewhat. .SH OPTION CHANGES Earlier versions of this utility had a \fI\-\-bytchk=NDO\fR option which set the BYTCHK bit and set the cdb verification length field to \fINDO\fR. The shorter form of that option was \fI\-B NDO\fR. For backward compatibility that option is still present but not documented. In its place is the \fI\-\-ndo=NDO\fR whose shorter form of \fI\-n NDO\fR. \fI\-\-ndo=NDO\fR sets the BYTCHK field to 1 unless that is overridden by the \fI\-\-ebytchk=BCH\fR. .SH NOTES Various numeric arguments (e.g. \fILBA\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The amount of error correction and the number of retries attempted before a block is considered defective are controlled in part by the Verify Error Recovery mode page. A note in the SBC\-3 draft (rev 29 section 6.4.9 on the Verify Error Recovery mode page) advises that to minimize the number of checks (and hence have the most "sensitive" verify check) do the following in that mode page: set the EER bit to 0, the PER bit to 1, the DTE bit to 1, the DCR bit to 1, the verify retry count to 0 and the verify recovery time limit to 0. Mode pages can be modified with the .B sdparm utility. .PP The SCSI VERIFY(6) command defined in the SSC\-2 standard and later (i.e. for tape drive systems) is not supported by this utility. .SH EXIT STATUS The exit status of sg_verify is 0 when it is successful. When \fIBCH\fR is other than 0 then a comparison takes place and if it fails then the exit status is 14 which happens to be the sense key value of MISCOMPARE. Otherwise see the EXIT STATUS section in the sg3_utils(8) man page. .PP Earlier versions of this utility set an exit status of 98 when there was a MISCOMPARE. .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2013 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B sdparm(sdparm), sg_modes(sg3_utils), sg_readcap(sg3_utils), .B sg_inq(sg3_utils) sg3_utils-1.40/doc/sg_xcopy.80000664000175000017500000003541412406465611015055 0ustar douggdougg.TH SG_XCOPY "8" "September 2014" "sg3_utils\-1.40" SG3_UTILS .SH NAME sg_xcopy \- copy data to and from files and devices using SCSI EXTENDED COPY (XCOPY) .SH SYNOPSIS .B sg_xcopy [\fIbs=BS\fR] [\fIconv=CONV\fR] [\fIcount=COUNT\fR] [\fIibs=BS\fR] [\fIif=IFILE\fR] [\fIiflag=FLAGS\fR] [\fIobs=BS\fR] [\fIof=OFILE\fR] [\fIoflag=FLAGS\fR] [\fIseek=SEEK\fR] [\fIskip=SKIP\fR] [\fI\-\-help\fR] [\fI\-\-version\fR] .PP [\fIbpt=BPT\fR] [\fIcat=\fR0|1] [\fIdc=\fR0|1] [\fIid_usage=\fR{hold|discard|disable}] [\fIlist_id=ID\fR] [\fIprio=PRIO\fR] [\fItime=\fR0|1] [\fIverbose=VERB\fR] [\fI\-\-on_dst|\-\-on_src\fR] [\fI\-\-verbose\fR] .SH DESCRIPTION .\" Add any additional description here .PP Copy data to and from any files. Specialized for "files" that are Linux SCSI devices that support the SCSI EXTENDED COPY (XCOPY) command. .PP During the draft stages of SPC\-4 the T10 committee has expanded the XCOPY command so that it now has two variants: "LID1" (for a List Identifier length of 1 byte) and "LID4" (for a List Identifier length of 4 bytes). This utility supports the older, LID1 variant which is also found in SPC\-3 and earlier. While the LID1 variant in SPC\-4 is command level (binary) compatible with XCOPY as defined in SPC\-3, some of the command naming has changed. This utility uses the older, SPC\-3 XCOPY names. .PP This utility has similar syntax and semantics to .B dd(1) but with no "conversions" is supported. .PP The first group in the synopsis above are "standard" Unix .B dd(1) operands. The second group are extra options added by this utility. Both groups are defined below in combined, alphabetical order. .PP By default the XCOPY command is sent to \fIOFILE\fR. This can be changed with the \fI\-\-on_src\fR or \fIiflag=xflag\R options which cause the XCOPY command to be sent to \fIIFILE\fR instead. Also see the section on ENVIRONMENT VARIABLES. .PP The ddpt utility supports the same xcopy(LID1) functionality as this utility with the same options and flags. Additionally ddpt supports a subset of xcopy(LID4) functionality variously called "xcopy version 2, lite" or ODX. ODX is a market name and stands for Offloaded Data Xfer (i.e. transfer). .SH OPTIONS .TP \fBbpt\fR=\fIBPT\fR each IO transaction will be made using \fIBPT\fR blocks (or less if near the end of the copy). Default is 128 for block sizes less that 2048 bytes, otherwise the default is 32. So for bs=512 the reads and writes will each convey 64 KiB of data by default (less if near the end of the transfer or memory restrictions). When cd/dvd drives are accessed, the block size is typically 2048 bytes and bpt defaults to 32 which again implies 64 KiB transfers. .TP \fBbs\fR=\fIBS\fR where \fIBS\fR .B must be the block size of the physical device (if either the input or output files are accessed via SCSI commands). Note that this differs from .B dd(1) which permits \fIBS\fR to be an integral multiple. Defaults to the device block size. .TP \fBcat\fR={0|1} sets the SCSI EXTENDED COPY command segment descriptor CAT bit to 0 or 1 (default: 0). The CAT bit (in conjunction with the PAD bit) controls the handling of residual data. See section .B HANDLING OF RESIDUAL DATA for details. .TP \fBdc\fR={0|1} sets the SCSI EXTENDED COPY command segment descriptor DC bit to 0 or 1 (default: 0). The DC bit controls whether \fICOUNT\fR refers to the source (\fIdc=0\fR) or the target (\fIdc=1\fR) descriptor. .TP \fBconv\fR=\fBCONV\fR all \fBCONV\fR arguments are ignored. .TP \fBcount\fR=\fICOUNT\fR copy \fICOUNT\fR blocks from \fIIFILE\fR to \fIOFILE\fR. Default is the minimum (\fIIFILE\fR if \fIdc=0\fR or \fIOFILE\fR if \fIdc=1\fR) number of blocks that SCSI devices report from SCSI READ CAPACITY commands or that block devices (or their partitions) report. Normal files are not probed for their size. If \fIskip=SKIP\fR or \fIskip=SEEK\fR are given and the count is derived (i.e. not explicitly given) then the derived count is scaled back so that the copy will not overrun the device. If the file name is a block device partition and \fICOUNT\fR is not given then the size of the partition rather than the size of the whole device is used. If \fICOUNT\fR is not given (or \fIcount=\-1\fR) and cannot be derived then an error message is issued and no copy takes place. .TP \fBibs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBid_usage\fR={hold|discard|disable} sets the SCSI EXTENDED COPY command parameter list field called LIST ID USAGE to 0 if the argument is 'hold', to 2 if the argument is 'discard', or to '3' if the argument is 'disable'. .TP \fBif\fR=\fIIFILE\fR read from \fIIFILE\fR instead of stdin. If \fIIFILE\fR is '\-' then stdin is read. Starts reading at the beginning of \fIIFILE\fR unless \fISKIP\fR is given. .TP \fBiflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIIFILE\fR and are ignored when \fIIFILE\fR is stdin. .TP \fBobs\fR=\fIBS\fR if given must be the same as \fIBS\fR given to 'bs=' option. .TP \fBof\fR=\fIOFILE\fR write to \fIOFILE\fR instead of stdout. If \fIOFILE\fR is '\-' then writes to stdout. If \fIOFILE\fR is /dev/null then no actual writes are performed. If \fIOFILE\fR is '.' (period) then it is treated the same way as /dev/null (this is a shorthand notation). If \fIOFILE\fR exists then it is _not_ truncated; it is overwritten from the start of \fIOFILE\fR unless 'oflag=append' or \fISEEK\fR is given. .TP \fBoflag\fR=\fIFLAGS\fR where \fIFLAGS\fR is a comma separated list of one or more flags outlined below. These flags are associated with \fIOFILE\fR and are ignored when \fIOFILE\fR is /dev/null, '.' (period), or stdout. .TP \fBlist_id\fR=\fIID\fR sets the SCSI EXTENDED COPY command parameter list field called LIST IDENTIFIER to \fIID\fR. \fIID\fR should be a value between 0 and 255 (inclusive) and the default value is 1. .TP \fBprio\fR=\fIPRIO\fR sets the SCSI EXTENDED COPY command parameter list field called PRIORITY to \fIPRIO\fR. The default value is 1. .TP \fBseek\fR=\fISEEK\fR start writing \fISEEK\fR bs\-sized blocks from the start of \fIOFILE\fR. Default is block 0 (i.e. start of file). .TP \fBskip\fR=\fISKIP\fR start reading \fISKIP\fR bs\-sized blocks from the start of \fIIFILE\fR. Default is block 0 (i.e. start of file). .TP \fBtime\fR={0|1} when 1, times transfer and does throughput calculation, outputting the results (to stderr) at completion. When 0 (default) doesn't perform timing. .TP \fBverbose\fR=\fIVERB\fR as \fIVERB\fR increases so does the amount of debug output sent to stderr. Default value is zero which yields the minimum amount of debug output. A value of 1 reports extra information that is not repetitive. A value 2 reports cdbs and responses for SCSI commands that are not repetitive (i.e. other that READ and WRITE). Error processing is not considered repetitive. Values of 3 and 4 yield output for all SCSI commands (and Unix read() and write() calls) so there can be a lot of output. .TP \fB\-h\fR, \fB\-\-help\fR outputs usage message and exits. .TP \fB\-\-on_dst\fR send the XCOPY command to the output file/device (i.e. \fIOFILE\fR). This is the default unless overridden by the \fI\-\-on_src\fR or \fIiflag=xflag\fR options. Also see the section below on ENVIRONMENT VARIABLES. .TP \fB\-\-on_src\fR send the XCOPY command to the input file/device (i.e. \fIIFILE\fR). .TP \fB\-v\fR, \fB\-\-verbose\fR equivalent to \fIverbose=1\fR. When used twice, equivalent to \fIverbose=2\fR, etc. .TP \fB\-V\fR, \fB\-\-version\fR outputs version number information and exits. .SH FLAGS Here is a list of flags and their meanings: .TP append causes the O_APPEND flag to be added to the open of \fIOFILE\fR. For regular files this will lead to data appended to the end of any existing data. Cannot be used together with the \fIseek=SEEK\fR option as they conflict. The default action of this utility is to overwrite any existing data from the beginning of the file or, if \fISEEK\fR is given, starting at block \fISEEK\fR. Note that attempting to 'append' to a device file (e.g. a disk) will usually be ignored or may cause an error to be reported. .TP excl causes the O_EXCL flag to be added to the open of \fIIFILE\fR and/or \fIOFILE\fR. .TP flock after opening the associated file (i.e. \fIIFILE\fR and/or \fIOFILE\fR) an attempt is made to get an advisory exclusive lock with the flock() system call. The flock arguments are "FLOCK_EX | FLOCK_NB" which will cause the lock to be taken if available else a "temporarily unavailable" error is generated. An exit status of 90 is produced in the latter case and no copy is done. .TP null has no affect, just a placeholder. .TP pad sets the SCSI EXTENDED COPY command segment descriptor PAD bit. The PAD bit (in conjunction with the CAT bit) controls the handling of residual data.(See section .B HANDLING OF RESIDUAL DATA for details. .TP xcopy has no affect; for compatibility with ddpt. .SH HANDLING OF RESIDUAL DATA The \fIpad\fR and \fIcat\fR bits control the handling of residual data. As the data can be specified either in terms of source or target block size and both might have different block sizes residual data is likely to happen in these cases. If both block sizes are identical these bits have no effect as residual data will not occur. .PP If none of these bits are set, the EXTENDED COPY command will be aborted with additional sense 'UNEXPECTED INEXACT SEGMENT'. .PP If only the \fIcat\fR bit is set the residual data will be retained and made available for subsequent segment descriptors. Residual data will be discarded for the last segment descriptor. .PP If the \fIpad\fR bit is set for the source descriptor only, any residual data for both source or destination will be discarded. .PP If the \fIpad\fR bit is set for the target descriptor only any residual source data will be handled as if the \fIcat\fR bit is set, but any residual destination data will be padded to make a whole block transfer. .PP If the \fIpad\fR bit is set for both source and target any residual source data will be discarded, and any residual destination data will be padded. .SH ENVIRONMENT VARIABLES If the command line invocation does not explicitly (and unambiguously) indicate whether the XCOPY SCSI command should be sent to \fIIFILE\fR (i.e. the source) or \fIOFILE\fR (i.e. the destination) then a check is made for the presence of the XCOPY_TO_SRC and XCOPY_TO_DST environment variables. If either one exists (but not both) then it indicates where the SCSI XCOPY command will be sent. By default the XCOPY command is sent to \fIOFILE\fR. .SH RETIRED OPTIONS Here are some retired options that are still present: .TP append=0 | 1 when set, equivalent to 'oflag=append'. When clear the action is to overwrite the existing file (if it exists); this is the default. See the 'append' flag. .SH NOTES Copying data behind an Operating System's back can cause problems. In the case of Linux, users should look at this link: http://linux\-mm.org/Drop_Caches .br This command sequence may be useful: .br sync; echo 3 > /proc/sys/vm/drop_caches .PP Various numeric arguments (e.g. \fISKIP\fR) may include multiplicative suffixes or be given in hexadecimal. See the "NUMERIC ARGUMENTS" section in the sg3_utils(8) man page. .PP The \fICOUNT\fR, \fISKIP\fR and \fISEEK\fR arguments can take 64 bit values (i.e. very big numbers). Other values are limited to what can fit in a signed 32 bit number. .PP All informative, warning and error output is sent to stderr so that dd's output file can be stdout and remain unpolluted. If no options are given, then the usage message is output and nothing else happens. .PP If a device supports xcopy operations then it should set the 3PC field (3PC stands for Third Party Copy) in its standard INQUIRY response. This utility will attempt a xcopy operation irrespective of the value in the 3PC field but if it is zero (cleared) one would expect the xcopy operation to fail. .PP The status of the SCSI EXTENDED COPY command can be queried with .B sg_copy_results(sg3_utils) .PP Currently only block\-to\-block transfers are implemented; \fIIFILE\fR and \fIOFILE\fR must refer to a SCSI block device. .PP No account is taken of partitions so, for example, /dev/sbc2, /dev/sdc, /dev/sg2, and /dev/bsg/3:0:0:1 would all refer to the same thing: the whole logical unit (i.e. the whole disk) starting at LBA 0. So any partition indication (e.g. /dev/sdc2) is ignored. The user should set \fISKIP\fR, \fISEEK\fR and \fICOUNT\fR with information obtained from a command like 'fdisk \-l \-u /dev/sdc' to account for partitions. .PP XCOPY (LID1) capability has been added to the ddpt utility which is in a package of the same name. The ddpt utility will run on other OSes (e.g. FreeBSD and Windows) while sg_xcopy only runs on Linux. Also ddpt permits the arguments to \fIibs=\fR and \fIibs=\fR to be different. .SH EXAMPLES Copy 2M of data from the start of one device to another: .PP # sg_xcopy if=/dev/sdo of=/dev/sdp count=2048 list_id=2 dc=1 .br sg_xcopy: if=/dev/sdo skip=0 of=/dev/sdp seek=0 count=1024 .br Start of loop, count=1024, bpt=65535, lba_in=0, lba_out=0 .br sg_xcopy: 1024 blocks, 1 command .PP Check the status of the EXTENDED COPY command: .PP # sg_copy_results \-\-status \-\-list_id=2 /dev/sdp .br Receive copy results (copy status): Held data discarded: Yes Copy manager status: Operation completed without errors Segments processed: 1 Transfer count units: 0 Transfer count: 0 .SH SIGNALS The signal handling has been borrowed from dd: SIGINT, SIGQUIT and SIGPIPE output the number of remaining blocks to be transferred and the records in + out counts; then they have their default action. SIGUSR1 causes the same information to be output yet the copy continues. All output caused by signals is sent to stderr. .SH EXIT STATUS The exit status of sg_xcopy is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .PP An additional exit status of 90 is generated if the flock flag is given and some other process holds the advisory exclusive lock. .SH AUTHORS Written by Hannes Reinecke and Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2000\-2014 Hannes Reinecke and Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" There is a web page discussing sg_dd at http://sg.danny.cz/sg/sg_dd.html .PP A POSIX threads version of this utility called .B sgp_dd is in the sg3_utils package. Another version from that package is called .B sgm_dd and it uses memory mapped IO to speed transfers from sg devices. .PP The lmbench package contains .B lmdd which is also interesting. For moving data to and from tapes see .B dt which is found at http://www.scsifaq.org/RMiller_Tools/index.html .PP To change mode parameters that effect a SCSI device's caching and error recovery see .B sdparm(sdparm) .PP See also .B dd(1), sg_copy_results(sg3_utils), ddrescue(GNU), ddpt,ddptctl(ddpt) sg3_utils-1.40/doc/sg_scan.8.linux0000664000175000017500000000561312326640175015774 0ustar douggdougg.TH SG_SCAN "8" "May 2013" "sg3_utils\-1.36" SG3_UTILS .SH NAME sg_scan \- scans sg devices (or SCSI/ATAPI/ATA devices) and prints results .SH SYNOPSIS .B sg_scan [\fI\-a\fR] [\fI\-i\fR] [\fI\-n\fR] [\fI\-w\fR] [\fI\-x\fR] [\fIDEVICE\fR]* .SH DESCRIPTION .\" Add any additional description here .PP If no \fIDEVICE\fR names are given, sg_scan does a scan of the sg devices and outputs a line of information for each sg device that is currently bound to a SCSI device. If one or more \fIDEVICE\fRs are given only those devices are scanned. Each device is opened with the O_NONBLOCK flag so that the scan will not "hang" on any device that another process holds an O_EXCL lock on. .PP Any given \fIDEVICE\fR name is expected to comply with (to some extent) the Storage Architecture Model (SAM see www.t10.org). Any device names associated with the Linux SCSI subsystem (e.g. /dev/sda and /dev/st0m) are suitable. Devices names associated with ATAPI devices (e.g. most CD/DVD drives and ATAPI tape drives) are also suitable. If the device does not fall into the above categories then an ATA IDENTIFY command is tried. .PP In Linux 2.6 and 3 series kernels, the lsscsi utility may be helpful. Apart from providing more information (by data\-mining in the sysfs pseudo file system), it does not need root permissions to execute, as this utility would typically need. .SH OPTIONS .TP \fB\-a\fR do alphabetical scan (i.e. sga, sgb, sgc). Note that sg device nodes with an alphabetical index have been deprecated since the Linux kernel 2.2 series. .TP \fB\-i\fR do a SCSI INQUIRY, output results in a second (indented) line. If the device is an ATA disk then output information from an ATA IDENTIFY command .TP \fB\-n\fR do numeric scan (i.e. sg0, sg1...) [default] .TP \fB\-w\fR use a read/write flag when opening sg device (default is read\-only) .TP \fB\-x\fR extra information output about queueing .SH NOTES This utility was written at a time when hotplugging of SCSI devices was not supported in Linux. It used a simple algorithm to scan sg device nodes in ascending numeric or alphabetical order, stopping after there were 4 consecutive errors. .PP In the Linux kernel 2.6 series, this utility uses sysfs to find which sg device nodes are active and only checks those. Hence there can be large "holes" in the numbering of sg device nodes (e.g. after an adapter has been removed) and still all active sg device nodes will be listed. This utility assumes that sg device nodes are named using the normal conventions and searches from /dev/sg0 to /dev/sg4095 inclusive. .SH EXIT STATUS The exit status of sg_scan is 0 when it is successful. Otherwise see the sg3_utils(8) man page. .SH AUTHORS Written by D. Gilbert and F. Jansen .SH COPYRIGHT Copyright \(co 1999\-2013 Douglas Gilbert .br This software is distributed under the GPL version 2. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B lsscsi(8) sg3_utils-1.40/README0000664000175000017500000005277312430315266013250 0ustar douggdougg README for sg3_utils ==================== Introduction ============ This package contains low level utilities for devices that use the SCSI command set. Originally the SCSI command set was associated exclusively with the SCSI Parallel Interface (SPI) transport. SPI has now almost been completely replaced by the Serial Attached SCSI (SAS) transport which also accepts the SCSI command set. Additionally many other storage related transports use the SCSI command set (amongst others); examples are ATAPI devices (CD/DVDs and tapes), USB mass storage devices (including those using the newer UAS[P]), Fibre Channel disks, IEEE 1394 storage devices (SBP protocol), iSCSI, FCoE and SOP devices. This package originally targeted the Linux SCSI subsystem. Since most operating systems contain a SCSI command pass-through mechanism, many utilities within this package have been ported. This README mainly concentrates on Linux: see the README.freebsd file for the FreeBSD port, README.solaris for the Solaris port, the README.tru64 file for the Tru64 (OSF) port and README.win32 for the Windows ports (of which there are two variants). Most utilities within the sg3_utils package work at the SCSI command level. For example the sg_inq utility issues a SCSI INQUIRY command and decodes the response. The COVERAGE file has a table containing a row for each SCSI command issued by this package; to the right of each row is the utility (sometimes more than one) that issue that SCSI command. The COVERAGE file has a second table for ATA commands usage. Some utilities interface at a slightly higher level, for example: sg_dd, sgm_dd and sgp_dd. These are closely related to the Unix dd command and typically issue a sequence of SCSI READ and WRITE commands to copy data. These utilities are relatively tightly bound to Linux and are not ported to other Operating Systems. A new utility called ddpt (in a package of the same name) is more generic while still allowing a copy to be done in terms of SCSI READ and WRITE commands. ddpt has been ported to other OSes. Description =========== A web site supporting the sg3_utils package can be found at http://sg.danny.cz/sg/sg3_utils.html . That page has a table of released versions for download. The most recent release or beta of sg3_utils may be found on this page: http://sg.danny.cz/sg in the News section. The predecessor to this package was called sg_utils. It is described in http://sg.danny.cz/sg/uu_index.html and old versions can be downloaded from the Downloads section of http://sg.danny.cz/sg . In the Linux 2.4 kernel series these utilities need to use the SCSI generic (sg) driver to access SCSI devices. The name of this package (i.e. sg3_utils) refers to version 3 of the SCSI generic (sg) driver which was introduced at the beginning of the 2.4 Linux kernel series. Significantly this added a new SCSI command interface structure (i.e. struct sg_io_hdr) that is more flexible than the older "sg_header" structure found in the sg driver in the 2.2 and earlier Linux kernel series. The sg_io_hdr structure is also more flexible than the awkward (and limiting) interface to the SCSI_IOCTL_SEND_COMMAND ioctl supported by the Linux SCSI mid level. The version 3 sg driver also added the SG_IO ioctl that is synchronous (i.e. it issues the requested SCSI command and waits for the response (or a timeout) before the ioctl returns to the user space program that invoked it). The SG_IO ioctl is now supported in other parts of the Linux kernel in the 2.6 series. In sg3_utils version 1.27 support has been added for the Linux bsg driver which use the sg version 4 interface. There seems no point in renaming this package sg4_utils. The existing utilities just silently support either. Currently the source build must be able to see the /usr/include/linux/bsg.h file. Then at run time the /proc/devices pseudo file needs to have an entry for the bsg driver (appeared around lk 2.6.28). With this in place each utility at run time checks the device it has been given and if it is a char device whose major number matches the bsg entry in /proc/devices then the sg v4 interface is used. Otherwise the sg v3 interface is used. Utilities that wish to use the asynchronous SCSI command interface (i.e. via a write() read() sequence) or issue special "commands" (e.g. bus and device resets) still need to use the Linux sg driver. Note that various drivers (e.g. cdrom/sr) have different open() flag and permissions policies that the user may need to take into account. If users have problems or questions about them please contact the author. Documentation for the Linux sg device driver can be found at: http://sg.danny.cz/sg/p/sg_v3_ho.html . This is written in DocBook and the original xml can be found in the same directory with the ".xml" extension. Postscript and pdf renderings are also in that directory. Older documentation for the sg version 3 driver can be found at: http://sg.danny.cz/sg/p/scsi_generic_v3.txt . All utilities are either "GPL"-ed or have a FreeBSD license. The author's intention is that users may incorporate all or part of the code in their work as they please. Attribution is encouraged. Please check the code as other contributors (apart from the author) may also have copyright notices. For a list of contributors see the CREDITS file. To save the repetition of common code (e.g. SCSI error processing) and reduce the size of the executable files, a shared library called libsgutils.so (its Linux name) is created during the build process. That library is built from the contents of the include and lib subdirectories. The header files in the include subdirectory can be seen as the API of libsgutils and are commented with that in mind. The SCSI pass-through code for the supported operating systems is found in the lib subdirectory with names like sg_pt_linux.c and sg_pt_win32.c . Various distributions (of Linux mainly) distribute sg3_utils as 3 installable packages. One is a package containing the shared library discussed above (e.g. libsgutils2-2_1.33-0.1_i386.deb). A second package contains the utilities (e.g. sg3-utils_1.33-0.1_i386.deb) and depends on the first package). Finally there is an optional package that contains header files and a static library (e.g. libsgutils2-dev_1.33-0.1_i386.deb). This final package is only needed to build other packages (e.g. sdparm) that wish to use the sg3_utils shared library. All the utilities in the src subdirectory have "man" pages that are placed in the doc subdirectory. There is also a sg3_utils (8) man page that summarizes common facilities including exit statuses. Additional information (including each utility's version number) can be found towards the top of each ".c" file corresponding to the utility name. The sg driver in Linux can be seen as having 3 distinct versions: v1 lk < 2.2.6 sg_header based relatively unchanged since 1992 v2 lk >= 2.2.6 enhanced sg_header interface structure [1999/4/16] v3 lk >= 2.4 additional sg_io_hdr interface structure [2001/1/4] v3 lk >= 2.6 same interface as found in lk 2.4 [2.6.0: 2003/12/18] and the bsg driver supports the sg v4 interface and was added around lk 2.6.28 . This package is targeted at "v3" and "v4". Another package called "sg_utils" is targeted at "v2" and to a lesser extent "v1". The "sg_utils" package has a subset of the utilities found in this package. In Linux some sg driver ioctls (notably SG_IO) are defined for many block devices in lk 2.6 series. In practice this means all SCSI block devices, ATAPI block devices (mainly CD, DVD and BD optical devices) but _not_ ATA disks, depending on which kernel configuration options, can be accessed by the utilities in this package. SATA disks that use the libata kernel library (or some other SCSI to ATA Translation (SAT) Layer (SATL)) accept SCSI commands and thus are supported. Support for the SG_IO as been added to the scsi tape driver (st) in lk 2.6.6 . In the src directory the bulk of the utilities are written in relatively clean POSIX compliant C code with Linux specific system calls and structures removed and placed in Linux specific files in the lib directory. A small number of utilities in the src directory do contain Linux specific logic and are not ported to other OSes (e.g. sg_dd). One utility, sg_scan, has two separate implementations, one for Linux (sg_scan.c.linux) and one for Windows (sg_scan.c.win32). The src-lib directory split approach allows FreeBSD, Solaris, Tru64 and Windows specific code to be isolated to a few files in the lib directory whose interfaces match those of the Linux specific code. Darwin is not supported because the Apple folks do not want to give their users a pass-through SCSI interface. The author has read about creative hackers using a VM containing a real OS to circumvent the Apple restriction. C standard is C99 ================== The C code in this package is written for portability rather than speed. It assumes a level of C99 compliance and favours POSIX system and library calls over OS specific calls. The C code is written in a C++ friendly way and is checked from time to time that it compiles clean with C++. To accommodate C++ certain C99 constructs such as designated initializers cannot be used. Building ======== This package is designed to be built with the usual: "./configure ; make ; make install" sequence. In some situations that may need to be prefixed by a call to the "./autogen.sh" script which invokes autoconf and automake. That in turn may require packages containing those utilities to be installed. The libtool utility is also required. Naturally a C compiler is required and due to the vagaries of libtool a C++ compiler also. The "./configure" takes many command line options with the defaults being usually sufficient to start with. One quirk is that the location of the installation is under the /usr/local directory. So the sg_inq utility will be installed at /usr/local/bin/sg_inq . This is controlled by the "--prefix=" option which defaults to "--prefix=/usr/local". As an example to install the executables in /usr/bin and disable the creation of the shared library (libsgutils.so) this invocation could be used: "./configure --prefix=/usr --disable-shared". To reduce the size of an executable as well try this: "./configure --prefix=/usr --disable-shared --disable-scsistrings". In Linux there are package build files for "rpm" based and for "deb" based systems. The 'sg3_utils.spec' file in the main directory can be used like this: 'rpmbuild -ba sg3_utils.spec' in a rpmbuild tree SPECS directory. To cross build or make a more widely distributable package then the --target option may be useful: 'rpmbuild --target=i386 -ba sg3_utils.spec' or 'rpmbuild --target=x86_64 -ba sg3_utils.spec' . The sg3_utils.spec file in the main directory targets Red Hat systems, an alternative "spec" file for Suse systems has been placed under the 'suse' directory. The 'build_debian.sh' script should build several "deb" packages and place them in the parent directory. In debian based systems doing a 'apt-get install build-essential' is one way to get most of build environment needed if it has not already been loaded. There are now some problems with this script and the superseded Debian 4.0 ("etch"). See debian/README.debian4 for a workaround. Amongst other things debian builds are sensitive to the value in the debian/compat file. If it contains "7" then it works on lenny and gives warning on squeeze (but fails on the earlier etch). Warning ======= Many devices use SCSI command sets over transport protocols not normally associated with SCSI (as defined at http://www.t10.org ). Some of these devices react poorly (e.g. lock up) when sent SCSI commands that they don't support. Even sending a supported SCSI command with a field set to an unexpected value can cause problems. [The author is talking about billions of USB devices with horrible SCSI implementations.] For example, all "SCSI" devices must support the INQUIRY command which the SCSI-2 standard says should request a 36 byte response. However later SCSI standards (e.g. SPC-2) have increased that length but some SCSI devices lock up when they receive a request for anything other than a 36 byte response. Any well implemented "SCSI" device should react sensibly when a utility in sg3_utils sends a SCSI command that it doesn't support. Unfortunately this cannot be guaranteed. Prior to lk 2.6.29 USB mass storage limited sense data to 18 bytes which caused problems for certain types of descriptor based sense data. An example of this is the SCSI ATA PASS-THROUGH command with the CK_COND bit set. Utilities ========= Here is list in alphabetical order of utilities found in the 'src' subdirectory of the sg3_utils package: sginfo, sg_compare_and_write, sg_copy_results, sgm_dd, sgp_dd, sg_dd, sg_decode_sense, sg_emc_trespass, sg_format, sg_get_config, sg_get_lba_status, sg_ident, sg_inq, sg_logs, sg_luns, sg_map, sg_map26, sg_modes, sg_opcodes, sg_persist, sg_prevent, sg_raw, sg_rbuf, sg_rdac, sg_read, sg_readcap, sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign, sg_referrals, sg_request, sg_reset, sg_rmsn, sg_rtpg, sg_safte, sg_sanitize, sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog, sg_sat_set_features, sg_scan, sg_senddiag, sg_ses, sg_ses_microcode, sg_start, sg_stpg, sg_sync, sg_test_rwbuff, sg_turs, sg_unmap, sg_verify, sg_vpd, sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify sg_wr_mode, sg_xcopy Each of the above utilities depends on header files found in the 'include' subdirectory and library code found in the 'lib' subdirectory. Associated man pages are found in the 'doc' subdirectory. Additional programs found in the 'archive', 'examples' and 'utils' subdirectories in not build by the top level build infrastructure. Linux binary distributions of the sg3_utils package (e.g. "rpm" and debian packages) typically contain the shared library, the utilities found in the 'src' subdirectory, their associated man pages and some documentation files (e.g. README, INSTALL, CREDITS, COPYING and COVERAGE). See the INSTALL file for generic instructions about building with autotools (e.g. ./configure ). Man pages can be read (without building and installing the package) by going to the 'doc' subdirectory and executing something like this: $ man ./sg_dd.8 To see which SCSI commands (and ATA commands) are used by these utilities refer to the COVERAGE file. Here is a list in alphabetical order of utilities found in the 'examples' subdirectory: - bsg_queue_tst, sg_excl, scsi_inquiry, sg_iovec_tst, sg_queue_tst, sg_sat_chk_power, sg__sat_identify, sg__sat_phy_event, sg__sat_set_features, sg_sat_smart_rd_data, sg_simple1, sg_simple2, sg_simple3, sg_simple4, sg_simple5, sg_simple16, sg_tst_excl, sg_tst_excl2, sg_tst_excl3, sg_tst_context and sg_tst_async Also in that subdirectory is a script to test sg_persist, an example data file for sg_persist (called "transport_ids.txt") and an example data file for sg_reassign (called "reassign_addr.txt"). There are several scripts for 'sg_senddiag -pf -raw=-' that will put some SAS disk phys into a "compliant jitter tolerance pattern" (CJTPAT). The 'utils' subdirectory contains source and a Makefile to build "hxascdmp" which accepts binary data from stdin (or a file on the command line) and outputs an ASCII-HEX and ASCII representation of it. It is similar to the Unix od command. There is also code to sg_chk_asc.c which checks a given text file (typically a copy of http://www.t10.org/lists/asc-num.txt ) and checks it against the asc/ascq text strings held in sg_lib_data.c . The 'doc' subdirectory contains a README file containing the urls of various related documents. The 'scripts' subdirectory contains some Bourne (bash) shell scripts that rely on utilities in the main directory. One script uses the sdparm utility. These scripts are described in the scripts/README file and have usage messages. Notes for utilities without man pages ===================================== These utils are found in the 'examples' subdirectory. The "scsi_inquiry" program shows the use of the SCSI_IOCTL_SEND_COMMAND ioctl to send a SCSI INQUIRY command. That ioctl() is supported by the SCSI sub system mid level and so is common to all sd, sr, st and sg devices. That ioctl is deprecated in the lk 2.6 series. This program has been placed in the "examples" subdirectory. "sg_simple1" and "sg_simple2" are example programs demonstrating calls to the SCSI INQUIRY and TEST UNIT READY commands. They only differ in their error processing: sg_simple1 uses sg_lib.[hc] for error processing while sg_simple2 does its own more primitive checks. "sg_simple3" tests out user space scatter gather added to the version 3 sg driver. "sg_simple4" shows the INQUIRY command using mmap-ed IO to obtain its response buffer. "sg_simple5" also sends and INQUIRY and TEST UNIT READY commands. It uses the generic pass through mechanism based on sg_pt.h . It will currently build in Linux and FreeBSD (with "make -f Makefile.freebsd"). It has extensive error checking code. "sg_simple16" attempts to send a 16 byte SCSI command, READ_16, to the scsi device. This is only supported for lk >= 2.4.15 and for adapter drivers that indicate that they have 16 byte CDB capability (otherwise DID_ABORT will appear in the host_status). "sg_sat_chk_power" attempts to push an ATA CHECK POWER MODE command through the SAT-defined ATA PASS_THROUGH (16) SCSI command. That ATA command needs to read the "FIS" registers after the command is completed which involves using the ATA Status Return (sense data) descriptor (as defined in SAT). "sg_sat_smart_rd_data" attempts to push an ATA SMART/READ DATA command through the SAT-defined ATA PASS_THROUGH (16) SCSI command. If successful, the 256 word (512 byte) response is output. "sg_tst_excl" and "sg_tst_excl2" use multiple threads to bombard the given device with O_EXCL open flags, so only one should succeed at a time. While holding O_EXCL control a thread attempts a double increment on an integer in the given LBA. If the integer starts even (after the first read) then it should remain even if the O_EXCL flag is doing its job. The "sg_tst_excl" variant uses the Linux SG_IO v3 interface while the "sg_tst_excl2" uses the more generic sg_pt infrastructure. "sg_tst_excl3" is a variant of "sg_tst_excl2". "sg_tst_excl3" only does the double increment from the first thread, each time using O_EXCL on open. The remaining threads check the value is even, each time doing an open without the O_EXCL flag. "bsg_queue_tst" sends an INQUIRY command via the Linux SG_IO v4 interface which is used by the bsg driver. So it will take device names like "/dev/bsg/6:0:0:0". It tests if sending repeated INQUIRYs with the BSG_FLAG_Q_AT_HEAD or BSG_FLAG_Q_AT_TAIL flag makes any difference. "sg_tst_async" is a test harness for the Linux sg driver. It is multi threaded, submitting either TEST UNIT READY, READ(16) or WRITE(16) SCSI commands asynchronously. Each thread opens a file descriptor and submits those commands up to the queue limit (sg driver has a per file descriptor queue limit of 16). Multiple threads doing the same thing act as a multiplier to that queue limit. Command line processing ======================= These utilities can be divided into 3 groups when their handling of command line arguments is considered: - ad hoc, typically in a short form only, sometimes longer (e.g. "sg_logs -pcb /dev/sdc") - inspired by the dd Unix command (e.g. sg_dd, sgm_dd, sgp_dd, sg_read) - recent utilities use "getopt_long" (see "man getopt_long") type command lines. These have short form (starting with "-") and corresponding longer form (starting with "--") options. The older utilities that use ad hoc options, in alphabetical order: - sg_emc_trespass, sginfo(1/2), sg_inq, sg_logs, sg_map, sg_modes, sg_opcodes, sg_rbuf, sg_rdac, sg_readcap, sg_reset, sg_scan (Linux), sg_senddiag, sg_start, sg_test_rwbuf, sg_turs In sg3_utils version 1.23 the following utilities from this group were converted to have a dual getopt_long/ad_hoc interface, defaulting to the getop_long interface: - sg_inq, sg_logs, sg_modes, sg_opcodes, sg_rbuf, sg_readcap, sg_senddiag, sg_start, sg_turs These can be switched back to the older (backward compatible) ad hoc interface by defining the SG3_UTILS_OLD_OPTS environment variable or using '-O' as the first command line option. The more recent utilities that use "getopt_long" only are: - sg_compare_and_write, sg_decode_sense, sg_format, sg_get_config, sg_get_lba_status, sg_ident, sg_luns, sg_map26, sg_persist, sg_prevent, sg_raw, sg_read_block_limits, sg_read_buffer, sg_read_long, sg_reassign, sg_referrals, sg_requests, sg_rmsn, sg_rtpg, sg_safte, sg_sanitize, sg_sat_identify, sg_sat_phy_event, sg_sat_read_gplog, sg_sat_set_features, sg_scan(w), sg_ses, sg_ses_microcode, sg_stpg, sg_sync, sg_test_rwbuf, sg_unmap, sg_verify, sg_vpd, sg_write_buffer, sg_write_long, sg_write_same, sg_write_verify, sg_wr_mode Dangerous code ============== This C code snippet: unsigned char uc = 0x80; uint64_t ull; ull = (uc << 24); Somewhat surprisingly sets ull to: ull: 0xffffffff80000000 This result is due to the 'unary conversion' of uc to a (32 bit signed) 'int' before the shift. The resultant type from the shift is also an int and it has its top bit set so there is sign extension when it is assigned into a 64 bit unsigned integer. Making sure there is no conversion to 'int' solves the problem. In this case if uc is declared as unsigned int the result will be as expected (i.e. 0x80000000). Other SCSI and storage tools ============================ See http://sg.danny.cz/sg/tools.html Douglas Gilbert 10th November 2014 sg3_utils-1.40/README.sg_start0000664000175000017500000000231611715321645015064 0ustar douggdouggHi, you can use sg_start to start (spin-up, 1) and stop (spin-down, 0) devices. I also offers a parameter (-s) to send a synchronize cache command to a device, so it should write back its internal buffers to the medium. Be aware that the Linux SCSI subsystem at this time does not automatically starts stopped devices, so stopping a device which is in use may have fatal results for you. So, you should apply with care. I use it in my shutdown script at the end (before the poweroff command): # SG_SHUG_NOS is set in my config file rc.config # SG_SHUT_NOS="0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15" if test -x /bin/sg_start; then if test "`basename $command`" = "reboot"; then for no in $SG_SHUT_NOS; do /bin/sg_start /dev/sg$no -s >/dev/null 2>&1; done else for no in $SG_SHUT_NOS; do /bin/sg_start /dev/sg$no -s 0 >/dev/null 2>&1; done fi fi Enjoy! Kurt Garloff Postscript ========== sg_start has been reworked to allow a block device (e.g. /dev/sda) in addition to the sg device name (e.g. /dev/sg0) in the lk 2.6 series. sg_start now has more command line options, see its man page. Douglas Gilbert 2004/5/8 sg3_utils-1.40/configure0000775000175000017500000146313612401205666014277 0ustar douggdougg#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for sg3_utils 1.40. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: dgilbert@interlog.com about your system, including any $0: error possibly output before this message. Then install $0: a modern shell, or manually run the script under such a $0: shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='sg3_utils' PACKAGE_TARNAME='sg3_utils' PACKAGE_VERSION='1.40' PACKAGE_STRING='sg3_utils 1.40' PACKAGE_BUGREPORT='dgilbert@interlog.com' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS OS_WIN32_CYGWIN_FALSE OS_WIN32_CYGWIN_TRUE OS_WIN32_MINGW_FALSE OS_WIN32_MINGW_TRUE OS_SOLARIS_FALSE OS_SOLARIS_TRUE OS_OSF_FALSE OS_OSF_TRUE OS_LINUX_FALSE OS_LINUX_TRUE OS_FREEBSD_FALSE OS_FREEBSD_TRUE os_libs os_cflags GETOPT_O_FILES CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_maintainer_mode enable_dependency_tracking enable_shared enable_static with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock enable_linuxbsg enable_win32_spt_direct enable_scsistrings ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures sg3_utils 1.40 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/sg3_utils] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of sg3_utils 1.40:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --enable-shared[=PKGS] build shared libraries [default=yes] --enable-static[=PKGS] build static libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-linuxbsg ignore linux bsg (sgv4) if present --enable-win32-spt-direct enable Win32 SPT Direct --disable-scsistrings Disable full SCSI sense strings Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF sg3_utils configure 1.40 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by sg3_utils $as_me 1.40, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.14' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='sg3_utils' VERSION='1.40' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE ac_config_headers="$ac_config_headers config.h" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # AC_PROG_CXX # Adding libtools to the build seems to bring in C++ environment case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: # check for headers { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi for ac_header in linux/types.h linux/bsg.h linux/kdev_t.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "#ifdef HAVE_LINUX_TYPES_H # include #endif " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # check for functions for ac_func in getopt_long do : ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long" if test "x$ac_cv_func_getopt_long" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_GETOPT_LONG 1 _ACEOF GETOPT_O_FILES='' else GETOPT_O_FILES='getopt_long.o' fi done for ac_func in posix_fadvise do : ac_fn_c_check_func "$LINENO" "posix_fadvise" "ac_cv_func_posix_fadvise" if test "x$ac_cv_func_posix_fadvise" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_FADVISE 1 _ACEOF fi done for ac_func in posix_memalign do : ac_fn_c_check_func "$LINENO" "posix_memalign" "ac_cv_func_posix_memalign" if test "x$ac_cv_func_posix_memalign" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POSIX_MEMALIGN 1 _ACEOF fi done for ac_func in sysconf do : ac_fn_c_check_func "$LINENO" "sysconf" "ac_cv_func_sysconf" if test "x$ac_cv_func_sysconf" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SYSCONF 1 _ACEOF fi done for ac_func in lseek64 do : ac_fn_c_check_func "$LINENO" "lseek64" "ac_cv_func_lseek64" if test "x$ac_cv_func_lseek64" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LSEEK64 1 _ACEOF fi done cat >>confdefs.h <<_ACEOF #define SG_LIB_BUILD_HOST "${host}" _ACEOF case "${host}" in *-*-linux-gnu*) cat >>confdefs.h <<_ACEOF #define SG_LIB_LINUX 1 _ACEOF os_cflags='' os_libs='' ;; *-*-linux*) cat >>confdefs.h <<_ACEOF #define SG_LIB_LINUX 1 _ACEOF os_cflags='' os_libs='' ;; *-*-freebsd*|*-*-kfreebsd*-gnu*) cat >>confdefs.h <<_ACEOF #define SG_LIB_FREEBSD 1 _ACEOF os_cflags='' os_libs='-lcam' ;; *-*-solaris*) cat >>confdefs.h <<_ACEOF #define SG_LIB_SOLARIS 1 _ACEOF os_cflags='' os_libs='' ;; *-*-osf*) cat >>confdefs.h <<_ACEOF #define SG_LIB_OSF1 1 _ACEOF os_cflags='' os_libs='' ;; *-*-cygwin*) cat >>confdefs.h <<_ACEOF #define SG_LIB_WIN32 1 _ACEOF os_cflags='-Wno-char-subscripts' os_libs='' ;; *-*-mingw*) cat >>confdefs.h <<_ACEOF #define SG_LIB_WIN32 1 _ACEOF cat >>confdefs.h <<_ACEOF #define SG_LIB_MINGW 1 _ACEOF os_cflags='' os_libs='' ;; *) cat >>confdefs.h <<_ACEOF #define SG_LIB_LINUX 1 _ACEOF os_cflags='' os_libs='' ;; esac # Define platform-specific symbol. if echo $host_os | grep 'freebsd' > /dev/null; then OS_FREEBSD_TRUE= OS_FREEBSD_FALSE='#' else OS_FREEBSD_TRUE='#' OS_FREEBSD_FALSE= fi if echo $host_os | grep '^linux' > /dev/null; then OS_LINUX_TRUE= OS_LINUX_FALSE='#' else OS_LINUX_TRUE='#' OS_LINUX_FALSE= fi if echo $host_os | grep '^osf' > /dev/null; then OS_OSF_TRUE= OS_OSF_FALSE='#' else OS_OSF_TRUE='#' OS_OSF_FALSE= fi if echo $host_os | grep '^solaris' > /dev/null; then OS_SOLARIS_TRUE= OS_SOLARIS_FALSE='#' else OS_SOLARIS_TRUE='#' OS_SOLARIS_FALSE= fi if echo $host_os | grep '^mingw' > /dev/null; then OS_WIN32_MINGW_TRUE= OS_WIN32_MINGW_FALSE='#' else OS_WIN32_MINGW_TRUE='#' OS_WIN32_MINGW_FALSE= fi if echo $host_os | grep '^cygwin' > /dev/null; then OS_WIN32_CYGWIN_TRUE= OS_WIN32_CYGWIN_FALSE='#' else OS_WIN32_CYGWIN_TRUE='#' OS_WIN32_CYGWIN_FALSE= fi # Check whether --enable-linuxbsg was given. if test "${enable_linuxbsg+set}" = set; then : enableval=$enable_linuxbsg; cat >>confdefs.h <<_ACEOF #define IGNORE_LINUX_BSG 1 _ACEOF fi # Check whether --enable-win32-spt-direct was given. if test "${enable_win32_spt_direct+set}" = set; then : enableval=$enable_win32_spt_direct; cat >>confdefs.h <<_ACEOF #define WIN32_SPT_DIRECT 1 _ACEOF fi # Check whether --enable-scsistrings was given. if test "${enable_scsistrings+set}" = set; then : enableval=$enable_scsistrings; else cat >>confdefs.h <<_ACEOF #define SG_SCSI_STRINGS 1 _ACEOF fi ac_config_files="$ac_config_files Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_FREEBSD_TRUE}" && test -z "${OS_FREEBSD_FALSE}"; then as_fn_error $? "conditional \"OS_FREEBSD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then as_fn_error $? "conditional \"OS_LINUX\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_OSF_TRUE}" && test -z "${OS_OSF_FALSE}"; then as_fn_error $? "conditional \"OS_OSF\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_SOLARIS_TRUE}" && test -z "${OS_SOLARIS_FALSE}"; then as_fn_error $? "conditional \"OS_SOLARIS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_WIN32_MINGW_TRUE}" && test -z "${OS_WIN32_MINGW_FALSE}"; then as_fn_error $? "conditional \"OS_WIN32_MINGW\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${OS_WIN32_CYGWIN_TRUE}" && test -z "${OS_WIN32_CYGWIN_FALSE}"; then as_fn_error $? "conditional \"OS_WIN32_CYGWIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by sg3_utils $as_me 1.40, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ sg3_utils config.status 1.40 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; "lib/Makefile") CONFIG_FILES="$CONFIG_FILES lib/Makefile" ;; "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;; "scripts/Makefile") CONFIG_FILES="$CONFIG_FILES scripts/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # Whether or not to build static libraries. build_old_libs=$enable_static # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi sg3_utils-1.40/Makefile.in0000664000175000017500000006117012401205666014424 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = . DIST_COMMON = INSTALL NEWS README AUTHORS ChangeLog \ $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/config.h.in COPYING TODO compile config.guess \ config.sub depcomp install-sh missing ltmain.sh ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)config.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = include \ lib \ src \ doc \ scripts EXTRA_DIST = autogen.sh COVERAGE CREDITS all: config.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs distclean-libtool: -rm -f libtool config.lt # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile config.h installdirs: installdirs-recursive installdirs-am: install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic distclean-hdr \ distclean-libtool distclean-local distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-cscope clean-generic \ clean-libtool cscope cscopelist-am ctags ctags-am dist \ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \ dist-xz dist-zip distcheck distclean distclean-generic \ distclean-hdr distclean-libtool distclean-local distclean-tags \ distcleancheck distdir distuninstallcheck dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs installdirs-am maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am distclean-local: rm -rf autom4te.cache rm -f build-stamp configure-stamp # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/examples/0000755000175000017500000000000012431015530014156 5ustar douggdouggsg3_utils-1.40/examples/Makefile0000664000175000017500000000605112404735305015633 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = gcc LD = gcc EXECS = sg_simple1 sg_simple2 sg_simple3 sg_simple4 sg_simple16 \ sg_iovec_tst scsi_inquiry sg_excl sg_sense_test sg_simple5 \ sg__sat_identify sg__sat_phy_event sg__sat_set_features \ sg_sat_chk_power sg_sat_smart_rd_data EXTRAS = sg_simple_aio sg_queue_tst sgq_dd BSG_EXTRAS = bsg_queue_tst MAN_PGS = MAN_PREF = man8 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 CFLAGS = -g -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) # CFLAGS = -g -O2 -Wall -iquote ../include -D_REENTRANT -DSG_KERNEL_INCLUDES $(LARGE_FILE_FLAGS) # CFLAGS = -g -O2 -Wall -pedantic -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) LDFLAGS = LIBFILESOLD = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_io_linux.o LIBFILESNEW = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_pt_linux.o all: $(EXECS) extras: $(EXTRAS) bsg: $(BSG_EXTRAS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) $(EXTRAS) $(BSG_EXTRAS) core .depend sg_simple1: sg_simple1.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_simple2: sg_simple2.o $(LD) -o $@ $(LDFLAGS) $^ sg_simple3: sg_simple3.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_simple4: sg_simple4.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_simple16: sg_simple16.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ # sg_simple_aio: sg_simple_aio.o $(LIBFILESOLD) # $(LD) -o $@ $(LDFLAGS) $^ -l aio sg_simple_aio: sg_simple_aio.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_iovec_tst: sg_iovec_tst.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ scsi_inquiry: scsi_inquiry.o $(LD) -o $@ $(LDFLAGS) $^ sg_excl: sg_excl.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_sense_test: sg_sense_test.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_simple5: sg_simple5.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg__sat_identify: sg__sat_identify.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg__sat_phy_event: sg__sat_phy_event.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg__sat_set_features: sg__sat_set_features.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_sat_chk_power: sg_sat_chk_power.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_sat_smart_rd_data: sg_sat_smart_rd_data.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_queue_tst: sg_queue_tst.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ bsg_queue_tst: bsg_queue_tst.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sgq_dd: sgq_dd.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ install: $(EXECS) install -d $(INSTDIR) for name in $^; \ do install -s -o root -g root -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.40/examples/sg_simple5.c0000664000175000017500000001700410640357443016411 0ustar douggdougg#include #include #include #include #include "sg_lib.h" #include "sg_pt.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic pass through interface. This allows this example program to be ported to OSes other than linux. * Copyright (C) 2006-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. Invocation: sg_simple5 [-x] Version 1.01 (20070331) */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define CMD_TIMEOUT_SECS 60 int main(int argc, char * argv[]) { int sg_fd, k, ok, dsize, res, duration, resid, cat, got, slen; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; char * file_name = 0; char b[512]; unsigned char sense_b[32]; int verbose = 0; struct sg_pt_base * ptvp; for (k = 1; k < argc; ++k) { if (0 == strcmp("-v", argv[k])) verbose = 1; else if (0 == strcmp("-vv", argv[k])) verbose = 2; else if (0 == strcmp("-vvv", argv[k])) verbose = 3; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple5 [-v|-vv|-vvv] '\n"); return 1; } sg_fd = scsi_pt_open_device(file_name, 1 /* ro */, 0); /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if (sg_fd < 0) { fprintf(stderr, "error opening file: %s: %s\n", file_name, safe_strerror(-sg_fd)); return 1; } dsize = sizeof(inqBuff); ok = 0; ptvp = construct_scsi_pt_obj(); /* one object per command */ if (NULL == ptvp) { fprintf(stderr, "sg_simple5: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, inqBuff, dsize); res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose); if (res < 0) { fprintf(stderr, " pass through os error: %s\n", safe_strerror(-res)); goto finish_inq; } else if (SCSI_PT_DO_BAD_PARAMS == res) { fprintf(stderr, " bad pass through setup\n"); goto finish_inq; } else if (SCSI_PT_DO_TIMEOUT == res) { fprintf(stderr, " pass through timeout\n"); goto finish_inq; } if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) fprintf(stderr, " duration=%d ms\n", duration); resid = get_scsi_pt_resid(ptvp); switch ((cat = get_scsi_pt_result_category(ptvp))) { case SCSI_PT_RESULT_GOOD: got = dsize - resid; if (verbose && (resid > 0)) fprintf(stderr, " requested %d bytes but " "got %d bytes)\n", dsize, got); break; case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ if (verbose) { sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp), sizeof(b), b); fprintf(stderr, " scsi status: %s\n", b); } goto finish_inq; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptvp); if (verbose) { sg_get_sense_str("", sense_b, slen, (verbose > 1), sizeof(b), b); fprintf(stderr, "%s", b); } if (verbose && (resid > 0)) { got = dsize - resid; if ((verbose) || (got > 0)) fprintf(stderr, " requested %d bytes but " "got %d bytes\n", dsize, got); } goto finish_inq; case SCSI_PT_RESULT_TRANSPORT_ERR: if (verbose) { get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); fprintf(stderr, " transport: %s", b); } goto finish_inq; case SCSI_PT_RESULT_OS_ERR: if (verbose) { get_scsi_pt_os_err_str(ptvp, sizeof(b), b); fprintf(stderr, " os: %s", b); } goto finish_inq; default: fprintf(stderr, " unknown pass through result " "category (%d)\n", cat); goto finish_inq; } ok = 1; finish_inq: destruct_scsi_pt_obj(ptvp); if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s\n", p + 8, p + 16, p + 32); } ok = 0; /* Now prepare TEST UNIT READY command */ ptvp = construct_scsi_pt_obj(); /* one object per command */ if (NULL == ptvp) { fprintf(stderr, "sg_simple5: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, turCmdBlk, sizeof(turCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); /* no data in or out */ res = do_scsi_pt(ptvp, sg_fd, CMD_TIMEOUT_SECS, verbose); if (res < 0) { fprintf(stderr, " pass through os error: %s\n", safe_strerror(-res)); goto finish_inq; } else if (SCSI_PT_DO_BAD_PARAMS == res) { fprintf(stderr, " bad pass through setup\n"); goto finish_inq; } else if (SCSI_PT_DO_TIMEOUT == res) { fprintf(stderr, " pass through timeout\n"); goto finish_inq; } if ((verbose > 1) && ((duration = get_scsi_pt_duration_ms(ptvp)) >= 0)) fprintf(stderr, " duration=%d ms\n", duration); resid = get_scsi_pt_resid(ptvp); switch ((cat = get_scsi_pt_result_category(ptvp))) { case SCSI_PT_RESULT_GOOD: break; case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ if (verbose) { sg_get_scsi_status_str(get_scsi_pt_status_response(ptvp), sizeof(b), b); fprintf(stderr, " scsi status: %s\n", b); } goto finish_tur; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptvp); if (verbose) { sg_get_sense_str("", sense_b, slen, (verbose > 1), sizeof(b), b); fprintf(stderr, "%s", b); } goto finish_tur; case SCSI_PT_RESULT_TRANSPORT_ERR: if (verbose) { get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); fprintf(stderr, " transport: %s", b); } goto finish_tur; case SCSI_PT_RESULT_OS_ERR: if (verbose) { get_scsi_pt_os_err_str(ptvp, sizeof(b), b); fprintf(stderr, " os: %s", b); } goto finish_tur; default: fprintf(stderr, " unknown pass through result " "category (%d)\n", cat); goto finish_tur; } ok = 1; finish_tur: destruct_scsi_pt_obj(ptvp); if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); scsi_pt_close_device(sg_fd); return 0; } sg3_utils-1.40/examples/sg_simple3.c0000664000175000017500000001473512061626602016412 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver. There is another variant of this program called "sg_simple1". This variant demonstrates using the scatter gather facility in the sg_io_hdr interface to break an INQUIRY response into its component parts. * Copyright (C) 1999 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. Invocation: sg_simple3 [-x] Version 03.58 (20020226) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #define INQ_REPLY_BASE_LEN 8 #define INQ_REPLY_VID_LEN 8 #define INQ_REPLY_PID_LEN 16 #define INQ_REPLY_PREV_LEN 4 #define INQ_REPLY_IOVEC_COUNT 4 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_BASE_LEN + INQ_REPLY_VID_LEN + INQ_REPLY_PID_LEN + INQ_REPLY_PREV_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; sg_iovec_t iovec[INQ_REPLY_IOVEC_COUNT]; unsigned char inqBaseBuff[INQ_REPLY_BASE_LEN]; char inqVidBuff[INQ_REPLY_VID_LEN]; char inqPidBuff[INQ_REPLY_PID_LEN]; char inqPRevBuff[INQ_REPLY_PREV_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple3 [-x] '\n"); return 1; } /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if ((sg_fd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple3: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple3: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); io_hdr.iovec_count = INQ_REPLY_IOVEC_COUNT; io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_BASE_LEN + INQ_REPLY_VID_LEN + INQ_REPLY_PID_LEN + INQ_REPLY_PREV_LEN; iovec[0].iov_base = inqBaseBuff; iovec[0].iov_len = INQ_REPLY_BASE_LEN; iovec[1].iov_base = inqVidBuff; iovec[1].iov_len = INQ_REPLY_VID_LEN; iovec[2].iov_base = inqPidBuff; iovec[2].iov_len = INQ_REPLY_PID_LEN; iovec[3].iov_base = inqPRevBuff; iovec[3].iov_len = INQ_REPLY_PREV_LEN; io_hdr.dxferp = iovec; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple3: Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBaseBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", inqVidBuff, inqPidBuff, inqPRevBuff); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple3: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); close(sg_fd); return 0; } sg3_utils-1.40/examples/README0000664000175000017500000000147112357543201015053 0ustar douggdouggBuilding files in this directory depends on several files being already built in the ../lib directory. So to build files here, the ./configure needs to be executed in the parent directory followed by changing directory to the lib directory and calling 'make' there. Another way is to do a top level 'make' after the ./configure which will make the libraries followed by all the utilities in the src/ directory. There is an brief explanation of each example in the README file in the main (i.e. this directory's parent) directory. There are also some notes at the top of each source file. Those files with the extension "cpp" are C++ examples that use facilities in C++11. They can be built by calling 'make -f Makefile.cplus'. A gcc/g++ compiler of 4.7.3 vintage or later will be required. Douglas Gilbert 10th July 2014 sg3_utils-1.40/examples/reassign_addr.txt0000664000175000017500000000072110640357271017541 0ustar douggdougg# This file is an example for the sg_reassign utility. # That utility can take one or more logical block addresses from stdin when # either the '--address=-" or "-a -" option is given on the command line. # To see logical block addresses placed in the command parameter block # without executing them command try something like: # 'sg_reassign --address=- --dummy -vv /dev/sda < reassign_addr.txt 1,34,0x33,0X444 0x89abcde 0xdeadbeef # 6 lba's # dpg 20070130 sg3_utils-1.40/examples/bsg_queue_tst.c0000664000175000017500000001240412061626602017205 0ustar douggdougg#include #include #include #include #include #include #include #include #include /* If the following fails the Linux kernel is probably too old */ #include #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" /* This program was used to test SCSI mid level queue ordering. The default behaviour is to "queue at head" which is useful for error processing but not for streaming READ and WRITE commands. * Copyright (C) 2010 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. Invocation: bsg_queue_tst [-t] -t queue at tail Version 0.90 (20100324) */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define SDIAG_CMD_LEN 6 #define SENSE_BUFFER_LEN 96 #define EBUFF_SZ 256 #ifndef BSG_FLAG_Q_AT_TAIL #define BSG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef BSG_FLAG_Q_AT_HEAD #define BSG_FLAG_Q_AT_HEAD 0x20 #endif int main(int argc, char * argv[]) { int bsg_fd, k, ok; unsigned char inqCmdBlk[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char sdiagCmdBlk[SDIAG_CMD_LEN] = {0x1d, 0, 0, 0, 0, 0}; unsigned char inqBuff[16][INQ_REPLY_LEN]; struct sg_io_v4 io_hdr[16]; struct sg_io_v4 rio_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[16][SENSE_BUFFER_LEN]; int q_at_tail = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-t", argv[k], 2)) ++q_at_tail; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'bsg_queue_tst [-t] '\n" "where:\n -t queue_at_tail (def: q_at_head)\n"); return 1; } /* An access mode of O_RDWR is required for write()/read() interface */ if ((bsg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "bsg_queue_tst: error opening file: %s", file_name); perror(ebuff); return 1; } for (k = 0; k < 16; ++k) { /* Prepare INQUIRY command */ memset(&io_hdr[k], 0, sizeof(struct sg_io_v4)); io_hdr[k].guard = 'Q'; /* io_hdr[k].iovec_count = 0; */ /* memset takes care of this */ if (0 == (k % 3)) { io_hdr[k].request_len = sizeof(sdiagCmdBlk); io_hdr[k].request = (uint64_t)(long)sdiagCmdBlk; } else { io_hdr[k].request_len = sizeof(inqCmdBlk); io_hdr[k].request = (uint64_t)(long)inqCmdBlk; io_hdr[k].din_xfer_len = INQ_REPLY_LEN; io_hdr[k].din_xferp = (uint64_t)(long)inqBuff[k]; } io_hdr[k].response = (uint64_t)(long)sense_buffer[k]; io_hdr[k].max_response_len = SENSE_BUFFER_LEN; io_hdr[k].timeout = 20000; /* 20000 millisecs == 20 seconds */ io_hdr[k].usr_ptr = k; /* default is to queue at head (in SCSI mid level) */ if (q_at_tail) io_hdr[k].flags |= BSG_FLAG_Q_AT_TAIL; else io_hdr[k].flags |= BSG_FLAG_Q_AT_HEAD; if (write(bsg_fd, &io_hdr[k], sizeof(struct sg_io_v4)) < 0) { perror("bsg_queue_tst: bsg write error"); close(bsg_fd); return 1; } } /* sleep(3); */ for (k = 0; k < 16; ++k) { memset(&rio_hdr, 0, sizeof(struct sg_io_v4)); rio_hdr.guard = 'Q'; if (read(bsg_fd, &rio_hdr, sizeof(struct sg_io_v4)) < 0) { perror("bsg_queue_tst: bsg read error"); close(bsg_fd); return 1; } /* now for the error processing */ ok = 0; if (0 == rio_hdr.device_status) ok = 1; else { switch (sg_err_category_sense((unsigned char *)(long) rio_hdr.response, rio_hdr.response_len)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_print_sense("command error", (unsigned char *)(long)rio_hdr.response, rio_hdr.response_len, 1); break; } } if (ok) { /* output result if it is available */ /* if (0 == rio_hdr.pack_id) */ if (0 == (rio_hdr.usr_ptr % 3)) printf("SEND DIAGNOSTIC %d duration=%u\n", (int)rio_hdr.usr_ptr, rio_hdr.duration); else printf("INQUIRY %d duration=%u\n", (int)rio_hdr.usr_ptr, rio_hdr.duration); } } close(bsg_fd); return 0; } sg3_utils-1.40/examples/sg_tst_excl.cpp0000664000175000017500000005431212400160337017211 0ustar douggdougg/* * Copyright (c) 2013-2014 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" static const char * version_str = "1.09 20140828"; static const char * util_name = "sg_tst_excl"; /* This is a test program for checking O_EXCL on open() works. It uses * multiple threads and can be run as multiple processes and attempts * to "break" O_EXCL. The strategy is to open a device O_EXCL|O_NONBLOCK * and do a double increment on a LB then close it. Prior to the first * increment, the value is checked for even or odd. Assuming the count * starts as an even (typically 0) then it should remain even. Odd instances * are counted and reported at the end of the program, after all threads * have completed. * * This is C++ code with some things from C++11 (e.g. threads) and was * only just able to compile (when some things were reverted) with gcc/g++ * version 4.7.3 found in Ubuntu 13.04 . C++11 "feature complete" support * was not available until g++ version 4.8.1 and that is only currently * found in Fedora 19 . * * The build uses various object files from the /lib directory * which is assumed to be a sibling of this examples directory. Those * object files in the lib directory can be built with: * cd ; ./configure ; cd lib; make * Then to build sg_tst_excl concatenate the next 3 lines: * g++ -Wall -std=c++11 -pthread -I ../include ../lib/sg_lib.o * ../lib/sg_lib_data.o ../lib/sg_io_linux.o -o sg_tst_excl * sg_tst_excl.cpp * or use the C++ Makefile in that directory: * make -f Makefile.cplus sg_tst_excl * * Currently this utility is Linux only and assumes the SG_IO v3 interface * which is supported by sg and block devices (but not bsg devices which * require the SG_IO v4 interface). This restriction is relaxed in the * sg_tst_excl2 variant of this utility. * * BEWARE: this utility modifies a logical block (default LBA 1000) on the * given device. * */ using namespace std; using namespace std::chrono; #define DEF_NUM_PER_THREAD 200 #define DEF_NUM_THREADS 4 #define DEF_WAIT_MS 0 /* 0: yield; -1: don't wait; -2: sleep(0) */ #define DEF_LBA 1000 #define EBUFF_SZ 256 static mutex odd_count_mutex; static mutex console_mutex; static unsigned int odd_count; static unsigned int ebusy_count; static unsigned int eagain_count; static void usage(void) { printf("Usage: %s [-b] [-f] [-h] [-l ] [-n ] " "[-t ]\n" " [-V] [-w ] [-x] [-xx] " "\n", util_name); printf(" where\n"); printf(" -b block on open (def: O_NONBLOCK)\n"); printf(" -f force: any SCSI disk (def: only " "scsi_debug)\n"); printf(" WARNING: written to\n"); printf(" -h print this usage message then exit\n"); printf(" -l logical block to increment (def: %u)\n", DEF_LBA); printf(" -n number of loops per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -t number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" -V print version number then exit\n"); printf(" -w >0: sleep_for(); =0: " "yield(); -1: no\n" " wait; -2: sleep(0) (def: %d)\n", DEF_WAIT_MS); printf(" -x don't use O_EXCL on first thread " "(def: use\n" " O_EXCL on all threads)\n" " -xx don't use O_EXCL on any thread\n\n"); printf("Test O_EXCL open flag with Linux sg driver. Each open/close " "cycle with the\nO_EXCL flag does a double increment on " "lba (using its first 4 bytes).\nEach increment uses a READ_16, " "READ_16, increment, WRITE_16 cycle. The two\nREAD_16s are " "launched asynchronously. Note that '-xx' will run test\n" "without any O_EXCL flags.\n"); } #define READ16_REPLY_LEN 512 #define READ16_CMD_LEN 16 #define WRITE16_REPLY_LEN 512 #define WRITE16_CMD_LEN 16 /* Opens dev_name and spins if busy (i.e. gets EBUSY), sleeping for * wait_ms milliseconds if wait_ms is positive. * Reads lba (twice) and treats the first 4 bytes as an int (SCSI endian), * increments it and writes it back. Repeats so that happens twice. Then * closes dev_name. If an error occurs returns -1 else returns 0 if * first int read from lba is even otherwise returns 1. */ static int do_rd_inc_wr_twice(const char * dev_name, unsigned int lba, int block, int excl, int wait_ms, int id, unsigned int & ebusy, unsigned int & eagains) { int k, sg_fd, ok, res; int odd = 0; unsigned int u = 0; struct sg_io_hdr pt, pt2; unsigned char r16CmdBlk [READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char w16CmdBlk [WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char sense_buffer[64]; unsigned char lb[READ16_REPLY_LEN]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; r16CmdBlk[6] = w16CmdBlk[6] = (lba >> 24) & 0xff; r16CmdBlk[7] = w16CmdBlk[7] = (lba >> 16) & 0xff; r16CmdBlk[8] = w16CmdBlk[8] = (lba >> 8) & 0xff; r16CmdBlk[9] = w16CmdBlk[9] = lba & 0xff; if (! block) open_flags |= O_NONBLOCK; if (excl) open_flags |= O_EXCL; while (((sg_fd = open(dev_name, open_flags)) < 0) && (EBUSY == errno)) { ++ebusy; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_rd_inc_wr_twice: error opening file: %s", dev_name); perror(ebuff); return -1; } for (k = 0; k < 2; ++k) { /* Prepare READ_16 command */ memset(&pt, 0, sizeof(pt)); pt.interface_id = 'S'; pt.cmd_len = sizeof(r16CmdBlk); pt.mx_sb_len = sizeof(sense_buffer); pt.dxfer_direction = SG_DXFER_FROM_DEV; pt.dxfer_len = READ16_REPLY_LEN; pt.dxferp = lb; pt.cmdp = r16CmdBlk; pt.sbp = sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ pt.pack_id = id; // queue up two READ_16s to same LBA if (write(sg_fd, &pt, sizeof(pt)) < 0) { { lock_guard lg(console_mutex); perror("do_rd_inc_wr_twice: write(sg, READ_16)"); } close(sg_fd); return -1; } pt2 = pt; if (write(sg_fd, &pt2, sizeof(pt2)) < 0) { { lock_guard lg(console_mutex); perror("do_rd_inc_wr_twice: write(sg, READ_16) 2"); } close(sg_fd); return -1; } while (((res = read(sg_fd, &pt, sizeof(pt))) < 0) && (EAGAIN == errno)) { ++eagains; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? } if (res < 0) { { lock_guard lg(console_mutex); perror("do_rd_inc_wr_twice: read(sg, READ_16)"); } close(sg_fd); return -1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "Recovered error on READ_16, continuing\n"); } ok = 1; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3("READ_16 command error", &pt, 1); } break; } if (ok) { while (((res = read(sg_fd, &pt2, sizeof(pt2))) < 0) && (EAGAIN == errno)) { ++eagains; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? } if (res < 0) { { lock_guard lg(console_mutex); perror("do_rd_inc_wr_twice: read(sg, READ_16) 2"); } close(sg_fd); return -1; } pt = pt2; /* now for the error processing */ ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "Recovered error on READ_16, continuing " "2\n"); } ok = 1; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3("READ_16 command error 2", &pt, 1); } break; } } if (! ok) { close(sg_fd); return -1; } u = (lb[0] << 24) + (lb[1] << 16) + (lb[2] << 8) + lb[3]; if (0 == k) odd = (1 == (u % 2)); ++u; lb[0] = (u >> 24) & 0xff; lb[1] = (u >> 16) & 0xff; lb[2] = (u >> 8) & 0xff; lb[3] = u & 0xff; if (wait_ms > 0) /* allow daylight for bad things ... */ this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? /* Prepare WRITE_16 command */ memset(&pt, 0, sizeof(pt)); pt.interface_id = 'S'; pt.cmd_len = sizeof(w16CmdBlk); pt.mx_sb_len = sizeof(sense_buffer); pt.dxfer_direction = SG_DXFER_TO_DEV; pt.dxfer_len = WRITE16_REPLY_LEN; pt.dxferp = lb; pt.cmdp = w16CmdBlk; pt.sbp = sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ pt.pack_id = id; if (ioctl(sg_fd, SG_IO, &pt) < 0) { { lock_guard lg(console_mutex); perror("do_rd_inc_wr_twice: WRITE_16 SG_IO ioctl error"); } close(sg_fd); return -1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: { lock_guard lg(console_mutex); fprintf(stderr, "Recovered error on WRITE_16, continuing\n"); } ok = 1; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3("WRITE_16 command error", &pt, 1); } break; } if (! ok) { close(sg_fd); return -1; } } close(sg_fd); return odd; } #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 /* Send INQUIRY and fetches response. If okay puts PRODUCT ID field * in b (up to m_blen bytes). Does not use O_EXCL flag. Returns 0 on success, * else -1 . */ static int do_inquiry_prod_id(const char * dev_name, int block, int wait_ms, unsigned int & ebusys, char * b, int b_mlen) { int sg_fd, ok, ret; struct sg_io_hdr pt; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; unsigned char sense_buffer[64]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; /* O_EXCL | O_RDONLY fails with EPERM */ if (! block) open_flags |= O_NONBLOCK; while (((sg_fd = open(dev_name, open_flags)) < 0) && (EBUSY == errno)) { ++ebusys; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_inquiry_prod_id: error opening file: %s", dev_name); perror(ebuff); return -1; } /* Prepare INQUIRY command */ memset(&pt, 0, sizeof(pt)); pt.interface_id = 'S'; pt.cmd_len = sizeof(inqCmdBlk); /* pt.iovec_count = 0; */ /* memset takes care of this */ pt.mx_sb_len = sizeof(sense_buffer); pt.dxfer_direction = SG_DXFER_FROM_DEV; pt.dxfer_len = INQ_REPLY_LEN; pt.dxferp = inqBuff; pt.cmdp = inqCmdBlk; pt.sbp = sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* pt.flags = 0; */ /* take defaults: indirect IO, etc */ /* pt.pack_id = 0; */ /* pt.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &pt) < 0) { perror("do_inquiry_prod_id: Inquiry SG_IO ioctl error"); close(sg_fd); return -1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: fprintf(stderr, "Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &pt, 1); break; } if (ok) { /* Good, so fetch Product ID from response, copy to 'b' */ if (b_mlen > 0) { if (b_mlen > 16) { memcpy(b, inqBuff + 16, 16); b[16] = '\0'; } else { memcpy(b, inqBuff + 16, b_mlen - 1); b[b_mlen - 1] = '\0'; } } ret = 0; } else ret = -1; close(sg_fd); return ret; } static void work_thread(const char * dev_name, unsigned int lba, int id, int block, int excl, int num, int wait_ms) { unsigned int thr_odd_count = 0; unsigned int thr_ebusy_count = 0; unsigned int thr_eagain_count = 0; int k, res; { lock_guard lg(console_mutex); cerr << "Enter work_thread id=" << id << " excl=" << excl << " block=" << block << endl; } for (k = 0; k < num; ++k) { res = do_rd_inc_wr_twice(dev_name, lba, block, excl, wait_ms, k, thr_ebusy_count, thr_eagain_count); if (res < 0) break; if (res) ++thr_odd_count; } { lock_guard lg(console_mutex); if (k < num) cerr << "thread id=" << id << " FAILed at iteration: " << k << '\n'; else cerr << "thread id=" << id << " normal exit" << '\n'; } { lock_guard lg(odd_count_mutex); odd_count += thr_odd_count; ebusy_count += thr_ebusy_count; eagain_count += thr_eagain_count; } } int main(int argc, char * argv[]) { int k, res; int block = 0; int force = 0; unsigned int lba = DEF_LBA; int num_per_thread = DEF_NUM_PER_THREAD; int num_threads = DEF_NUM_THREADS; int wait_ms = DEF_WAIT_MS; int no_o_excl = 0; char * dev_name = NULL; char b[64]; for (k = 1; k < argc; ++k) { if (0 == memcmp("-b", argv[k], 2)) ++block; else if (0 == memcmp("-f", argv[k], 2)) ++force; else if (0 == memcmp("-h", argv[k], 2)) { usage(); return 0; } else if (0 == memcmp("-l", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) lba = (unsigned int)atoi(argv[k]); else break; } else if (0 == memcmp("-n", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_per_thread = atoi(argv[k]); else break; } else if (0 == memcmp("-t", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_threads = atoi(argv[k]); else break; } else if (0 == memcmp("-V", argv[k], 2)) { printf("%s version: %s\n", util_name, version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) { ++k; if ((k < argc) && (isdigit(*argv[k]) || ('-' == *argv[k]))) { if ('-' == *argv[k]) wait_ms = - atoi(argv[k] + 1); else wait_ms = atoi(argv[k]); } else break; } else if (0 == memcmp("-xxx", argv[k], 4)) no_o_excl += 3; else if (0 == memcmp("-xx", argv[k], 3)) no_o_excl += 2; else if (0 == memcmp("-x", argv[k], 2)) ++no_o_excl; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); dev_name = NULL; break; } else if (! dev_name) dev_name = argv[k]; else { printf("too many arguments\n"); dev_name = 0; break; } } if (0 == dev_name) { usage(); return 1; } try { struct stat a_stat; if (stat(dev_name, &a_stat) < 0) { perror("stat() on dev_name failed"); return 1; } if (! S_ISCHR(a_stat.st_mode)) { fprintf(stderr, "%s should be a sg device which is a char " "device. %s\n", dev_name, dev_name); fprintf(stderr, "is not a char device and damage could be done " "if it is a BLOCK\ndevice, exiting ...\n"); return 1; } if (! force) { res = do_inquiry_prod_id(dev_name, block, wait_ms, ebusy_count, b, sizeof(b)); if (res) { fprintf(stderr, "INQUIRY failed on %s\n", dev_name); return 1; } // For safety, since written to, only permit scsi_debug // devices. Bypass this with '-f' option. if (0 != memcmp("scsi_debug", b, 10)) { fprintf(stderr, "Since this utility writes to LBA %d, only " "devices with scsi_debug\nproduct ID accepted.\n", lba); return 2; } } vector vt; for (k = 0; k < num_threads; ++k) { int excl = 1; if (no_o_excl > 1) excl = 0; else if ((0 == k) && (1 == no_o_excl)) excl = 0; thread * tp = new thread {work_thread, dev_name, lba, k, block, excl, num_per_thread, wait_ms}; vt.push_back(tp); } // g++ 4.7.3 didn't like range-for loop here for (k = 0; k < (int)vt.size(); ++k) vt[k]->join(); for (k = 0; k < (int)vt.size(); ++k) delete vt[k]; if (no_o_excl) cout << "Odd count: " << odd_count << endl; else cout << "Expecting odd count of 0, got " << odd_count << endl; cout << "Number of EBUSYs: " << ebusy_count << endl; cout << "Number of EAGAINs: " << eagain_count << endl; } catch(system_error& e) { cerr << "got a system_error exception: " << e.what() << '\n'; auto ec = e.code(); cerr << "category: " << ec.category().name() << '\n'; cerr << "value: " << ec.value() << '\n'; cerr << "message: " << ec.message() << '\n'; cerr << "\nNote: if g++ may need '-pthread' or similar in " "compile/link line" << '\n'; } catch(...) { cerr << "got another exception: " << '\n'; } return 0; } sg3_utils-1.40/examples/sdiag_sas_p0_cjtpat.txt0000664000175000017500000000062511213073735020635 0ustar douggdougg# This is the hex for a SAS protocol specific diagnostic # page. It will attempt to put phy identifier 0 of the # given device into CJTPAT (jitter pattern) generation mode. # Physical transmission speed is 3 Gbps # N.B. This will turn the receiver off on phy id 0. # # Usage example: 'sg_senddiag --pf --raw=- /dev/sg2 < {this_file}' # 3f,6,0,1c,0,1,2,9, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 sg3_utils-1.40/examples/sg_iovec_tst.c0000664000175000017500000001356212061626602017032 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 2003-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. This program will read a certain number of blocks of a given block size from a given sg device node and write what is retrieved out to a normal file. The purpose is to test the sg_iovec mechanism within the sg_io_hdr structure. Version 0.12 (20070121) */ #define ME "sg_iovec_tst: " #define A_PRIME 509 #define IOVEC_ELEMS 2048 #define SENSE_BUFF_LEN 32 #define DEF_TIMEOUT 40000 /* 40,000 milliseconds */ struct sg_iovec iovec[IOVEC_ELEMS]; /* Returns 0 if everything ok */ int sg_read(int sg_fd, unsigned char * buff, int num_blocks, int from_block, int bs) { unsigned char rdCmd[10] = {READ_10, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char senseBuff[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; int dxfer_len = bs * num_blocks; int k, pos, rem; rdCmd[2] = (unsigned char)((from_block >> 24) & 0xff); rdCmd[3] = (unsigned char)((from_block >> 16) & 0xff); rdCmd[4] = (unsigned char)((from_block >> 8) & 0xff); rdCmd[5] = (unsigned char)(from_block & 0xff); rdCmd[7] = (unsigned char)((num_blocks >> 8) & 0xff); rdCmd[8] = (unsigned char)(num_blocks & 0xff); for (k = 0, pos = 0, rem = dxfer_len; k < IOVEC_ELEMS; ++k) { iovec[k].iov_base = buff + pos; iovec[k].iov_len = (rem > A_PRIME) ? A_PRIME : rem; if (rem <= A_PRIME) break; pos += A_PRIME; rem -= A_PRIME; } if (k >= IOVEC_ELEMS) { fprintf(stderr, "Can't fit dxfer_len=%d bytes in iovec\n", dxfer_len); return -1; } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rdCmd); io_hdr.cmdp = rdCmd; io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = dxfer_len; io_hdr.iovec_count = k + 1; io_hdr.dxferp = iovec; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = from_block; if (ioctl(sg_fd, SG_IO, &io_hdr)) { perror("reading (SG_IO) on sg device, error"); return -1; } switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: fprintf(stderr, "Recovered error while reading block=%d, num=%d\n", from_block, num_blocks); break; case SG_LIB_CAT_UNIT_ATTENTION: fprintf(stderr, "Unit attention\n"); return -1; default: sg_chk_n_print3("reading", &io_hdr, 1); return -1; } return 0; } int main(int argc, char * argv[]) { int sg_fd, fd, res, j, m, dxfer_len; unsigned int k, num; int do_help = 0; int blk_size = 512; int count = 0; char * sg_file_name = 0; char * out_file_name = 0; unsigned char * buffp; for (j = 1; j < argc; ++j) { if (0 == strncmp("-b=", argv[j], 3)) { m = 3; num = sscanf(argv[j] + m, "%d", &blk_size); if ((1 != num) || (blk_size <= 0)) { printf("Couldn't decode number after '-b' switch\n"); sg_file_name = 0; break; } } else if (0 == strncmp("-c=", argv[j], 3)) { m = 3; num = sscanf(argv[j] + m, "%d", &count); if (1 != num) { printf("Couldn't decode number after '-c' switch\n"); sg_file_name = 0; break; } } else if (0 == strcmp("-h", argv[j])) do_help = 1; else if (*argv[j] == '-') { printf("Unrecognized switch: %s\n", argv[j]); sg_file_name = 0; break; } else if (NULL == sg_file_name) sg_file_name = argv[j]; else out_file_name = argv[j]; } if ((NULL == sg_file_name) || (NULL == out_file_name) || (0 == count)) { printf("Usage: sg_iovec_tst [-h] [-b=num] -c=num " "\n"); printf(" where: -h this usage message\n"); printf(" -b=num block size (default 512 Bytes)\n"); printf(" -c=num count of blocks to transfer\n"); printf(" reads from and sends to " "\n"); return 1; } sg_fd = open(sg_file_name, O_RDONLY); if (sg_fd < 0) { perror(ME "sg device node open error"); return 1; } /* Don't worry, being very careful not to write to a none-sg file ... */ res = ioctl(sg_fd, SG_GET_VERSION_NUM, &k); if ((res < 0) || (k < 30000)) { printf(ME "not a sg device, or driver prior to 3.x\n"); return 1; } fd = open(out_file_name, O_WRONLY | O_CREAT, 0666); if (fd < 0) { perror(ME "output file open error"); return 1; } dxfer_len = count * blk_size; buffp = (unsigned char *)malloc(dxfer_len); if (buffp) { if (0 == sg_read(sg_fd, buffp, count, 0, blk_size)) { if (write(fd, buffp, dxfer_len) < 0) perror(ME "output write failed"); } free(buffp); } res = close(fd); if (res < 0) { perror(ME "output file close error"); close(sg_fd); return 1; } res = close(sg_fd); if (res < 0) { perror(ME "sg device close error"); return 1; } return 0; } sg3_utils-1.40/examples/sdiag_sas_p1_cjtpat.txt0000664000175000017500000000072011213073735020632 0ustar douggdougg# This is the hex for a SAS protocol specific diagnostic # page. It will attempt to put phy identifier 1 of the # given device into CJTPAT (jitter pattern) generation mode. # Physical transmission speed is 3 Gbps # See sdiag_sas_p1_stop.txt to turn off this test pattern. # N.B. This will turn the receiver off on phy id 1. # # Usage example: 'sg_senddiag --pf --raw=- /dev/sg2 < {this_file}' # 3f,6,0,1c,1,1,2,9, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 sg3_utils-1.40/examples/transport_ids.txt0000664000175000017500000000216011244617022017620 0ustar douggdougg# This file is an example for the sg_persist utility. # It discusses using "TransportID"s which are defined (most recently) # in SPC-4 revison 20 section 7.5.4 titled: "TransportID identifiers". # # The sg_persist utility can take one or more "transportID"s from stdin when # either the '--transport-id=-" or "-X -" option is given on the command # line. # To see transport IDs decoded after they have been read in (e.g. to check # they are well formed) use the verbose flag 3 times (i.e. "... -vvv ..."). # Here is a simple example (for SPI) of a comma separted hex list: 1,0,0,7,0,0,0,1 # SPI, initiator address=7, relative_port_num=1 # and here is the transport specific format for the same thing: # spi,1,7 # An example for SAS follows, first as a hex string, then in transport # specific format (incremented by 1) 6,0,0,0,50,6,5,b0,0,6,f2,60 sas,500605b00006f261 # For iSCSI the hex list form is awkward, better to use the transport # specific format. [The leading spaces are ignored.] iqn.5886.com.acme.diskarrays-sn-a8675309 # Leading spaces and tabs before a '#' are ok. # dpg 20090824 sg3_utils-1.40/examples/Makefile.cplus0000664000175000017500000000365212404735305016764 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = g++ LD = g++ ## CC = clang++ ## LD = clang++ EXECS = sg_tst_excl sg_tst_excl2 sg_tst_excl3 sg_tst_context sg_tst_async EXTRAS = BSG_EXTRAS = MAN_PGS = MAN_PREF = man8 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 CPPFLAGS = -std=c++11 -pthread -g -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) ## CFLAGS = -g -O2 -W -Wall -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) # CFLAGS = -g -O2 -Wall -iquote ../include -D_REENTRANT -DSG_KERNEL_INCLUDES $(LARGE_FILE_FLAGS) # CFLAGS = -g -O2 -Wall -pedantic -iquote ../include -D_REENTRANT $(LARGE_FILE_FLAGS) LDFLAGS = -std=c++11 -pthread LIBFILESOLD = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_io_linux.o LIBFILESNEW = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_pt_linux.o all: $(EXECS) extras: $(EXTRAS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) $(EXTRAS) $(BSG_EXTRAS) core .depend sg_tst_excl: sg_tst_excl.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_excl2: sg_tst_excl2.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_excl3: sg_tst_excl3.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_context: sg_tst_context.o $(LIBFILESNEW) $(LD) -o $@ $(LDFLAGS) $^ sg_tst_async: sg_tst_async.o $(LIBFILESOLD) $(LD) -o $@ $(LDFLAGS) $^ install: $(EXECS) install -d $(INSTDIR) for name in $^; \ do install -s -o root -g root -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.40/examples/sg_simple1.c0000664000175000017500000001346012061626602016402 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver There is another variant of this program called "sg_simple2" which does not include the sg_lib.h header and logic and so has simpler but more primitive error processing. In the lk 2.6 series devices nodes such as /dev/sda also support the SG_IO ioctl. * Copyright (C) 1999-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. Invocation: sg_simple1 [-x] Version 03.58 (20070312) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple1 [-x] '\n"); return 1; } /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if ((sg_fd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple1: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple1: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple1: Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple1: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); close(sg_fd); return 0; } sg3_utils-1.40/examples/sg__sat_set_features.c0000664000175000017500000002341310646136655020541 0ustar douggdougg/* * Copyright (c) 2006-2007 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program performs a ATA PASS-THROUGH (16) SCSI command in order to perform an ATA SET FEATURES command. See http://www.t10.org SAT draft at time of writing: sat-r09.pdf Invocation: sg_sat_set_features [-c ] [-f ] [-h] [-L ] [-v] [-V] */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ATA_SET_FEATURES 0xef #define EBUFF_SZ 256 static char * version_str = "1.03 20070719"; static struct option long_options[] = { {"count", required_argument, 0, 'c'}, {"chk_cond", no_argument, 0, 'C'}, {"feature", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"lba", required_argument, 0, 'L'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; void usage() { fprintf(stderr, "Usage: " "sg_sat_set_features [--count=C] [--chk_cond] [--feature=F] " "[--help]\n" " [-lba=LBA] [--verbose] [--version] " "DEVICE\n" " where:\n" " --count=C|-c C count field contents (def: 0)\n" " --chk_cond|-C set chk_cond field in pass-through " "(def: 0)\n" " --feature=F|-f F feature field contents (def: 0)\n" " --help|-h output this usage message\n" " --lba=LBA| -L LBA LBA field contents (def: 0)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Sends an ATA SET FEATURES command via a SAT pass through.\n" "Primary feature code is placed in '--feature=F' with '--count=C' " "and\n" "'--lba=LBA' being auxiliaries for some features. The arguments C, " "F and LBA\n" "are decimal unless prefixed by '0x' or have a trailing 'h'.\n" "Example enabling write cache: 'sg_sat_set_feature --feature=2 " "/dev/sdc'\n"); } int main(int argc, char * argv[]) { int sg_fd, c, k; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sg_io_hdr_t io_hdr; char device_name[256]; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[64]; int count = 0; int feature = 0; int lba = 0; int verbose = 0; int extend = 0; int chk_cond = 0; /* set to 1 to read register(s) back */ int protocol = 3; /* non-data data-in */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */ const unsigned char * ucp = NULL; memset(device_name, 0, sizeof(device_name)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:Cf:hL:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': count = sg_get_num(optarg); if ((count < 0) || (count > 255)) { fprintf(stderr, "bad argument for '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': chk_cond = 1; break; case 'f': feature = sg_get_num(optarg); if ((feature < 0) || (feature > 255)) { fprintf(stderr, "bad argument for '--feature'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'L': lba = sg_get_num(optarg); if ((lba < 0) || (lba > 255)) { fprintf(stderr, "bad argument for '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if ('\0' == device_name[0]) { fprintf(stderr, "missing device name!\n"); usage(); return 1; } if ((sg_fd = open(device_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_sat_set_features: error opening file: %s", device_name); perror(ebuff); return 1; } /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[14] = ATA_SET_FEATURES; aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; aptCmdBlk[4] = feature; aptCmdBlk[6] = count; aptCmdBlk[8] = lba & 0xff; aptCmdBlk[10] = (lba >> 8) & 0xff; aptCmdBlk[12] = (lba >> 16) & 0xff; if (verbose) { fprintf(stderr, " ata pass through(16) cdb: "); for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k) fprintf(stderr, "%02x ", aptCmdBlk[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(aptCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.dxfer_len = 0; io_hdr.dxferp = NULL; io_hdr.cmdp = aptCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_sat_set_features: SG_IO ioctl error"); close(sg_fd); return 1; } /* error processing: N.B. expect check condition, no sense ... !! */ switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: /* sat-r09 uses this sk */ case SG_LIB_CAT_NO_SENSE: /* earlier SAT drafts used this */ ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == ucp) { if (verbose > 1) printf("ATA Return Descriptor expected in sense but not " "found\n"); sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); } else if (verbose) sg_chk_n_print3("ATA Return Descriptor", &io_hdr, 1); if (ucp && ucp[3]) { if (ucp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]); } break; default: fprintf(stderr, "unexpected SCSI sense category\n"); ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == ucp) sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); else if (verbose) sg_chk_n_print3("ATA Return Descriptor, as expected", &io_hdr, 1); if (ucp && ucp[3]) { if (ucp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]); } break; } close(sg_fd); return 0; } sg3_utils-1.40/examples/sg_unmap_example.txt0000664000175000017500000000315311250760723020260 0ustar douggdougg# sg_unmap_example.txt # This is an example of the contents of a file that can be given to sg_unmap # For example, assume the /dev/sdc is a scratch disk (e.g. one made by the # scsi_debug kernel module) then: # sg_unmap --in=sg_unmap_example.txt /dev/sdc 0x12345677,1 # unmap LBA 0x12345677 0x12345678 2 # unmap LBA 0x12345678 and 0x12345679 0x12340000 3333 # unmap 3333 blocks starting at LBA 0x12340000 0X5a5a5a5a5a 0 # unmaps 0 blocks (i.e. does nothing) a5a5a5h 7 # unmap 7 blocks starting at LBA 0xa5a5a5 # Note that there can be leading and trailing whitespace and whitespace # (plus comma) can be a separator. # # Example invocation: # $ sg_unmap --in=../examples/sg_unmap_example.txt -vv /dev/sdc # open /dev/sg2 with flags=0x802 # unmap cdb: 42 00 00 00 00 00 00 00 58 00 # unmap parameter list: # 00 56 00 50 00 00 00 00 00 00 00 00 12 34 56 77 # 00 00 00 01 00 00 00 00 00 00 00 00 12 34 56 78 # 00 00 00 02 00 00 00 00 00 00 00 00 12 34 00 00 # 00 00 0d 05 00 00 00 00 00 00 00 5a 5a 5a 5a 5a # 00 00 00 00 00 00 00 00 00 00 00 00 00 a5 a5 a5 # 00 00 00 07 00 00 00 00 # sg_cmds_process_resp: slen=18 # unmap: Fixed format, current; Sense key: Illegal Request # Additional sense: Invalid command operation code # Raw sense data (in hex): # 70 00 05 00 00 00 00 0a 00 00 00 00 20 00 00 00 # 00 00 # UNMAP not supported # # -------------------------------------------------------- # Notice the 8 byte header then 5 descriptors in the parameter # list sg3_utils-1.40/examples/sg_simple16.c0000664000175000017500000000664510640357443016504 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program performs a READ_16 command as scsi mid-level support 16 byte commands from lk 2.4.15 * Copyright (C) 2001 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. Invocation: sg_simple16 Version 1.02 (20020206) */ #define READ16_REPLY_LEN 512 #define READ16_CMD_LEN 16 #define EBUFF_SZ 256 int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char r16CmdBlk [READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char inBuff[READ16_REPLY_LEN]; unsigned char sense_buffer[32]; for (k = 1; k < argc; ++k) { if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple16 '\n"); return 1; } if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple16: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple16: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare READ_16 command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(r16CmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = READ16_REPLY_LEN; io_hdr.dxferp = inBuff; io_hdr.cmdp = r16CmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple16: Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on READ_16, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ_16 command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ printf("READ_16 duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } close(sg_fd); return 0; } sg3_utils-1.40/examples/sg_sense_test.c0000664000175000017500000000742212117736101017203 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" /* This is a simple program that tests the sense data descriptor format printout function in sg_lib.c * Copyright (C) 2004-20013 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. */ #define EBUFF_SZ 256 #define ME "sg_sense_test: " int main(/* int argc, char * argv[] */) { unsigned char err1[] = {0x72, 0x5, 0x4, 0x1, 0, 0, 0, 32, 0x2, 0x6, 0, 0, 0xc8, 0x0, 0x3, 0, 0, 0xa, 0x80, 0, 1, 2, 3, 4, 0xaa, 0xbb, 0xcc, 0xdd, 1, 0xa, 0, 0, 1, 2, 3, 4, 0xaa, 0xbb, 0xee, 0xff}; unsigned char err2[] = {0x72, SPC_SK_MEDIUM_ERROR, 0x4, 0x1, 0x80, 0, 0, 32, 0x2, 0x6, 0, 0, 0xc8, 0x0, 0x3, 0, 0, 0xa, 0x80, 0, 1, 2, 3, 4, 0xaa, 0xbb, 0xcc, 0xdd, 1, 0xa, 0, 0, 1, 2, 3, 4, 0xaa, 0xbb, 0xee, 0xff}; /* Set SDAT_OVFL */ unsigned char err3[] = {0x72, SPC_SK_NO_SENSE, 0x4, 0x1, 0, 0, 0, 8, 0x2, 0x6, 0, 0, 0xc8, 0x0, 0x3, 0}; unsigned char err4[] = {0x73, SPC_SK_COPY_ABORTED, 0x4, 0x1, 0, 0, 0, 22, 0x2, 0x6, 0, 0, 0xc8, 0x0, 0x3, 0, 0x3, 0x2, 0, 0x55, 0x5, 0x2, 0, 0x20, 0x85, 0x4, 0, 0x20, 0x33, 0x44}; /* Set Filemark, EOM, ILI and SDAT_OVFL */ unsigned char err5[] = {0xf1, 0, (0xf0 | SPC_SK_ILLEGAL_REQUEST), 0x11, 0x22, 0x33, 0x44, 0xa, 0x0, 0x0, 0, 0, 0x4, 0x1, 0, 0xcf, 0, 5,}; unsigned char err6[] = {0x72, SPC_SK_NO_SENSE, 0x4, 0x1, 0, 0, 0, 14, 0x9, 0xc, 1, 0, 0x11, 0x22, 0x66, 0x33, 0x77, 0x44, 0x88, 0x55, 0x1, 0x2}; unsigned char err7[] = {0xf1, 0, 0xe5, 0x11, 0x22, 0x33, 0x44, 0xa, 0x0, 0x0, 0x0, 0x0, 0x24, 0x1, 0xbb, 0xc9, 0x0, 0x2}; char leadin[128]; char b[2048]; int k, prev_len; sg_print_sense("err1 test", err1, sizeof(err1), 1 /* raw_info */); sg_print_sense("\nerr2 test", err2, sizeof(err2), 1); sg_print_sense("\nerr3 test", err3, sizeof(err3), 1); sg_print_sense("\nerr4 test", err4, sizeof(err4), 1); sg_print_sense("\nerr5 test", err5, sizeof(err5), 1); sg_print_sense("\nerr6 test", err6, sizeof(err6), 1); sg_print_sense("\nerr7 test", err7, sizeof(err7), 1); printf("\n\nTry different output string sizes with " "sg_get_sense_str(err2):\n"); for (k = 1, prev_len = -1; k < 512; ++k) { snprintf(leadin, sizeof(leadin), "blen=%d", k); sg_get_sense_str(leadin, err2, sizeof(err2), 0, k, b); printf("%s\n", b); if (prev_len == (int)strlen(b)) break; else prev_len = strlen(b); } printf("\n\nTry different output string sizes with " "sg_get_sense_str(err4):\n"); for (k = 1, prev_len = -1; k < 512; ++k) { snprintf(leadin, sizeof(leadin), "blen=%d", k); sg_get_sense_str(leadin, err4, sizeof(err4), 0, k, b); printf("%s\n", b); if (prev_len == (int)strlen(b)) break; else prev_len = strlen(b); } return 0; } sg3_utils-1.40/examples/sg_compare_and_write.txt0000664000175000017500000000466412061266052021114 0ustar douggdougg# sg_compare_and_write.txt # This file provides a usage example of sg_compare_and_write. # sg_compare_and_write accepts a buffer containing 2 logical instances: # - the verify instance: used to match the current content of the LBA range # - the write instance: used to write to the LBA if the verify succeeds # # In case of failure to verify the data, the command will return with check # condition with the sense code set to MISCOMPARE DURING VERIFY OPERATION. # # The following example shows initialization, successful and unsuccessful # compare and write using sg3_utils. I am using caw_buf_zero2one and # caw_buf_one2zero as shown bellow. $ hexdump /tmp/caw_buf_zero2one 0000000 0000 0000 0000 0000 0000 0000 0000 0000 * 0000200 1111 1111 1111 1111 1111 1111 1111 1111 * 0000400 $ hexdump /tmp/caw_buf_one2zero 0000000 1111 1111 1111 1111 1111 1111 1111 1111 * 0000200 0000 0000 0000 0000 0000 0000 0000 0000 * 0000400 $ sg_map -i -x /dev/sg0 0 0 0 0 0 /dev/sda ATA ST3320613AS CC2H /dev/sg1 3 0 0 0 5 /dev/scd0 HL-DT-ST DVD-RAM GH22NS30 1.01 /dev/sg2 5 0 0 0 0 /dev/sdb KMNRIO K2 0000 /dev/sg3 5 0 0 1 0 /dev/sdc KMNRIO K2 0000 # First I zero out the volume to make sure that the first compare and write # will succeed $ sg_write_same --16 -i /dev/zero -n 0x200000 -x 512 /dev/sdc $ dd if=/dev/sdc bs=512 count=1 skip=100 2>/dev/null | hexdump 0000000 0000 0000 0000 0000 0000 0000 0000 0000 * 0000200 $ ./sg_compare_and_write --in=/tmp/caw_buf_zero2one --lba=100 --xferlen=1024 /dev/sdc # contents of LBA 100 are a block of ones $ dd if=/dev/sdc bs=512 count=1 skip=100 2>/dev/null | hexdump 0000000 1111 1111 1111 1111 1111 1111 1111 1111 * 0000200 # We repeat the same compare and write command (zero2one input buffer). # compare and write fails since the verify failed (compared the zero block to # the actual 1 block in LBA 100 $ ./sg_compare_and_write --in=/tmp/caw_buf_zero2one --lba=100 --xferlen=1024 /dev/sdc COMPARE AND WRITE: Fixed format, current; Sense key: Miscompare Additional sense: Miscompare during verify operation sg_compare_and_write: SCSI COMPARE AND WRITE failed # Now we use the second buffer (one2zero) $ ./sg_compare_and_write --in=/tmp/caw_buf_one2zero --lba=100 --xferlen=1024 /dev/sdc # operation succeeded, contents of LBA 100 are back to zero $ dd if=/dev/sdc bs=512 count=1 skip=100 2>/dev/null | hexdump 0000000 0000 0000 0000 0000 0000 0000 0000 0000 * 0000200 sg3_utils-1.40/examples/sg_tst_context.cpp0000664000175000017500000003570112400160337017743 0ustar douggdougg/* * Copyright (c) 2013 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pt.h" static const char * version_str = "1.02 20140828"; static const char * util_name = "sg_tst_context"; /* This is a test program for checking that file handles keep their * context properly when sent (synchronous) SCSI pass-through commands. * A disk device is assumed and even-numbered threads send TEST UNIT * READY commands while odd-numbered threads send alternating START STOP * UNIT commands (i.e. start then stop then start, etc). The point is to * check the results to make sure that they don't get the other command's * response. For example a START STOP UNIT command should not see a "not * ready" sense key. * * This is C++ code with some things from C++11 (e.g. threads) and was * only just able to compile (when some things were reverted) with gcc/g++ * version 4.7.3 found in Ubuntu 13.04 . C++11 "feature complete" support * was not available until g++ version 4.8.1 and that is found in Fedora * 19 and Ubuntu 13.10 . * * The build uses various object files from the /lib directory * which is assumed to be a sibling of this examples directory. Those * object files in the lib directory can be built with: * cd ; ./configure ; cd lib; make * Then to build sg_tst_context concatenate the next 3 lines: * g++ -Wall -std=c++11 -pthread -I ../include ../lib/sg_lib.o * ../lib/sg_lib_data.o ../lib/sg_pt_linux.o -o sg_tst_context * sg_tst_context.cpp * Alternatively use 'make -f Makefile.cplus sg_tst_context' * */ using namespace std; using namespace std::chrono; #define DEF_NUM_PER_THREAD 200 #define DEF_NUM_THREADS 2 #define EBUFF_SZ 256 static mutex count_mutex; static mutex console_mutex; static unsigned int even_notreadys; static unsigned int odd_notreadys; static unsigned int ebusy_count; static void usage(void) { printf("Usage: %s [-e] [-h] [-n ] [-N] [-R] [-s]\n" " [-t ] [-V] \n", util_name); printf(" where\n"); printf(" -e use O_EXCL on open (def: don't)\n"); printf(" -h print this usage message then exit\n"); printf(" -n number of loops per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -N use O_NONBLOCK on open (def: don't)\n"); printf(" -R make sure device in ready (started) " "state after\n" " test (do extra iteration if " "necessary)\n"); printf(" -s share an open file handle (def: one " "per thread)\n"); printf(" -t number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" -V print version number then exit\n\n"); printf("Test if file handles keep context through to their responses. " "Sends\nTEST UNIT READY commands on even threads (origin 0) and " "START STOP\nUNIT commands on odd threads. Expect NOT READY " "sense keys only\nfrom the even threads (i.e from TUR)\n"); } static int pt_err(int res) { if (res < 0) fprintf(stderr, " pass through OS error: %s\n", safe_strerror(-res)); else if (SCSI_PT_DO_BAD_PARAMS == res) fprintf(stderr, " bad pass through setup\n"); else if (SCSI_PT_DO_TIMEOUT == res) fprintf(stderr, " pass through timeout\n"); else fprintf(stderr, " do_scsi_pt error=%d\n", res); return (res < 0) ? res : -EPERM /* -1 */; } static int pt_cat_no_good(int cat, struct sg_pt_base * ptp, const unsigned char * sbp) { int slen; char b[256]; const int bl = (int)sizeof(b); const char * cp = NULL; b[0] = '\0'; switch (cat) { case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ sg_get_scsi_status_str(get_scsi_pt_status_response(ptp), bl, b); cp = " scsi status: %s\n"; break; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptp); sg_get_sense_str("", sbp, slen, 1, bl, b); cp = "%s\n"; break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptp, bl, b); cp = " transport: %s\n"; break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptp, bl, b); cp = " os: %s\n"; break; default: cp = " unknown pt result category (%d)\n"; break; } if (cp) { lock_guard lg(console_mutex); fprintf(stderr, cp, b); } return -EIO /* -5 */; } #define TUR_CMD_LEN 6 #define SSU_CMD_LEN 6 #define NOT_READY SG_LIB_CAT_NOT_READY /* Returns 0 for good, 1024 for a sense key of NOT_READY, or a negative * errno */ static int do_tur(int pt_fd, int id) { int slen, res, cat; struct sg_pt_base * ptp = NULL; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}; unsigned char sense_buffer[64]; ptp = construct_scsi_pt_obj(); set_scsi_pt_cdb(ptp, turCmdBlk, sizeof(turCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); res = do_scsi_pt(ptp, pt_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "TEST UNIT READY do_scsi_pt() submission error, " "id=%d\n", id); } res = pt_err(res); goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { slen = get_scsi_pt_sense_len(ptp); if ((SCSI_PT_RESULT_SENSE == cat) && (NOT_READY == sg_err_category_sense(sense_buffer, slen))) { res = 1024; goto err; } { lock_guard lg(console_mutex); fprintf(stderr, "TEST UNIT READY do_scsi_pt() category problem, " "id=%d\n", id); } res = pt_cat_no_good(cat, ptp, sense_buffer); goto err; } res = 0; err: if (ptp) destruct_scsi_pt_obj(ptp); return res; } /* Returns 0 for good, 1024 for a sense key of NOT_READY, or a negative * errno */ static int do_ssu(int pt_fd, int id, bool start) { int slen, res, cat; struct sg_pt_base * ptp = NULL; unsigned char ssuCmdBlk [SSU_CMD_LEN] = {0x1b, 0x0, 0x0, 0x0, 0x0, 0x0}; unsigned char sense_buffer[64]; if (start) ssuCmdBlk[4] |= 0x1; ptp = construct_scsi_pt_obj(); set_scsi_pt_cdb(ptp, ssuCmdBlk, sizeof(ssuCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); res = do_scsi_pt(ptp, pt_fd, 40 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "START STOP UNIT do_scsi_pt() submission error, " "id=%d\n", id); } res = pt_err(res); goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { slen = get_scsi_pt_sense_len(ptp); if ((SCSI_PT_RESULT_SENSE == cat) && (NOT_READY == sg_err_category_sense(sense_buffer, slen))) { res = 1024; goto err; } { lock_guard lg(console_mutex); fprintf(stderr, "START STOP UNIT do_scsi_pt() category problem, " "id=%d\n", id); } res = pt_cat_no_good(cat, ptp, sense_buffer); goto err; } res = 0; err: if (ptp) destruct_scsi_pt_obj(ptp); return res; } static void work_thread(const char * dev_name, int id, int num, bool share, int pt_fd, int nonblock, int oexcl, bool ready_after) { unsigned int thr_even_notreadys = 0; unsigned int thr_odd_notreadys = 0; unsigned int thr_ebusy_count = 0; int k; int res = 0; bool started = true; char ebuff[EBUFF_SZ]; { lock_guard lg(console_mutex); cerr << "Enter work_thread id=" << id << " num=" << num << " share=" << share << endl; } if (! share) { int open_flags = O_RDWR; if (nonblock) open_flags |= O_NONBLOCK; if (oexcl) open_flags |= O_EXCL; while (((pt_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == pt_fd)) { ++thr_ebusy_count; this_thread::yield(); // give other threads a chance } if (pt_fd < 0) { snprintf(ebuff, EBUFF_SZ, "work_thread id=%d: error opening: %s", id, dev_name); perror(ebuff); return; } if (thr_ebusy_count) { lock_guard lg(count_mutex); ebusy_count += thr_ebusy_count; } } for (k = 0; k < num; ++k) { if (0 == (id % 2)) { res = do_tur(pt_fd, id); if (1024 == res) { ++thr_even_notreadys; res = 0; } } else { started = (0 == (k % 2)); res = do_ssu(pt_fd, id, started); if (1024 == res) { ++thr_odd_notreadys; res = 0; } } if (res) break; if (ready_after && (! started)) do_ssu(pt_fd, id, true); } if (! share) scsi_pt_close_device(pt_fd); { lock_guard lg(count_mutex); even_notreadys += thr_even_notreadys; odd_notreadys += thr_odd_notreadys; } { lock_guard lg(console_mutex); if (k < num) cerr << "thread id=" << id << " FAILed at iteration: " << k << " [negated errno: " << res << "]\n"; else cerr << "thread id=" << id << " normal exit" << '\n'; } } int main(int argc, char * argv[]) { int k; int pt_fd = -1; int oexcl = 0; int nonblock = 0; int num_per_thread = DEF_NUM_PER_THREAD; bool ready_after = false; bool share = false; int num_threads = DEF_NUM_THREADS; char * dev_name = NULL; char ebuff[EBUFF_SZ]; for (k = 1; k < argc; ++k) { if (0 == memcmp("-e", argv[k], 2)) ++oexcl; else if (0 == memcmp("-h", argv[k], 2)) { usage(); return 0; } else if (0 == memcmp("-n", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_per_thread = atoi(argv[k]); else break; } else if (0 == memcmp("-N", argv[k], 2)) ++nonblock; else if (0 == memcmp("-R", argv[k], 2)) ready_after = true; else if (0 == memcmp("-s", argv[k], 2)) share = true; else if (0 == memcmp("-t", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_threads = atoi(argv[k]); else break; } else if (0 == memcmp("-V", argv[k], 2)) { printf("%s version: %s\n", util_name, version_str); return 0; } else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); dev_name = NULL; break; } else if (! dev_name) dev_name = argv[k]; else { printf("too many arguments\n"); dev_name = 0; break; } } if (0 == dev_name) { usage(); return 1; } try { if (share) { int open_flags = O_RDWR; if (nonblock) open_flags |= O_NONBLOCK; if (oexcl) open_flags |= O_EXCL; while (((pt_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == pt_fd)) { ++ebusy_count; sleep(0); // process yield ?? } if (pt_fd < 0) { snprintf(ebuff, EBUFF_SZ, "main: error opening: %s", dev_name); perror(ebuff); return 1; } } vector vt; for (k = 0; k < num_threads; ++k) { thread * tp = new thread {work_thread, dev_name, k, num_per_thread, share, pt_fd, nonblock, oexcl, ready_after}; vt.push_back(tp); } for (k = 0; k < (int)vt.size(); ++k) vt[k]->join(); for (k = 0; k < (int)vt.size(); ++k) delete vt[k]; if (share) scsi_pt_close_device(pt_fd); cout << "Expected not_readys on TEST UNIT READY: " << even_notreadys << endl; cout << "UNEXPECTED not_readys on START STOP UNIT: " << odd_notreadys << endl; if (ebusy_count) cout << "Number of EBUSYs (on open): " << ebusy_count << endl; } catch(system_error& e) { cerr << "got a system_error exception: " << e.what() << '\n'; auto ec = e.code(); cerr << "category: " << ec.category().name() << '\n'; cerr << "value: " << ec.value() << '\n'; cerr << "message: " << ec.message() << '\n'; cerr << "\nNote: if g++ may need '-pthread' or similar in " "compile/link line" << '\n'; } catch(...) { cerr << "got another exception: " << '\n'; } return 0; } sg3_utils-1.40/examples/sg_tst_excl2.cpp0000664000175000017500000004552312400160337017277 0ustar douggdougg/* * Copyright (c) 2013-2014 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pt.h" static const char * version_str = "1.07 20140828"; static const char * util_name = "sg_tst_excl2"; /* This is a test program for checking O_EXCL on open() works. It uses * multiple threads and can be run as multiple processes and attempts * to "break" O_EXCL. The strategy is to open a device O_EXCL|O_NONBLOCK * and do a double increment on a LB then close it. Prior to the first * increment, the value is checked for even or odd. Assuming the count * starts as an even (typically 0) then it should remain even. Odd instances * are counted and reported at the end of the program, after all threads * have completed. * * This is C++ code with some things from C++11 (e.g. threads) and was * only just able to compile (when some things were reverted) with gcc/g++ * version 4.7.3 found in Ubuntu 13.04 . C++11 "feature complete" support * was not available until g++ version 4.8.1 and that is only currently * found in Fedora 19 . * * The build uses various object files from the /lib directory * which is assumed to be a sibling of this examples directory. Those * object files in the lib directory can be built with: * cd ; ./configure ; cd lib; make * Then to build sg_tst_excl2 concatenate the next 3 lines: * g++ -Wall -std=c++11 -pthread -I ../include ../lib/sg_lib.o * ../lib/sg_lib_data.o ../lib/sg_pt_linux.o -o sg_tst_excl2 * sg_tst_excl2.cpp * Alternatively use 'make -f Makefile.cplus sg_tst_excl2' * * BEWARE: this utility modifies a logical block (default LBA 1000) on the * given device. * * Test breaks sg driver in lk 3.10.4 but works with proposed fix so should * work soon thereafter. Works on standard block driver (e.g. /dev/sdc) in * lk 3.10.4 . Fails on bsg driver in lk 3.10.4 because it ignores the * O_EXCL flag (and that is unlikely to change). * */ using namespace std; using namespace std::chrono; #define DEF_NUM_PER_THREAD 200 #define DEF_NUM_THREADS 4 #define DEF_WAIT_MS 0 /* 0: yield; -1: don't wait; -2: sleep(0) */ #define DEF_LBA 1000 #define EBUFF_SZ 256 static mutex odd_count_mutex; static mutex console_mutex; static unsigned int odd_count; static unsigned int ebusy_count; static void usage(void) { printf("Usage: %s [-b] [-f] [-h] [-l ] [-n ] " "[-t ]\n" " [-V] [-w ] [-x] " "\n", util_name); printf(" where\n"); printf(" -b block on open (def: O_NONBLOCK)\n"); printf(" -f force: any SCSI disk (def: only " "scsi_debug)\n"); printf(" WARNING: written to\n"); printf(" -h print this usage message then exit\n"); printf(" -l logical block to increment (def: %u)\n", DEF_LBA); printf(" -n number of loops per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -t number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" -V print version number then exit\n"); printf(" -w >0: sleep_for(); =0: " "yield(); -1: no\n" " wait; -2: sleep(0) (def: %d)\n", DEF_WAIT_MS); printf(" -x don't use O_EXCL on first thread " "(def: use\n" " O_EXCL on all threads)\n\n"); printf("Test O_EXCL open flag with pass-through drivers. Each " "open/close cycle with\nthe O_EXCL flag does a double increment " "on lba (using its first 4 bytes).\n"); } /* Assumed a lock (mutex) held when pt_err() is called */ static int pt_err(int res) { if (res < 0) fprintf(stderr, " pass through os error: %s\n", safe_strerror(-res)); else if (SCSI_PT_DO_BAD_PARAMS == res) fprintf(stderr, " bad pass through setup\n"); else if (SCSI_PT_DO_TIMEOUT == res) fprintf(stderr, " pass through timeout\n"); else fprintf(stderr, " do_scsi_pt error=%d\n", res); return -1; } /* Assumed a lock (mutex) held when pt_cat_no_good() is called */ static int pt_cat_no_good(int cat, struct sg_pt_base * ptp, const unsigned char * sbp) { int slen; char b[256]; const int bl = (int)sizeof(b); switch (cat) { case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ sg_get_scsi_status_str(get_scsi_pt_status_response(ptp), bl, b); fprintf(stderr, " scsi status: %s\n", b); break; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptp); sg_get_sense_str("", sbp, slen, 1, bl, b); fprintf(stderr, "%s", b); break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptp, bl, b); fprintf(stderr, " transport: %s", b); break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptp, bl, b); fprintf(stderr, " os: %s", b); break; default: fprintf(stderr, " unknown pt result category (%d)\n", cat); break; } return -1; } #define READ16_REPLY_LEN 512 #define READ16_CMD_LEN 16 #define WRITE16_REPLY_LEN 512 #define WRITE16_CMD_LEN 16 /* Opens dev_name and spins if busy (i.e. gets EBUSY), sleeping for * wait_ms milliseconds if wait_ms is positive. Reads lba and treats the * first 4 bytes as an int (SCSI endian), increments it and writes it back. * Repeats so that happens twice. Then closes dev_name. If an error occurs * returns -1 else returns 0 if first int read is even otherwise returns 1. */ static int do_rd_inc_wr_twice(const char * dev_name, unsigned int lba, int block, int excl, int wait_ms, unsigned int & ebusys) { int k, sg_fd, res, cat; int odd = 0; unsigned int u = 0; struct sg_pt_base * ptp = NULL; unsigned char r16CmdBlk [READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char w16CmdBlk [WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char sense_buffer[64]; unsigned char lb[READ16_REPLY_LEN]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; r16CmdBlk[6] = w16CmdBlk[6] = (lba >> 24) & 0xff; r16CmdBlk[7] = w16CmdBlk[7] = (lba >> 16) & 0xff; r16CmdBlk[8] = w16CmdBlk[8] = (lba >> 8) & 0xff; r16CmdBlk[9] = w16CmdBlk[9] = lba & 0xff; if (! block) open_flags |= O_NONBLOCK; if (excl) open_flags |= O_EXCL; while (((sg_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == sg_fd)) { ++ebusys; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_rd_inc_wr_twice: error opening file: %s", dev_name); { lock_guard lg(console_mutex); perror(ebuff); } return -1; } ptp = construct_scsi_pt_obj(); for (k = 0; k < 2; ++k) { /* Prepare READ_16 command */ clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, r16CmdBlk, sizeof(r16CmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_in(ptp, lb, READ16_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "READ_16 do_scsi_pt() submission error\n"); res = pt_err(res); } goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { { lock_guard lg(console_mutex); fprintf(stderr, "READ_16 do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); } goto err; } u = (lb[0] << 24) + (lb[1] << 16) + (lb[2] << 8) + lb[3]; // Assuming u starts test as even (probably 0), expect it to stay even if (0 == k) odd = (1 == (u % 2)); ++u; lb[0] = (u >> 24) & 0xff; lb[1] = (u >> 16) & 0xff; lb[2] = (u >> 8) & 0xff; lb[3] = u & 0xff; if (wait_ms > 0) /* allow daylight for bad things ... */ this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? /* Prepare WRITE_16 command */ clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, w16CmdBlk, sizeof(w16CmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_out(ptp, lb, WRITE16_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "WRITE_16 do_scsi_pt() submission error\n"); res = pt_err(res); } goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { { lock_guard lg(console_mutex); fprintf(stderr, "WRITE_16 do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); } goto err; } } err: if (ptp) destruct_scsi_pt_obj(ptp); scsi_pt_close_device(sg_fd); return odd; } #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 /* Send INQUIRY and fetches response. If okay puts PRODUCT ID field * in b (up to m_blen bytes). Does not use O_EXCL flag. Returns 0 on success, * else -1 . */ static int do_inquiry_prod_id(const char * dev_name, int block, int wait_ms, unsigned int & ebusys, char * b, int b_mlen) { int sg_fd, res, cat; struct sg_pt_base * ptp = NULL; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; unsigned char sense_buffer[64]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; /* since O_EXCL | O_RDONLY gives EPERM */ if (! block) open_flags |= O_NONBLOCK; while (((sg_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == sg_fd)) { ++ebusys; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_inquiry_prod_id: error opening file: %s", dev_name); perror(ebuff); return -1; } /* Prepare INQUIRY command */ ptp = construct_scsi_pt_obj(); clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_in(ptp, inqBuff, INQ_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "INQUIRY do_scsi_pt() submission error\n"); res = pt_err(res); } goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { { lock_guard lg(console_mutex); fprintf(stderr, "INQUIRY do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); } goto err; } /* Good, so fetch Product ID from response, copy to 'b' */ if (b_mlen > 0) { if (b_mlen > 16) { memcpy(b, inqBuff + 16, 16); b[16] = '\0'; } else { memcpy(b, inqBuff + 16, b_mlen - 1); b[b_mlen - 1] = '\0'; } } err: if (ptp) destruct_scsi_pt_obj(ptp); close(sg_fd); return 0; } static void work_thread(const char * dev_name, unsigned int lba, int id, int block, int excl, int num, int wait_ms) { unsigned int thr_odd_count = 0; unsigned int thr_ebusy_count = 0; int k, res; { lock_guard lg(console_mutex); cerr << "Enter work_thread id=" << id << " excl=" << excl << " block=" << block << endl; } for (k = 0; k < num; ++k) { res = do_rd_inc_wr_twice(dev_name, lba, block, excl, wait_ms, thr_ebusy_count); if (res < 0) break; if (res) ++thr_odd_count; } { lock_guard lg(console_mutex); if (k < num) cerr << "thread id=" << id << " FAILed at iteration: " << k << '\n'; else cerr << "thread id=" << id << " normal exit" << '\n'; } { lock_guard lg(odd_count_mutex); odd_count += thr_odd_count; ebusy_count += thr_ebusy_count; } } int main(int argc, char * argv[]) { int k, res; int block = 0; int force = 0; unsigned int lba = DEF_LBA; int num_per_thread = DEF_NUM_PER_THREAD; int num_threads = DEF_NUM_THREADS; int wait_ms = DEF_WAIT_MS; int exclude_o_excl = 0; char * dev_name = NULL; char b[64]; for (k = 1; k < argc; ++k) { if (0 == memcmp("-b", argv[k], 2)) ++block; else if (0 == memcmp("-f", argv[k], 2)) ++force; else if (0 == memcmp("-h", argv[k], 2)) { usage(); return 0; } else if (0 == memcmp("-l", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) lba = (unsigned int)atoi(argv[k]); else break; } else if (0 == memcmp("-n", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_per_thread = atoi(argv[k]); else break; } else if (0 == memcmp("-t", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_threads = atoi(argv[k]); else break; } else if (0 == memcmp("-V", argv[k], 2)) { printf("%s version: %s\n", util_name, version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) { ++k; if ((k < argc) && (isdigit(*argv[k]) || ('-' == *argv[k]))) { if ('-' == *argv[k]) wait_ms = - atoi(argv[k] + 1); else wait_ms = atoi(argv[k]); } else break; } else if (0 == memcmp("-x", argv[k], 2)) ++exclude_o_excl; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); dev_name = NULL; break; } else if (! dev_name) dev_name = argv[k]; else { printf("too many arguments\n"); dev_name = 0; break; } } if (0 == dev_name) { usage(); return 1; } try { if (! force) { res = do_inquiry_prod_id(dev_name, block, wait_ms, ebusy_count, b, sizeof(b)); if (res) { fprintf(stderr, "INQUIRY failed on %s\n", dev_name); return 1; } // For safety, since written to, only permit scsi_debug // devices. Bypass this with '-f' option. if (0 != memcmp("scsi_debug", b, 10)) { fprintf(stderr, "Since this utility writes to LBA %d, only " "devices with scsi_debug\nproduct ID accepted.\n", lba); return 2; } } vector vt; for (k = 0; k < num_threads; ++k) { int excl = ((0 == k) && exclude_o_excl) ? 0 : 1; thread * tp = new thread {work_thread, dev_name, lba, k, block, excl, num_per_thread, wait_ms}; vt.push_back(tp); } for (k = 0; k < (int)vt.size(); ++k) vt[k]->join(); for (k = 0; k < (int)vt.size(); ++k) delete vt[k]; cout << "Expecting odd count of 0, got " << odd_count << endl; cout << "Number of EBUSYs: " << ebusy_count << endl; } catch(system_error& e) { cerr << "got a system_error exception: " << e.what() << '\n'; auto ec = e.code(); cerr << "category: " << ec.category().name() << '\n'; cerr << "value: " << ec.value() << '\n'; cerr << "message: " << ec.message() << '\n'; cerr << "\nNote: if g++ may need '-pthread' or similar in " "compile/link line" << '\n'; } catch(...) { cerr << "got another exception: " << '\n'; } return 0; } sg3_utils-1.40/examples/sgq_dd.c0000664000175000017500000011007512374750507015611 0ustar douggdougg#define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include typedef unsigned char u_char; /* horrible, for scsi.h */ #include "sg_lib.h" #include "sg_io_linux.h" /* A utility program for the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 1999-2002 D. Gilbert and P. Allworth * 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. This program is a specialization of the Unix "dd" command in which one or both of the given files is a scsi generic device or a raw device. A block size ('bs') is assumed to be 512 if not given. This program complains if 'ibs' or 'obs' are given with some other value than 'bs'. If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is not given or 'of=-' then stdout assumed. Multipliers: 'c','C' *1 'b','B' *512 'k' *1024 'K' *1000 'm' *(1024^2) 'M' *(1000^2) 'g' *(1024^3) 'G' *(1000^3) A non-standard argument "bpt" (blocks per transfer) is added to control the maximum number of blocks in each transfer. The default value is 128. For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16KB in this case) are transferred to or from the sg device in a single SCSI command. This version should compile with Linux sg drivers with version numbers >= 30000 . This version uses queuing within the Linux sg driver. */ static char * version_str = "0.57 20140819"; /* resurrected from "0.55 20020509" */ #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 /* #define SG_DEBUG */ #define SENSE_BUFF_LEN 32 /* Arbitrary, could be larger */ #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #define S_RW_LEN 10 /* Use SCSI READ(10) and WRITE(10) */ #define SGP_READ10 0x28 #define SGP_WRITE10 0x2a #define DEF_NUM_THREADS 4 /* actually degree of concurrency */ #define MAX_NUM_THREADS 32 #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikey value */ #endif #define FT_OTHER 0 /* filetype other than sg or raw device */ #define FT_SG 1 /* filetype is sg char device */ #define FT_RAW 2 /* filetype is raw char device */ #define QS_IDLE 0 /* ready to start a copy cycle */ #define QS_IN_STARTED 1 /* commenced read */ #define QS_IN_FINISHED 2 /* finished read, ready for write */ #define QS_OUT_STARTED 3 /* commenced write */ #define QS_IN_POLL 11 #define QS_OUT_POLL 12 #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 512 struct request_element; typedef struct request_collection { /* one instance visible to all threads */ int infd; int skip; int in_type; int in_scsi_type; int in_blk; /* next block address to read */ int in_count; /* blocks remaining for next read */ int in_done_count; /* count of completed in blocks */ int in_partial; int outfd; int seek; int out_type; int out_scsi_type; int out_blk; /* next block address to write */ int out_count; /* blocks remaining for next write */ int out_done_count; /* count of completed out blocks */ int out_partial; int bs; int bpt; int dio; int dio_incomplete; int sum_of_resids; int coe; int debug; int num_rq_elems; struct request_element * req_arr; } Rq_coll; typedef struct request_element { /* one instance per worker thread */ int qstate; /* "QS" state */ int infd; int outfd; int wr; int blk; int num_blks; unsigned char * buffp; unsigned char * alloc_bp; sg_io_hdr_t io_hdr; unsigned char cmd[S_RW_LEN]; unsigned char sb[SENSE_BUFF_LEN]; int bs; int dio; int dio_incomplete; int resid; int in_scsi_type; int out_scsi_type; int debug; } Rq_elem; static Rq_coll rcoll; static struct pollfd in_pollfd_arr[MAX_NUM_THREADS]; static struct pollfd out_pollfd_arr[MAX_NUM_THREADS]; static int dd_count = -1; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; static int sg_finish_io(int wr, Rq_elem * rep); static void install_handler (int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } static void print_stats() { int infull, outfull; if (0 != rcoll.out_count) fprintf(stderr, " remaining block count=%d\n", rcoll.out_count); infull = dd_count - rcoll.in_done_count - rcoll.in_partial; fprintf(stderr, "%d+%d records in\n", infull, rcoll.in_partial); outfull = dd_count - rcoll.out_done_count - rcoll.out_partial; fprintf(stderr, "%d+%d records out\n", outfull, rcoll.out_partial); } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig, &sigact, NULL); fprintf(stderr, "Interrupted by signal,"); print_stats (); kill (getpid (), sig); } static void siginfo_handler(int sig) { fprintf(stderr, "Progress report, continuing ...\n"); print_stats (); if (sig) { } /* suppress unused warning */ } static int dd_filetype(const char * filename) { struct stat st; if (stat(filename, &st) < 0) return FT_OTHER; if (S_ISCHR(st.st_mode)) { if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; else if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; } return FT_OTHER; } static void usage() { fprintf(stderr, "Usage: " "sgq_dd [if=] [skip=] [of=] [seek=] " "[bs=]\n" " [bpt=] [count=] [dio=0|1] [thr=] " "[coe=0|1] [gen=]\n" " [time=0|1] [deb=] [--version]\n" " usually either 'if' or 'of' is a sg or raw device\n" " 'bpt' is blocks_per_transfer (default is 128)\n" " 'dio' is direct IO, 1->attempt, 0->indirect IO (def)\n" " 'thr' is number of queues, must be > 0, default 4, max 32\n"); fprintf(stderr, " 'coe' continue on sg error, 0->exit (def), " "1->zero + continue\n" " 'time' 0->no timing(def), 1->time plus calculate throughput\n" " 'gen' 0-> 1 file is special(def), 1-> any files allowed\n" " 'deb' is debug, 0->none (def), > 0->varying degrees of debug\n"); } /* Returns -1 for error, 0 for nothing found, QS_IN_POLL or QS_OUT_POLL */ static int do_poll(Rq_coll * clp, int timeout, int * req_indexp) { int k, res; if (FT_SG == clp->out_type) { while (((res = poll(out_pollfd_arr, clp->num_rq_elems, timeout)) < 0) && (EINTR == errno)) ; if (res < 0) { perror("poll error on output fds"); return -1; } else if (res > 0) { for (k = 0; k < clp->num_rq_elems; ++k) { if (out_pollfd_arr[k].revents & POLLIN) { if (req_indexp) *req_indexp = k; return QS_OUT_POLL; } } } } if (FT_SG == clp->in_type) { while (((res = poll(in_pollfd_arr, clp->num_rq_elems, timeout)) < 0) && (EINTR == errno)) ; if (res < 0) { perror("poll error on input fds"); return -1; } else if (res > 0) { for (k = 0; k < clp->num_rq_elems; ++k) { if (in_pollfd_arr[k].revents & POLLIN) { if (req_indexp) *req_indexp = k; return QS_IN_POLL; } } } } return 0; } /* Return of 0 -> success, -1 -> failure, 2 -> try again */ static int read_capacity(int sg_fd, int * num_sect, int * sect_sz) { int res; unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char rcBuff[64]; unsigned char sense_b[64]; sg_io_hdr_t io_hdr; memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rcCmdBlk); io_hdr.mx_sb_len = sizeof(sense_b); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = sizeof(rcBuff); io_hdr.dxferp = rcBuff; io_hdr.cmdp = rcCmdBlk; io_hdr.sbp = sense_b; io_hdr.timeout = DEF_TIMEOUT; if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("read_capacity (SG_IO) error"); return -1; } res = sg_err_category3(&io_hdr); if (SG_LIB_CAT_UNIT_ATTENTION == res) return 2; /* probably have another go ... */ else if (SG_LIB_CAT_CLEAN != res) { sg_chk_n_print3("read capacity", &io_hdr, 1); return -1; } *num_sect = 1 + ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]); *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | (rcBuff[6] << 8) | rcBuff[7]; #ifdef SG_DEBUG fprintf(stderr, "number of sectors=%d, sector size=%d\n", *num_sect, *sect_sz); #endif return 0; } /* 0 -> ok, 1 -> short read, -1 -> error */ static int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; int stop_after_write = 0; rep->qstate = QS_IN_STARTED; if (rep->debug > 8) fprintf(stderr, "normal_in_operation: start blk=%d num_blks=%d\n", rep->blk, rep->num_blks); while (((res = read(rep->infd, rep->buffp, blocks * rep->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { fprintf(stderr, "sgq_dd: reading, in_blk=%d, errno=%d\n", rep->blk, errno); return -1; } if (res < blocks * rep->bs) { int o_blocks = blocks; stop_after_write = 1; blocks = res / rep->bs; if ((res % rep->bs) > 0) { blocks++; clp->in_partial++; } /* Reverse out + re-apply blocks on clp */ clp->in_blk -= o_blocks; clp->in_count += o_blocks; rep->num_blks = blocks; clp->in_blk += blocks; clp->in_count -= blocks; } clp->in_done_count -= blocks; rep->qstate = QS_IN_FINISHED; return stop_after_write; } /* 0 -> ok, -1 -> error */ static int normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; rep->qstate = QS_OUT_STARTED; if (rep->debug > 8) fprintf(stderr, "normal_out_operation: start blk=%d num_blks=%d\n", rep->blk, rep->num_blks); while (((res = write(rep->outfd, rep->buffp, rep->num_blks * rep->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { fprintf(stderr, "sgq_dd: output, out_blk=%d, errno=%d\n", rep->blk, errno); return -1; } if (res < blocks * rep->bs) { blocks = res / rep->bs; if ((res % rep->bs) > 0) { blocks++; clp->out_partial++; } rep->num_blks = blocks; } clp->out_done_count -= blocks; rep->qstate = QS_IDLE; return 0; } /* Returns 1 for retryable, 0 for ok, -ve for error */ static int sg_fin_in_operation(Rq_coll * clp, Rq_elem * rep) { int res; rep->qstate = QS_IN_FINISHED; res = sg_finish_io(rep->wr, rep); if (res < 0) { if (clp->coe) { memset(rep->buffp, 0, rep->num_blks * rep->bs); fprintf(stderr, ">> substituted zeros for in blk=%d for " "%d bytes\n", rep->blk, rep->num_blks * rep->bs); res = 0; } else { fprintf(stderr, "error finishing sg in command\n"); return res; } } if (0 == res) { /* looks good, going to return */ if (rep->dio_incomplete || rep->resid) { clp->dio_incomplete += rep->dio_incomplete; clp->sum_of_resids += rep->resid; } clp->in_done_count -= rep->num_blks; } return res; } /* Returns 1 for retryable, 0 for ok, -ve for error */ static int sg_fin_out_operation(Rq_coll * clp, Rq_elem * rep) { int res; rep->qstate = QS_IDLE; res = sg_finish_io(rep->wr, rep); if (res < 0) { if (clp->coe) { fprintf(stderr, ">> ignored error for out blk=%d for " "%d bytes\n", rep->blk, rep->num_blks * rep->bs); res = 0; } else { fprintf(stderr, "error finishing sg out command\n"); return res; } } if (0 == res) { if (rep->dio_incomplete || rep->resid) { clp->dio_incomplete += rep->dio_incomplete; clp->sum_of_resids += rep->resid; } clp->out_done_count -= rep->num_blks; } return res; } static int sg_start_io(Rq_elem * rep) { sg_io_hdr_t * hp = &rep->io_hdr; int res; rep->qstate = rep->wr ? QS_OUT_STARTED : QS_IN_STARTED; memset(rep->cmd, 0, sizeof(rep->cmd)); rep->cmd[0] = rep->wr ? SGP_WRITE10 : SGP_READ10; rep->cmd[2] = (unsigned char)((rep->blk >> 24) & 0xFF); rep->cmd[3] = (unsigned char)((rep->blk >> 16) & 0xFF); rep->cmd[4] = (unsigned char)((rep->blk >> 8) & 0xFF); rep->cmd[5] = (unsigned char)(rep->blk & 0xFF); rep->cmd[7] = (unsigned char)((rep->num_blks >> 8) & 0xff); rep->cmd[8] = (unsigned char)(rep->num_blks & 0xff); memset(hp, 0, sizeof(sg_io_hdr_t)); hp->interface_id = 'S'; hp->cmd_len = sizeof(rep->cmd); hp->cmdp = rep->cmd; hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; hp->dxfer_len = rep->bs * rep->num_blks; hp->dxferp = rep->buffp; hp->mx_sb_len = sizeof(rep->sb); hp->sbp = rep->sb; hp->timeout = DEF_TIMEOUT; hp->usr_ptr = rep; hp->pack_id = rep->blk; if (rep->dio) hp->flags |= SG_FLAG_DIRECT_IO; if (rep->debug > 8) { fprintf(stderr, "sg_start_io: SCSI %s, blk=%d num_blks=%d\n", rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks); sg_print_command(hp->cmdp); fprintf(stderr, " len=%d, dxfrp=%p, cmd_len=%d\n", hp->dxfer_len, hp->dxferp, hp->cmd_len); } while (((res = write(rep->wr ? rep->outfd : rep->infd, hp, sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return 1; return res; } return 0; } /* -1 -> unrecoverable error, 0 -> successful, 1 -> try again */ static int sg_finish_io(int wr, Rq_elem * rep) { int res; sg_io_hdr_t io_hdr; sg_io_hdr_t * hp; #if 0 static int testing = 0; /* thread dubious! */ #endif memset(&io_hdr, 0 , sizeof(sg_io_hdr_t)); /* FORCE_PACK_ID active set only read packet with matching pack_id */ io_hdr.interface_id = 'S'; io_hdr.dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; io_hdr.pack_id = rep->blk; while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr, sizeof(sg_io_hdr_t))) < 0) && (EINTR == errno)) ; if (res < 0) { perror("finishing io on sg device, error"); return -1; } if (rep != (Rq_elem *)io_hdr.usr_ptr) { fprintf(stderr, "sg_finish_io: bad usr_ptr, request-response mismatch\n"); exit(1); } memcpy(&rep->io_hdr, &io_hdr, sizeof(sg_io_hdr_t)); hp = &rep->io_hdr; switch (sg_err_category3(hp)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: fprintf(stderr, "Recovered error on block=%d, num=%d\n", rep->blk, rep->num_blks); break; case SG_LIB_CAT_UNIT_ATTENTION: return 1; default: { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s blk=%d", rep->wr ? "writing": "reading", rep->blk); sg_chk_n_print3(ebuff, hp, 1); return -1; } } #if 0 if (0 == (++testing % 100)) return -1; #endif if (rep->dio && ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) rep->dio_incomplete = 1; /* count dios done as indirect IO */ else rep->dio_incomplete = 0; rep->resid = hp->resid; if (rep->debug > 8) fprintf(stderr, "sg_finish_io: completed %s, blk=%d\n", wr ? "WRITE" : "READ", rep->blk); return 0; } /* Returns scsi_type or -1 for error */ static int sg_prepare(int fd, int sz) { int res, t; struct sg_scsi_id info; res = ioctl(fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { fprintf(stderr, "sgq_dd: sg driver prior to 3.x.y\n"); return -1; } res = ioctl(fd, SG_SET_RESERVED_SIZE, &sz); if (res < 0) perror("sgq_dd: SG_SET_RESERVED_SIZE error"); #if 0 t = 1; res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); if (res < 0) perror("sgq_dd: SG_SET_FORCE_PACK_ID error"); #endif res = ioctl(fd, SG_GET_SCSI_ID, &info); if (res < 0) { perror("sgq_dd: SG_SET_SCSI_ID error"); return -1; } else return info.scsi_type; } /* Return 0 for ok, anything else for errors */ static int prepare_rq_elems(Rq_coll * clp, const char * inf, const char * outf) { int k; Rq_elem * rep; size_t psz; char ebuff[EBUFF_SZ]; int sz = clp->bpt * clp->bs; int scsi_type; clp->req_arr = malloc(sizeof(Rq_elem) * clp->num_rq_elems); if (NULL == clp->req_arr) return 1; for (k = 0; k < clp->num_rq_elems; ++k) { rep = &clp->req_arr[k]; memset(rep, 0, sizeof(Rq_elem)); psz = getpagesize(); if (NULL == (rep->alloc_bp = malloc(sz + psz))) return 1; rep->buffp = (unsigned char *) (((unsigned long)rep->alloc_bp + psz - 1) & (~(psz - 1))); rep->qstate = QS_IDLE; rep->bs = clp->bs; rep->dio = clp->dio; rep->debug = clp->debug; rep->out_scsi_type = clp->out_scsi_type; if (FT_SG == clp->in_type) { if (0 == k) rep->infd = clp->infd; else { if ((rep->infd = open(inf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg reading", inf); perror(ebuff); return 1; } } in_pollfd_arr[k].fd = rep->infd; in_pollfd_arr[k].events = POLLIN; if ((scsi_type = sg_prepare(rep->infd, sz)) < 0) return 1; if (0 == k) clp->in_scsi_type = scsi_type; rep->in_scsi_type = clp->in_scsi_type; } else rep->infd = clp->infd; if (FT_SG == clp->out_type) { if (0 == k) rep->outfd = clp->outfd; else { if ((rep->outfd = open(outf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg writing", outf); perror(ebuff); return 1; } } out_pollfd_arr[k].fd = rep->outfd; out_pollfd_arr[k].events = POLLIN; if ((scsi_type = sg_prepare(rep->outfd, sz)) < 0) return 1; if (0 == k) clp->out_scsi_type = scsi_type; rep->out_scsi_type = clp->out_scsi_type; } else rep->outfd = clp->outfd; } return 0; } /* Returns a "QS" code and req index, or QS_IDLE and position of first idle (-1 if no idle position). Returns -1 on poll error. */ static int decider(Rq_coll * clp, int first_xfer, int * req_indexp) { int k, res; Rq_elem * rep; int first_idle_index = -1; int lowest_blk_index = -1; int times; int try_poll = 0; int lowest_blk = INT_MAX; times = first_xfer ? 1 : clp->num_rq_elems; for (k = 0; k < times; ++k) { rep = &clp->req_arr[k]; if ((QS_IN_STARTED == rep->qstate) || (QS_OUT_STARTED == rep->qstate)) try_poll = 1; else if ((QS_IN_FINISHED == rep->qstate) && (rep->blk < lowest_blk)) { lowest_blk = rep->blk; lowest_blk_index = k; } else if ((QS_IDLE == rep->qstate) && (first_idle_index < 0)) first_idle_index = k; } if (try_poll) { res = do_poll(clp, 0, req_indexp); if (0 != res) return res; } if (lowest_blk_index >= 0) { if (req_indexp) *req_indexp = lowest_blk_index; return QS_IN_FINISHED; } #if 0 if (try_poll) { res = do_poll(clp, 2, req_indexp); if (0 != res) return res; } #endif if (req_indexp) *req_indexp = first_idle_index; return QS_IDLE; } int main(int argc, char * argv[]) { int skip = 0; int seek = 0; int ibs = 0; int obs = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; int res, k; int in_num_sect = 0; int out_num_sect = 0; int num_threads = DEF_NUM_THREADS; int gen = 0; int do_time = 0; int in_sect_sz, out_sect_sz, first_xfer, qstate, req_index, seek_skip; int blocks, stop_after_write, terminate; char ebuff[EBUFF_SZ]; Rq_elem * rep; struct timeval start_tm, end_tm; memset(&rcoll, 0, sizeof(Rq_coll)); rcoll.bpt = DEF_BLOCKS_PER_TRANSFER; rcoll.in_type = FT_OTHER; rcoll.out_type = FT_OTHER; inf[0] = '\0'; outf[0] = '\0'; if (argc < 2) { usage(); return 1; } for(k = 1; k < argc; k++) { if (argv[k]) strncpy(str, argv[k], STR_SZ); else continue; for(key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (strcmp(key,"if") == 0) strncpy(inf, buf, INOUTF_SZ); else if (strcmp(key,"of") == 0) strncpy(outf, buf, INOUTF_SZ); else if (0 == strcmp(key,"ibs")) ibs = sg_get_num(buf); else if (0 == strcmp(key,"obs")) obs = sg_get_num(buf); else if (0 == strcmp(key,"bs")) rcoll.bs = sg_get_num(buf); else if (0 == strcmp(key,"bpt")) rcoll.bpt = sg_get_num(buf); else if (0 == strcmp(key,"skip")) skip = sg_get_num(buf); else if (0 == strcmp(key,"seek")) seek = sg_get_num(buf); else if (0 == strcmp(key,"count")) dd_count = sg_get_num(buf); else if (0 == strcmp(key,"dio")) rcoll.dio = sg_get_num(buf); else if (0 == strcmp(key,"thr")) num_threads = sg_get_num(buf); else if (0 == strcmp(key,"coe")) rcoll.coe = sg_get_num(buf); else if (0 == strcmp(key,"gen")) gen = sg_get_num(buf); else if (0 == strncmp(key,"deb", 3)) rcoll.debug = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "--vers", 6)) { fprintf(stderr, "sgq_dd for sg version 3 driver: %s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized argument '%s'\n", key); usage(); return 1; } } if (rcoll.bs <= 0) { rcoll.bs = DEF_BLOCK_SIZE; fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", rcoll.bs); } if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) { fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return 1; } if ((skip < 0) || (seek < 0)) { fprintf(stderr, "skip and seek cannot be negative\n"); return 1; } if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { fprintf(stderr, "too few or too many threads requested\n"); usage(); return 1; } if (rcoll.debug) fprintf(stderr, "sgq_dd: if=%s skip=%d of=%s seek=%d count=%d\n", inf, skip, outf, seek, dd_count); install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); rcoll.infd = STDIN_FILENO; rcoll.outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { rcoll.in_type = dd_filetype(inf); if (FT_SG == rcoll.in_type) { if ((rcoll.infd = open(inf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg reading", inf); perror(ebuff); return 1; } } if (FT_SG != rcoll.in_type) { if ((rcoll.infd = open(inf, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for reading", inf); perror(ebuff); return 1; } else if (skip > 0) { loff_t offset = skip; offset *= rcoll.bs; /* could exceed 32 here! */ if (lseek(rcoll.infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: couldn't skip to required position on %s", inf); perror(ebuff); return 1; } } } } if (outf[0] && ('-' != outf[0])) { rcoll.out_type = dd_filetype(outf); if (FT_SG == rcoll.out_type) { if ((rcoll.outfd = open(outf, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for sg writing", outf); perror(ebuff); return 1; } } else { if (FT_OTHER == rcoll.out_type) { if ((rcoll.outfd = open(outf, O_WRONLY | O_CREAT, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for writing", outf); perror(ebuff); return 1; } } else { if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: could not open %s for raw writing", outf); perror(ebuff); return 1; } } if (seek > 0) { loff_t offset = seek; offset *= rcoll.bs; /* could exceed 32 bits here! */ if (lseek(rcoll.outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, "sgq_dd: couldn't seek to required position on %s", outf); perror(ebuff); return 1; } } } } if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) { fprintf(stderr, "Disallow both if and of to be stdin and stdout"); return 1; } if ((FT_OTHER == rcoll.in_type) && (FT_OTHER == rcoll.out_type) && !gen) { fprintf(stderr, "Either 'if' or 'of' must be a sg or raw device\n"); return 1; } if (0 == dd_count) return 0; else if (dd_count < 0) { if (FT_SG == rcoll.in_type) { res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(in), repeat\n"); res = read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); } if (0 != res) { fprintf(stderr, "Unable to read capacity on %s\n", inf); in_num_sect = -1; } else { if (in_num_sect > skip) in_num_sect -= skip; } } if (FT_SG == rcoll.out_type) { res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(out), " "repeat\n"); res = read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { fprintf(stderr, "Unable to read capacity on %s\n", outf); out_num_sect = -1; } else { if (out_num_sect > seek) out_num_sect -= seek; } } if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } if (rcoll.debug > 1) fprintf(stderr, "Start of loop, count=%d, in_num_sect=%d, " "out_num_sect=%d\n", dd_count, in_num_sect, out_num_sect); if (dd_count <= 0) { fprintf(stderr, "Couldn't calculate count, please give one\n"); return 1; } rcoll.in_count = dd_count; rcoll.in_done_count = dd_count; rcoll.skip = skip; rcoll.in_blk = skip; rcoll.out_count = dd_count; rcoll.out_done_count = dd_count; rcoll.seek = seek; rcoll.out_blk = seek; if ((FT_SG == rcoll.in_type) || (FT_SG == rcoll.out_type)) rcoll.num_rq_elems = num_threads; else rcoll.num_rq_elems = 1; if (prepare_rq_elems(&rcoll, inf, outf)) { fprintf(stderr, "Setup failure, perhaps no memory\n"); return 1; } first_xfer = 1; stop_after_write = 0; terminate = 0; seek_skip = rcoll.seek - rcoll.skip; if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } while (rcoll.out_done_count > 0) { /* >>>>>>>>> main loop */ req_index = -1; qstate = decider(&rcoll, first_xfer, &req_index); rep = (req_index < 0) ? NULL : (rcoll.req_arr + req_index); switch (qstate) { case QS_IDLE: if ((NULL == rep) || (rcoll.in_count <= 0)) { /* usleep(1000); */ /* do_poll(&rcoll, 10, NULL); */ /* do_poll(&rcoll, 0, NULL); */ break; } if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: non-sleeping QS_IDLE state, " "req_index=%d\n", req_index); if (first_xfer >= 2) first_xfer = 0; else if (1 == first_xfer) ++first_xfer; if (stop_after_write) { terminate = 1; break; } blocks = (rcoll.in_count > rcoll.bpt) ? rcoll.bpt : rcoll.in_count; rep->wr = 0; rep->blk = rcoll.in_blk; rep->num_blks = blocks; rcoll.in_blk += blocks; rcoll.in_count -= blocks; if (FT_SG == rcoll.in_type) { res = sg_start_io(rep); if (0 != res) { if (1 == res) fprintf(stderr, "Out of memory starting sg io\n"); terminate = 1; } } else { res = normal_in_operation(&rcoll, rep, blocks); if (res < 0) terminate = 1; else if (res > 0) stop_after_write = 1; } break; case QS_IN_FINISHED: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_IN_FINISHED, " "req_index=%d\n", req_index); if ((rep->blk + seek_skip) != rcoll.out_blk) { /* if write would be out of sequence then wait */ if (rcoll.debug > 4) fprintf(stderr, " sgq_dd: QS_IN_FINISHED, " "out of sequence\n"); usleep(200); break; } rep->wr = 1; rep->blk = rcoll.out_blk; blocks = rep->num_blks; rcoll.out_blk += blocks; rcoll.out_count -= blocks; if (FT_SG == rcoll.out_type) { res = sg_start_io(rep); if (0 != res) { if (1 == res) fprintf(stderr, "Out of memory starting sg io\n"); terminate = 1; } } else { if (normal_out_operation(&rcoll, rep, blocks) < 0) terminate = 1; } break; case QS_IN_POLL: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_IN_POLL, " "req_index=%d\n", req_index); res = sg_fin_in_operation(&rcoll, rep); if (res < 0) terminate = 1; else if (res > 1) { if (first_xfer) { /* only retry on first xfer */ if (0 != sg_start_io(rep)) terminate = 1; } else terminate = 1; } break; case QS_OUT_POLL: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is QS_OUT_POLL, " "req_index=%d\n", req_index); res = sg_fin_out_operation(&rcoll, rep); if (res < 0) terminate = 1; else if (res > 1) { if (first_xfer) { /* only retry on first xfer */ if (0 != sg_start_io(rep)) terminate = 1; } else terminate = 1; } break; default: if (rcoll.debug > 8) fprintf(stderr, " sgq_dd: state is ?????\n"); terminate = 1; break; } if (terminate) break; } /* >>>>>>>>>>>>> end of main loop */ if ((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)rcoll.bs * (dd_count - rcoll.out_done_count); printf("time to transfer data was %d.%06d secs", (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) printf(", %.2f MB/sec\n", b / (a * 1000000.0)); else printf("\n"); } if (STDIN_FILENO != rcoll.infd) close(rcoll.infd); if (STDOUT_FILENO != rcoll.outfd) close(rcoll.outfd); res = 0; if (0 != rcoll.out_count) { fprintf(stderr, ">>>> Some error occurred,\n"); res = 2; } print_stats(); if (rcoll.dio_incomplete) { int fd; char c; fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", rcoll.dio_incomplete); if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (rcoll.sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", rcoll.sum_of_resids); return res; } sg3_utils-1.40/examples/sg_sat_chk_power.c0000664000175000017500000002211012142450532017645 0ustar douggdougg/* * Copyright (c) 2006-2012 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program performs a ATA PASS-THROUGH (16) SCSI command in order to perform an ATA CHECK POWER MODE command. See http://www.t10.org SAT draft at time of writing: sat-r09.pdf Invocation: sg_sat_chk_power [-v] [-V] */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d #define ATA_CHECK_POWER_MODE 0xe5 #define EBUFF_SZ 256 static const char * version_str = "1.04 20120319"; #if 0 /* Returns length of decoded fixed format sense for SAT ATA pass-through * command, else returns 0. If returns 0 (expected sense data not found) * then '\0' placed in first byte of bp. */ static int sg_sat_decode_fixed_sense(const unsigned char * sp, int slen, char * bp, int max_blen, int verbose) { int n; if ((NULL == bp) || (NULL == sp) || (max_blen < 1) || (slen < 14)) return 0; bp[0] = '\0'; if ((0x70 != (0x7f & sp[0])) || (SPC_SK_RECOVERED_ERROR != (0xf & sp[2])) || (0 != sp[12]) || (ASCQ_ATA_PT_INFO_AVAILABLE != sp[13])) return 0; n = snprintf(bp, max_blen, "error=0x%x, status=0x%x, device=0x%x, " "sector_count(7:0)=0x%x%c\n", sp[3], sp[4], sp[5], sp[6], ((0x40 & sp[8]) ? '+' : ' ')); if (n >= max_blen) return max_blen - 1; n += snprintf(bp + n, max_blen - n, "extend=%d, log_index=0x%x, " "lba_high,mid,low(7:0)=0x%x,0x%x,0x%x%c\n", (!!(0x80 & sp[8])), (0xf & sp[8]), sp[9], sp[10], sp[11], ((0x20 & sp[8]) ? '+' : ' ')); if (n >= max_blen) return max_blen - 1; if (verbose) n += snprintf(bp + n, max_blen - n, " sector_count_upper_nonzero=" "%d, lba_upper_nonzero=%d\n", !!(0x40 & sp[8]), !!(0x20 & sp[8])); return (n >= max_blen) ? max_blen - 1 : n; } #endif int main(int argc, char * argv[]) { int sg_fd, k; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[64]; int verbose = 0; int extend = 0; int chk_cond = 1; /* set to 1 to read register(s) back */ int protocol = 3; /* non-dat data-in */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */ const unsigned char * ucp = NULL; for (k = 1; k < argc; ++k) { if (0 == strcmp(argv[k], "-v")) ++verbose; else if (0 == strcmp(argv[k], "-vv")) verbose += 2; else if (0 == strcmp(argv[k], "-vvv")) verbose += 3; else if (0 == strcmp(argv[k], "-V")) { fprintf(stderr, "version: %s\n", version_str); exit(0); } else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_sat_chk_power [-v] [-V] '\n"); return 1; } if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_sat_chk_power: error opening file: %s", file_name); perror(ebuff); return 1; } /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[14] = ATA_CHECK_POWER_MODE; aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; if (verbose) { fprintf(stderr, " ata pass through(16) cdb: "); for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k) fprintf(stderr, "%02x ", aptCmdBlk[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(aptCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.dxfer_len = 0; io_hdr.dxferp = NULL; io_hdr.cmdp = aptCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_sat_chk_power: SG_IO ioctl error"); close(sg_fd); return 1; } /* error processing: N.B. expect check condition, no sense ... !! */ switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: /* sat-r09 (latest) uses this sk */ case SG_LIB_CAT_NO_SENSE: /* earlier SAT drafts used this */ /* XXX: Until the spec decides which one to go with. 20060607 */ ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == ucp) { if (verbose > 1) printf("ATA Return Descriptor expected in sense but not " "found\n"); sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); } else if (verbose) sg_chk_n_print3("ATA Return Descriptor, as expected", &io_hdr, 1); if (ucp && ucp[3]) { if (ucp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]); } break; default: fprintf(stderr, "unexpected SCSI sense category\n"); ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == ucp) sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); else if (verbose) sg_chk_n_print3("ATA Return Descriptor, as expected", &io_hdr, 1); if (ucp && ucp[3]) { if (ucp[3] & 0x4) printf("error in returned FIS: aborted command\n"); else printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]); } break; } if (ucp) { switch (ucp[5]) { /* sector_count (7:0) */ case 0xff: printf("In active mode or idle mode\n"); break; case 0x80: printf("In idle mode\n"); break; case 0x41: printf("In NV power mode and spindle is spun or spinning up\n"); break; case 0x40: printf("In NV power mode and spindle is spun or spinning down\n"); break; case 0x0: printf("In standby mode\n"); break; default: printf("unknown power mode (sector count) value=0x%x\n", ucp[5]); break; } } else fprintf(stderr, "Expecting a ATA Return Descriptor in sense and " "didn't receive it\n"); close(sg_fd); return 0; } sg3_utils-1.40/examples/sg_excl.c0000664000175000017500000001365412200001501015744 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This is a simple program that tests the O_EXCL flag in sg while executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver * Copyright (C) 2003-2013 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. Invocation: sg_excl [-x] Version 3.58 (20130731) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 #define ME "sg_excl: " int main(int argc, char * argv[]) { int sg_fd, k, ok /*, sg_fd2 */; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_excl [-x] '\n"); return 1; } /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if ((sg_fd = open(file_name, O_RDWR | O_EXCL | O_NONBLOCK)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf(ME "%s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } #if 0 if ((sg_fd2 = open(file_name, O_RDWR | O_EXCL)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "error opening file: %s a second time", file_name); perror(ebuff); return 1; } else { printf(ME "second open of %s in violation of O_EXCL\n", file_name); close(sg_fd2); } #endif /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); sleep(60); close(sg_fd); return 0; } sg3_utils-1.40/examples/ref_sense.txt0000664000175000017500000000046111524334352016703 0ustar douggdougg# Test User data segment referral sense data. Values are in hex. # Invocation: 'sg_decode_sense -f ref_sense.txt' [dpg 20110208] 72,0,0,0,0,0,0 38 b,36,1,0 0,0,0,2,11,11,11,11,22,22,22,22,55,55,55,55,66,66,66,66 1,0,0,7, 2,0,0,8 0,0,0,1,77,77,77,77,77,77,77,77,88,88,88,88,88,88,88,88, 3,0,0,5 sg3_utils-1.40/examples/sg_simple_aio.c0000664000175000017500000001563512061626602017157 0ustar douggdougg#include #include #include #include #include #include #include #include #include /* * To use "aio" then uncomment the 'WANT_AIO' define. * Depending on the distribution libaio and libaio-dev packages * may need to be loaded. * If WANT_AIO is defined then a '-laio' term will most likely * be required in the Makefile. */ /* #define WANT_AIO 1 */ #ifdef WANT_AIO #include #endif #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver This variant to test async I/O. * Copyright (C) 2003-2010 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. Invocation: sg_simple_aio [-x] Version 0.92 (20100320) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 #ifdef WANT_AIO void my_io_callback(io_context_t ctx, struct iocb *iocb, long res, long res2) { printf("my_io_callback: res=%ld, res2=%ld\n", res, res2); } #endif int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple_aio [-x] '\n"); return 1; } /* An access mode of O_RDWR is required for write()/read() interface */ if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple_aio: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple_aio: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ #if WANT_AIO { struct iocb a_iocb; struct iocb * iocb_arr[1]; io_context_t io_ctx; int res; if (0 != (res = io_queue_init(1, &io_ctx))) { printf("io_queue_init: failed %s\n", strerror(-res)); close(sg_fd); return 1; } iocb_arr[0] = &a_iocb; io_prep_pwrite(iocb_arr[0], sg_fd, &io_hdr, sizeof(io_hdr), 0); io_set_callback(iocb_arr[0], my_io_callback); res = io_submit(io_ctx, 1, iocb_arr); if (1 != res) { printf("io_submit: returned %d\n", res); close(sg_fd); return 1; } } #else if (write(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { perror("sg_simple_aio: Inquiry write error"); close(sg_fd); return 1; } #endif /* sleep(3); */ if (read(sg_fd, &io_hdr, sizeof(io_hdr)) < 0) { perror("sg_simple_aio: Inquiry read error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple_aio: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); close(sg_fd); return 0; } sg3_utils-1.40/examples/forwarded_sense.txt0000664000175000017500000000045011525023150020072 0ustar douggdougg# Test forwarded sense data. Values are in hex. # Invocation: 'sg_decode_sense -f forwarded_sense.txt' [dpg 20110209] # descriptor header 72 6 18 7 0 0 0 1c # Forwarded sense [len=12] c a 1 2 72 6 18 7 0 0 0 0 # Information [len=12] 0 a 80 0 11 22 33 44 55 66 77 88 # FRU [len=4] 3 2 0 99 sg3_utils-1.40/examples/sg_queue_tst.c0000664000175000017500000001166711353234740017056 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_linux_inc.h" /* This program was used to test SCSI mid level queue ordering. The default behaviour is to "queue at head" which is useful for error processing but not for streaming READ and WRITE commands. * Copyright (C) 2010 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. Invocation: sg_queue_tst [-t] -t queue at tail Version 0.90 (20100324) */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define SDIAG_CMD_LEN 6 #define SENSE_BUFFER_LEN 96 #define EBUFF_SZ 256 #ifndef SG_FLAG_Q_AT_TAIL #define SG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef SG_FLAG_Q_AT_HEAD #define SG_FLAG_Q_AT_HEAD 0x20 #endif int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char sdiagCmdBlk[SDIAG_CMD_LEN] = {0x1d, 0, 0, 0, 0, 0}; unsigned char inqBuff[16][INQ_REPLY_LEN]; sg_io_hdr_t io_hdr[16]; sg_io_hdr_t rio_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[16][SENSE_BUFFER_LEN]; int q_at_tail = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-t", argv[k], 2)) ++q_at_tail; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_queue_tst [-t] '\n" "where:\n -t queue_at_tail (def: q_at_head)\n"); return 1; } /* An access mode of O_RDWR is required for write()/read() interface */ if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_queue_tst: error opening file: %s", file_name); perror(ebuff); return 1; } for (k = 0; k < 16; ++k) { /* Prepare INQUIRY command */ memset(&io_hdr[k], 0, sizeof(sg_io_hdr_t)); io_hdr[k].interface_id = 'S'; /* io_hdr[k].iovec_count = 0; */ /* memset takes care of this */ io_hdr[k].mx_sb_len = (unsigned char)sizeof(sense_buffer); if (0 == (k % 3)) { io_hdr[k].cmd_len = sizeof(sdiagCmdBlk); io_hdr[k].cmdp = sdiagCmdBlk; io_hdr[k].dxfer_direction = SG_DXFER_NONE; } else { io_hdr[k].cmd_len = sizeof(inqCmdBlk); io_hdr[k].cmdp = inqCmdBlk; io_hdr[k].dxfer_direction = SG_DXFER_FROM_DEV; io_hdr[k].dxfer_len = INQ_REPLY_LEN; io_hdr[k].dxferp = inqBuff[k]; } io_hdr[k].sbp = sense_buffer[k]; io_hdr[k].mx_sb_len = SENSE_BUFFER_LEN; io_hdr[k].timeout = 20000; /* 20000 millisecs == 20 seconds */ io_hdr[k].pack_id = k; /* default is to queue at head (in SCSI mid level) */ if (q_at_tail) io_hdr[k].flags |= SG_FLAG_Q_AT_TAIL; else io_hdr[k].flags |= SG_FLAG_Q_AT_HEAD; /* io_hdr[k].usr_ptr = NULL; */ if (write(sg_fd, &io_hdr[k], sizeof(sg_io_hdr_t)) < 0) { perror("sg_queue_tst: sg write error"); close(sg_fd); return 1; } } /* sleep(3); */ for (k = 0; k < 16; ++k) { memset(&rio_hdr, 0, sizeof(sg_io_hdr_t)); rio_hdr.interface_id = 'S'; if (read(sg_fd, &rio_hdr, sizeof(sg_io_hdr_t)) < 0) { perror("sg_queue_tst: sg read error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&rio_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("command error", &rio_hdr, 1); break; } if (ok) { /* output result if it is available */ /* if (0 == rio_hdr.pack_id) */ if (0 == (rio_hdr.pack_id % 3)) printf("SEND DIAGNOSTIC %d duration=%u\n", rio_hdr.pack_id, rio_hdr.duration); else printf("INQUIRY %d duration=%u\n", rio_hdr.pack_id, rio_hdr.duration); } } close(sg_fd); return 0; } sg3_utils-1.40/examples/sg_simple2.c0000664000175000017500000001515012061626602016401 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include "sg_linux_inc.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver. There is another variant of this program called "sg_simple1" which includes the sg_lib.h header and logic and so has more advanced error processing. This version demonstrates the "sg3" interface. In the lk 2.6 series devices nodes such as /dev/sda also support the SG_IO ioctl. * Copyright (C) 1999-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. Invocation: sg_simple2 [-x] Version 03.58 (20070312) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #define INQ_REPLY_LEN 96 /* logic assumes >= sizeof(inqCmdBlk) */ #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 int main(int argc, char * argv[]) { int sg_fd, k; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple2 [-x] '\n"); return 1; } /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if ((sg_fd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple2: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) { printf("sg_simple2: %s doesn't seem to be an new sg device\n", file_name); close(sg_fd); return 1; } /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple2: Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) { if (io_hdr.sb_len_wr > 0) { printf("INQUIRY sense data: "); for (k = 0; k < io_hdr.sb_len_wr; ++k) { if ((k > 0) && (0 == (k % 10))) printf("\n "); printf("0x%02x ", sense_buffer[k]); } printf("\n"); } if (io_hdr.masked_status) printf("INQUIRY SCSI status=0x%x\n", io_hdr.status); if (io_hdr.host_status) printf("INQUIRY host_status=0x%x\n", io_hdr.host_status); if (io_hdr.driver_status) printf("INQUIRY driver_status=0x%x\n", io_hdr.driver_status); } else { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); } /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple2: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ if ((io_hdr.info & SG_INFO_OK_MASK) != SG_INFO_OK) { if (io_hdr.sb_len_wr > 0) { printf("TEST UNIT READY sense data: "); for (k = 0; k < io_hdr.sb_len_wr; ++k) { if ((k > 0) && (0 == (k % 10))) printf("\n "); printf("0x%02x ", sense_buffer[k]); } printf("\n"); } else if (io_hdr.masked_status) printf("TEST UNIT READY SCSI status=0x%x\n", io_hdr.status); else if (io_hdr.host_status) printf("TEST UNIT READY host_status=0x%x\n", io_hdr.host_status); else if (io_hdr.driver_status) printf("TEST UNIT READY driver_status=0x%x\n", io_hdr.driver_status); else printf("TEST UNIT READY unexpected error\n"); printf("Test Unit Ready failed so unit may _not_ be ready!\n"); } else printf("Test Unit Ready successful so unit is ready!\n"); /* Extra info, not necessary to look at */ if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); close(sg_fd); return 0; } sg3_utils-1.40/examples/Makefile.freebsd0000664000175000017500000000243412242710045017237 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = gcc LD = gcc EXECS = sg_simple5 MAN_PGS = MAN_PREF = man8 OS_FLAGS = -DSG_LIB_FREEBSD EXTRA_FLAGS = $(OS_FLAGS) # CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) # CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) CFLAGS_PTHREADS = -D_REENTRANT # there is no rule to make the following in the parent directory, # it is assumed they are already built. D_FILES = ../lib/sg_lib.o ../lib/sg_lib_data.o ../lib/sg_pt_freebsd.o LDFLAGS = -lcam # LDFLAGS = -v -lm all: $(EXECS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) core* .depend *.a *.la *.lo /bin/rm -rf .libs sg_simple5: sg_simple5.o $(D_FILES) $(LD) -o $@ $(LDFLAGS) $@.o $(D_FILES) install: $(EXECS) install -d $(INSTDIR) for name in $(EXECS); \ do install -s -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done sg3_utils-1.40/examples/sg_tst_async.cpp0000664000175000017500000011377512424673250017415 0ustar douggdougg/* * Copyright (c) 2014 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" #include "sg_unaligned.h" static const char * version_str = "1.08 20141028"; static const char * util_name = "sg_tst_async"; /* This is a test program for checking the async usage of the Linux sg * driver. Each thread opens 1 file descriptor to the next sg device (1 * or more can be given on the command line) and then starts up to 16 * commands while checking with the poll command (or * ioctl(SG_GET_NUM_WAITING) ) for the completion of those commands. Each * command has a unique "pack_id" which is a sequence starting at 1. * Either TEST UNIT UNIT, READ(16) or WRITE(16) commands are issued. * * This is C++ code with some things from C++11 (e.g. threads) and was * only just able to compile (when some things were reverted) with gcc/g++ * version 4.7.3 found in Ubuntu 13.04 . C++11 "feature complete" support * was not available until g++ version 4.8.1 . It should build okay on * recent distributions. * * The build uses various object files from the /lib directory * which is assumed to be a sibling of this examples directory. Those * object files in the lib directory can be built with: * cd ; ./configure ; cd lib; make * cd ../examples * Then to build sg_tst_async concatenate the next 3 lines: * g++ -Wall -std=c++11 -pthread -I ../include ../lib/sg_lib.o * ../lib/sg_lib_data.o ../lib/sg_io_linux.o -o sg_tst_async * sg_tst_async.cpp * or use the C++ Makefile in that directory: * make -f Makefile.cplus sg_tst_async * * Currently this utility is Linux only and uses the sg driver. The bsg * driver is known to be broken (it doesn't match responses to the * correct file descriptor that requested them) so this utility won't * be extended to bsg until that is fixed. * * BEWARE: >>> This utility will modify a logical block (default LBA 1000) * on the given device when the '-W' option is given. * */ using namespace std; using namespace std::chrono; #define DEF_NUM_PER_THREAD 1000 #define DEF_NUM_THREADS 4 #define DEF_WAIT_MS 10 /* 0: yield or no wait */ #define DEF_TIMEOUT_MS 20000 /* 20 seconds */ #define DEF_LB_SZ 512 #define DEF_BLOCKING 0 #define DEF_DIRECT 0 #define DEF_NO_XFER 0 #define DEF_LBA 1000 #define MAX_Q_PER_FD 16 /* sg driver per file descriptor limit */ #define MAX_CONSEC_NOMEMS 16 #define URANDOM_DEV "/dev/urandom" #ifndef SG_FLAG_Q_AT_TAIL #define SG_FLAG_Q_AT_TAIL 0x10 #endif #ifndef SG_FLAG_Q_AT_HEAD #define SG_FLAG_Q_AT_HEAD 0x20 #endif #define EBUFF_SZ 256 static mutex console_mutex; static mutex rand_lba_mutex; static atomic async_starts(0); static atomic async_finishes(0); static atomic ebusy_count(0); static atomic eagain_count(0); static atomic uniq_pack_id(1); static int page_size = 4096; /* rough guess, will ask sysconf() */ enum command2execute {SCSI_TUR, SCSI_READ16, SCSI_WRITE16}; /* Linux Block layer queue disciplines: */ enum blkLQDiscipline {BLQ_DEFAULT, BLQ_AT_HEAD, BLQ_AT_TAIL}; /* Queue disciplines of this utility. When both completions and * queuing a new command are both possible: */ enum myQDiscipline {MYQD_LOW, /* favour completions over new cmds */ MYQD_MEDIUM, MYQD_HIGH}; /* favour new cmds over completions */ struct opts_t { vector dev_names; bool direct; int maxq_per_thread; int num_per_thread; bool block; uint64_t lba; unsigned int hi_lba; /* last one, inclusive range */ vector hi_lbas; /* only used when hi_lba=-1 */ int lb_sz; bool no_xfer; int verbose; int wait_ms; command2execute c2e; blkLQDiscipline blqd; myQDiscipline myqd; }; #if 0 class Rand_uint { public: Rand_uint(unsigned int lo, unsigned int hi) : p{lo, hi} {} unsigned int operator()() const { return r(); } private: uniform_int_distribution::param_type p; auto r = bind(uniform_int_distribution{p}, default_random_engine()); /* compiler thinks auto should be a static, bs again? */ }; #endif #if 0 class Rand_uint { public: Rand_uint(unsigned int lo, unsigned int hi, unsigned int my_seed) : r(bind(uniform_int_distribution{lo, hi}, default_random_engine())) { r.seed(myseed); } unsigned int operator()() const { return r(); } private: function r; }; #endif /* Use this class to wrap C++11 features to produce uniform random * unsigned ints in the range [lo, hi] (inclusive) given a_seed */ class Rand_uint { public: Rand_uint(unsigned int lo, unsigned int hi, unsigned int a_seed) : uid(lo, hi), dre(a_seed) { } /* uid ctor takes inclusive range when integral type */ unsigned int get() { return uid(dre); } private: uniform_int_distribution uid; default_random_engine dre; }; static void usage(void) { printf("Usage: %s [-d] [-f] [-h] [-l ] [-M ]\n" " [-n ] [-N] [-q 0|1] [-Q 0|1|2] " "[-R]\n" " [-s ] [-t ] [-T] [-v] " "[-V]\n" " [-w ] [-W] *\n", util_name); printf(" where\n"); printf(" -d do direct_io (def: indirect)\n"); printf(" -f force: any sg device (def: only scsi_debug " "owned)\n"); printf(" WARNING: written to if '-W' given\n"); printf(" -h print this usage message then exit\n"); printf(" -l logical block to access (def: %u)\n", DEF_LBA); printf(" -l logical block range (inclusive), if " "hi_lba=-1\n" " assume last block on device\n"); printf(" -M maximum commands queued per thread " "(def:%d)\n", MAX_Q_PER_FD); printf(" -n number of commands per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -N no data xfer (def: xfer on READ and " "WRITE)\n"); printf(" -q 0|1 0: blk q_at_head; 1: q_at_tail\n"); printf(" -Q 0|1|2 0: favour completions (smaller q), 1: " "medium,\n" " 2: favour submissions (larger q, " "default)\n"); printf(" -s logical block size (def: 512)\n"); printf(" -R do READs (def: TUR)\n"); printf(" -t number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" -T do TEST UNIT READYs (default is TURs)\n"); printf(" -v increase verbosity\n"); printf(" -V print version number then exit\n"); printf(" -w >0: poll(); =0: poll(0); (def: " "%d)\n", DEF_WAIT_MS); printf(" -W do WRITEs (def: TUR)\n\n"); printf("Multiple threads send READ(16), WRITE(16) or TEST UNIT READY " "(TUR) SCSI\ncommands. There can be 1 or more s " "and each thread takes\nthe next in a round robin fashion. " "Each thread queues up to 16 commands.\nOne block is transferred " "by each READ and WRITE; zeros are written. If a\nlogical block " "range is given, a uniform distribution generates a pseudo\n" "random sequence of LBAs.\n"); } #ifdef __GNUC__ static int pr2serr_lk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); static void pr_errno_lk(int e_no, const char * fmt, ...) __attribute__ ((format (printf, 2, 3))); #else static int pr2serr_lk(const char * fmt, ...); static void pr_errno_lk(int e_no, const char * fmt, ...); #endif static int pr2serr_lk(const char * fmt, ...) { int n; va_list args; lock_guard lg(console_mutex); va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void pr_errno_lk(int e_no, const char * fmt, ...) { char b[160]; va_list args; lock_guard lg(console_mutex); va_start(args, fmt); vsnprintf(b, sizeof(b), fmt, args); fprintf(stderr, "%s: %s\n", b, strerror(e_no)); va_end(args); } static unsigned int get_urandom_uint(void) { unsigned int res = 0; int n; unsigned char b[sizeof(unsigned int)]; lock_guard lg(rand_lba_mutex); int fd = open(URANDOM_DEV, O_RDONLY); if (fd >= 0) { n = read(fd, b, sizeof(unsigned int)); if (sizeof(unsigned int) == n) memcpy(&res, b, sizeof(unsigned int)); close(fd); } return res; } #define TUR_CMD_LEN 6 #define READ16_REPLY_LEN 512 #define READ16_CMD_LEN 16 #define WRITE16_REPLY_LEN 512 #define WRITE16_CMD_LEN 16 /* Returns 0 if command injected okay, else -1 */ static int start_sg3_cmd(int sg_fd, command2execute cmd2exe, int pack_id, uint64_t lba, unsigned char * lbp, int xfer_bytes, int flags) { struct sg_io_hdr pt; unsigned char turCmdBlk[TUR_CMD_LEN] = {0, 0, 0, 0, 0, 0}; unsigned char r16CmdBlk[READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char w16CmdBlk[WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char sense_buffer[64]; const char * np = NULL; memset(&pt, 0, sizeof(pt)); switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; pt.cmdp = turCmdBlk; pt.cmd_len = sizeof(turCmdBlk); pt.dxfer_direction = SG_DXFER_NONE; break; case SCSI_READ16: np = "READ(16)"; if (lba > 0xffffffff) sg_put_unaligned_be32(lba >> 32, &r16CmdBlk[2]); sg_put_unaligned_be32(lba & 0xffffffff, &r16CmdBlk[6]); pt.cmdp = r16CmdBlk; pt.cmd_len = sizeof(r16CmdBlk); pt.dxfer_direction = SG_DXFER_FROM_DEV; pt.dxferp = lbp; pt.dxfer_len = xfer_bytes; break; case SCSI_WRITE16: np = "WRITE(16)"; if (lba > 0xffffffff) sg_put_unaligned_be32(lba >> 32, &w16CmdBlk[2]); sg_put_unaligned_be32(lba & 0xffffffff, &w16CmdBlk[6]); pt.cmdp = w16CmdBlk; pt.cmd_len = sizeof(w16CmdBlk); pt.dxfer_direction = SG_DXFER_TO_DEV; pt.dxferp = lbp; pt.dxfer_len = xfer_bytes; break; } pt.interface_id = 'S'; pt.mx_sb_len = sizeof(sense_buffer); pt.sbp = sense_buffer; /* ignored .... */ pt.timeout = DEF_TIMEOUT_MS; pt.pack_id = pack_id; pt.flags = flags; for (int k = 0; write(sg_fd, &pt, sizeof(pt)) < 0; ++k) { if ((ENOMEM == errno) && (k < MAX_CONSEC_NOMEMS)) { this_thread::yield(); continue; } pr_errno_lk(errno, "%s: %s, pack_id=%d", __func__, np, pack_id); return -1; } return 0; } static int finish_sg3_cmd(int sg_fd, command2execute cmd2exe, int & pack_id, int wait_ms, unsigned int & eagains) { int ok, res; struct sg_io_hdr pt; unsigned char sense_buffer[64]; const char * np = NULL; memset(&pt, 0, sizeof(pt)); switch (cmd2exe) { case SCSI_TUR: np = "TEST UNIT READY"; break; case SCSI_READ16: np = "READ(16)"; break; case SCSI_WRITE16: np = "WRITE(16)"; break; } pt.interface_id = 'S'; pt.mx_sb_len = sizeof(sense_buffer); pt.sbp = sense_buffer; pt.timeout = DEF_TIMEOUT_MS; pt.pack_id = 0; while (((res = read(sg_fd, &pt, sizeof(pt))) < 0) && (EAGAIN == errno)) { ++eagains; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); else if (-2 == wait_ms) sleep(0); // process yield ?? } if (res < 0) { pr_errno_lk(errno, "%s: %s", __func__, np); return -1; } /* now for the error processing */ pack_id = pt.pack_id; ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: pr2serr_lk("%s: Recovered error on %s, continuing\n", __func__, np); ok = 1; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3(np, &pt, 1); } break; } return ok ? 0 : -1; } /* Should have page alignment if direct_io chosen */ static unsigned char * get_aligned_heap(int bytes_at_least) { int n; void * wp; if (bytes_at_least < page_size) n = page_size; else n = bytes_at_least; #if 1 int err = posix_memalign(&wp, page_size, n); if (err) { pr2serr_lk("posix_memalign: error [%d] out of memory?\n", err); return NULL; } memset(wp, 0, n); return (unsigned char *)wp; #else /* hack if posix_memalign() is not available */ if (n == page_size) { wp = calloc(page_size, 1); memset(wp, 0, n); return (unsigned char *)wp; } else { pr2serr_lk("get_aligned_heap: too fiddly to align, choose smaller " "lb_sz\n"); return NULL; } #endif } static void work_thread(int id, struct opts_t * op) { int thr_async_starts = 0; int thr_async_finishes = 0; unsigned int thr_eagain_count = 0; unsigned int seed = 0; unsigned int hi_lba; int k, n, res, sg_fd, num_outstanding, do_inc, npt, pack_id, sg_flags; int num_waiting_read, num_to_read; int open_flags = O_RDWR; bool is_rw = (SCSI_TUR != op->c2e); char ebuff[EBUFF_SZ]; uint64_t lba; unsigned char * lbp; const char * dev_name; const char * err = NULL; Rand_uint * ruip = NULL; struct pollfd pfd[1]; list free_lst; /* of aligned lb buffers */ map pi_2_buff; /* pack_id -> lb buffer */ map pi_2_lba; /* pack_id -> LBA */ /* device name and hi_lba may depend on id */ n = op->dev_names.size(); dev_name = op->dev_names[id % n]; if ((UINT_MAX == op->hi_lba) && (n == (int)op->hi_lbas.size())) hi_lba = op->hi_lbas[id % n]; else hi_lba = op->hi_lba; if (op->verbose) { if ((op->verbose > 1) && hi_lba) pr2serr_lk("Enter work_thread id=%d using %s\n" " LBA range: 0x%x to 0x%x (inclusive)\n", id, dev_name, (unsigned int)op->lba, hi_lba); else pr2serr_lk("Enter work_thread id=%d using %s\n", id, dev_name); } if (! op->block) open_flags |= O_NONBLOCK; sg_fd = open(dev_name, open_flags); if (sg_fd < 0) { pr_errno_lk(errno, "%s: id=%d, error opening file: %s", __func__, id, dev_name); return; } pfd[0].fd = sg_fd; pfd[0].events = POLLIN; if (is_rw && hi_lba) { seed = get_urandom_uint(); if (op->verbose > 1) pr2serr_lk(" id=%d, /dev/urandom seed=0x%x\n", id, seed); ruip = new Rand_uint((unsigned int)op->lba, hi_lba, seed); } sg_flags = 0; if (BLQ_AT_TAIL == op->blqd) sg_flags |= SG_FLAG_Q_AT_TAIL; else if (BLQ_AT_HEAD == op->blqd) sg_flags |= SG_FLAG_Q_AT_HEAD; if (op->direct) sg_flags |= SG_FLAG_DIRECT_IO; if (op->no_xfer) sg_flags |= SG_FLAG_NO_DXFER; if (op->verbose > 1) pr2serr_lk(" id=%d, sg_flags=0x%x, %s cmds\n", id, sg_flags, ((SCSI_TUR == op->c2e) ? "TUR": ((SCSI_READ16 == op->c2e) ? "READ" : "WRITE"))); npt = op->num_per_thread; /* main loop, continues until num_per_thread exhausted and there are * no more outstanding responses */ for (k = 0, num_outstanding = 0; (k < npt) || num_outstanding; k = do_inc ? k + 1 : k) { do_inc = 0; if ((num_outstanding < op->maxq_per_thread) && (k < npt)) { do_inc = 1; pack_id = uniq_pack_id.fetch_add(1); if (is_rw) { /* get new lb buffer or one from free list */ if (free_lst.empty()) { lbp = get_aligned_heap(op->lb_sz); if (NULL == lbp) { err = "out of memory"; break; } } else { lbp = free_lst.back(); free_lst.pop_back(); } } else lbp = NULL; if (is_rw) { if (ruip) { lba = ruip->get(); /* fetch a random LBA */ if (op->verbose > 3) pr2serr_lk(" id=%d: start IO at lba=0x%" PRIx64 "\n", id, lba); } else lba = op->lba; } else lba = 0; if (start_sg3_cmd(sg_fd, op->c2e, pack_id, lba, lbp, op->lb_sz, sg_flags)) { err = "start_sg3_cmd()"; break; } ++thr_async_starts; ++num_outstanding; pi_2_buff[pack_id] = lbp; if (ruip) pi_2_lba[pack_id] = lba; } num_to_read = 0; if ((num_outstanding >= op->maxq_per_thread) || (k >= npt)) { /* full queue or finished injecting */ num_waiting_read = 0; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting_read) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } if (1 == num_waiting_read) num_to_read = num_waiting_read; else if (num_waiting_read > 0) { if (k >= npt) num_to_read = num_waiting_read; else { switch (op->myqd) { case MYQD_LOW: num_to_read = num_waiting_read; break; case MYQD_MEDIUM: num_to_read = num_waiting_read / 2; break; case MYQD_HIGH: default: num_to_read = 1; break; } } } else { /* nothing waiting to be read */ n = (op->wait_ms > 0) ? op->wait_ms : 0; while (0 == (res = poll(pfd, 1, n))) { if (res < 0) { err = "poll(wait_ms) failed"; break; } } if (err) break; } } else { /* not full, not finished injecting */ if (MYQD_HIGH == op->myqd) num_to_read = 0; else { num_waiting_read = 0; if (ioctl(sg_fd, SG_GET_NUM_WAITING, &num_waiting_read) < 0) { err = "ioctl(SG_GET_NUM_WAITING) failed"; break; } if (num_waiting_read > 0) num_to_read = num_waiting_read / ((MYQD_LOW == op->myqd) ? 1 : 2); else num_to_read = 0; } } while (num_to_read-- > 0) { if (finish_sg3_cmd(sg_fd, op->c2e, pack_id, op->wait_ms, thr_eagain_count)) { err = "finish_sg3_cmd()"; if (ruip && (pack_id > 0)) { auto q = pi_2_lba.find(pack_id); if (q != pi_2_lba.end()) { snprintf(ebuff, sizeof(ebuff), "%s: lba=0x%" PRIx64 , err, q->second); err = ebuff; } } break; } ++thr_async_finishes; --num_outstanding; auto p = pi_2_buff.find(pack_id); if (p == pi_2_buff.end()) { snprintf(ebuff, sizeof(ebuff), "pack_id=%d from " "finish_sg3_cmd() not found\n", pack_id); if (! err) err = ebuff; } else { lbp = p->second; pi_2_buff.erase(p); if (lbp) free_lst.push_front(lbp); } if (ruip && (pack_id > 0)) { auto q = pi_2_lba.find(pack_id); if (q != pi_2_lba.end()) { if (op->verbose > 3) pr2serr_lk(" id=%d: finish IO at lba=0x%" PRIx64 "\n", id, q->second); pi_2_lba.erase(q); } } if (err) break; } if (err) break; } close(sg_fd); // sg driver will handle any commands "in flight" if (ruip) delete ruip; if (err || (k < npt)) { if (k < npt) pr2serr_lk("thread id=%d FAILed at iteration %d%s%s\n", id, k, (err ? ", Reason: " : ""), (err ? err : "")); else pr2serr_lk("thread id=%d FAILed on last%s%s\n", id, (err ? ", Reason: " : ""), (err ? err : "")); } n = pi_2_buff.size(); if (n > 0) pr2serr_lk("thread id=%d Still %d elements in pi_2_buff map on " "exit\n", id, n); for (k = 0; ! free_lst.empty(); ++k) { lbp = free_lst.back(); free_lst.pop_back(); if (lbp) free(lbp); } if ((op->verbose > 2) && (k > 0)) pr2serr_lk("thread id=%d Maximum number of READ/WRITEs queued: %d\n", id, k); async_starts += thr_async_starts; async_finishes += thr_async_finishes; eagain_count += thr_eagain_count; } #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 /* Send INQUIRY and fetches response. If okay puts PRODUCT ID field * in b (up to m_blen bytes). Does not use O_EXCL flag. Returns 0 on success, * else -1 . */ static int do_inquiry_prod_id(const char * dev_name, int block, char * b, int b_mlen) { int sg_fd, ok, ret; struct sg_io_hdr pt; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; unsigned char sense_buffer[64]; int open_flags = O_RDWR; /* O_EXCL | O_RDONLY fails with EPERM */ if (! block) open_flags |= O_NONBLOCK; sg_fd = open(dev_name, open_flags); if (sg_fd < 0) { pr_errno_lk(errno, "%s: error opening file: %s", __func__, dev_name); return -1; } /* Prepare INQUIRY command */ memset(&pt, 0, sizeof(pt)); pt.interface_id = 'S'; pt.cmd_len = sizeof(inqCmdBlk); /* pt.iovec_count = 0; */ /* memset takes care of this */ pt.mx_sb_len = sizeof(sense_buffer); pt.dxfer_direction = SG_DXFER_FROM_DEV; pt.dxfer_len = INQ_REPLY_LEN; pt.dxferp = inqBuff; pt.cmdp = inqCmdBlk; pt.sbp = sense_buffer; pt.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* pt.flags = 0; */ /* take defaults: indirect IO, etc */ /* pt.pack_id = 0; */ /* pt.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &pt) < 0) { pr_errno_lk(errno, "%s: Inquiry SG_IO ioctl error", __func__); close(sg_fd); return -1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&pt)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: pr2serr_lk("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ { lock_guard lg(console_mutex); sg_chk_n_print3("INQUIRY command error", &pt, 1); } break; } if (ok) { /* Good, so fetch Product ID from response, copy to 'b' */ if (b_mlen > 0) { if (b_mlen > 16) { memcpy(b, inqBuff + 16, 16); b[16] = '\0'; } else { memcpy(b, inqBuff + 16, b_mlen - 1); b[b_mlen - 1] = '\0'; } } ret = 0; } else ret = -1; close(sg_fd); return ret; } /* Only allow ranges up to 2**32-1 upper limit, so READ CAPACITY(10) * sufficient. Return of 0 -> success, -1 -> failure, 2 -> try again */ static int do_read_capacity(const char * dev_name, int block, unsigned int * last_lba, unsigned int * blk_sz) { int res, sg_fd; unsigned char rcCmdBlk [10] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char rcBuff[64]; unsigned char sense_b[64]; sg_io_hdr_t io_hdr; int open_flags = O_RDWR; /* O_EXCL | O_RDONLY fails with EPERM */ if (! block) open_flags |= O_NONBLOCK; sg_fd = open(dev_name, open_flags); if (sg_fd < 0) { pr_errno_lk(errno, "%s: error opening file: %s", __func__, dev_name); return -1; } /* Prepare READ CAPACITY(10) command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rcCmdBlk); io_hdr.mx_sb_len = sizeof(sense_b); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = sizeof(rcBuff); io_hdr.dxferp = rcBuff; io_hdr.cmdp = rcCmdBlk; io_hdr.sbp = sense_b; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */; if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { pr_errno_lk(errno, "%s (SG_IO) error", __func__); close(sg_fd); return -1; } res = sg_err_category3(&io_hdr); if (SG_LIB_CAT_UNIT_ATTENTION == res) { lock_guard lg(console_mutex); sg_chk_n_print3("read capacity", &io_hdr, 1); close(sg_fd); return 2; /* probably have another go ... */ } else if (SG_LIB_CAT_CLEAN != res) { lock_guard lg(console_mutex); sg_chk_n_print3("read capacity", &io_hdr, 1); close(sg_fd); return -1; } *last_lba = sg_get_unaligned_be32(&rcBuff[0]); *blk_sz = sg_get_unaligned_be32(&rcBuff[4]); close(sg_fd); return 0; } int main(int argc, char * argv[]) { int k, n, res; int force = 0; int64_t ll; int num_threads = DEF_NUM_THREADS; char b[128]; struct timespec start_tm, end_tm; struct opts_t opts; struct opts_t * op; const char * cp; const char * dev_name; op = &opts; op->direct = !! DEF_DIRECT; op->lba = DEF_LBA; op->hi_lba = 0; op->lb_sz = DEF_LB_SZ; op->maxq_per_thread = MAX_Q_PER_FD; op->num_per_thread = DEF_NUM_PER_THREAD; op->no_xfer = !! DEF_NO_XFER; op->verbose = 0; op->wait_ms = DEF_WAIT_MS; op->c2e = SCSI_TUR; op->blqd = BLQ_DEFAULT; op->block = !! DEF_BLOCKING; op->myqd = MYQD_HIGH; page_size = sysconf(_SC_PAGESIZE); for (k = 1; k < argc; ++k) { if (0 == memcmp("-d", argv[k], 2)) op->direct = true; else if (0 == memcmp("-f", argv[k], 2)) ++force; else if (0 == memcmp("-h", argv[k], 2)) { usage(); return 0; } else if (0 == memcmp("-l", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { ll = sg_get_llnum(argv[k]); if (-1 == ll) { pr2serr_lk("could not decode lba\n"); return 1; } else op->lba = (uint64_t)ll; cp = strchr(argv[k], ','); if (cp) { if (0 == strcmp("-1", cp + 1)) op->hi_lba = UINT_MAX; else { ll = sg_get_llnum(cp + 1); if ((-1 == ll) || (ll > UINT_MAX)) { pr2serr_lk("could not decode hi_lba, or > " "UINT_MAX\n"); return 1; } else op->hi_lba = (unsigned int)ll; } } } else break; } else if (0 == memcmp("-M", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { n = atoi(argv[k]); if ((n < 1) || (n > MAX_Q_PER_FD)) { pr2serr_lk("-M expects a value from 1 to %d\n", MAX_Q_PER_FD); return 1; } op->maxq_per_thread = n; } else break; } else if (0 == memcmp("-n", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) op->num_per_thread = sg_get_num(argv[k]); else break; } else if (0 == memcmp("-N", argv[k], 2)) op->no_xfer = true; else if (0 == memcmp("-q", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { n = atoi(argv[k]); if (0 == n) op->blqd = BLQ_AT_HEAD; else if (1 == n) op->blqd = BLQ_AT_TAIL; } else break; } else if (0 == memcmp("-Q", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { n = atoi(argv[k]); if (0 == n) op->myqd = MYQD_LOW; else if (1 == n) op->myqd = MYQD_MEDIUM; else if (2 == n) op->myqd = MYQD_HIGH; } else break; } else if (0 == memcmp("-R", argv[k], 2)) op->c2e = SCSI_READ16; else if (0 == memcmp("-s", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) { op->lb_sz = atoi(argv[k]); if (op->lb_sz < 256) { cerr << "Strange lb_sz, using 256" << endl; op->lb_sz = 256; } } else break; } else if (0 == memcmp("-t", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_threads = atoi(argv[k]); else break; } else if (0 == memcmp("-T", argv[k], 2)) op->c2e = SCSI_TUR; else if (0 == memcmp("-vvvv", argv[k], 5)) op->verbose += 4; else if (0 == memcmp("-vvv", argv[k], 4)) op->verbose += 3; else if (0 == memcmp("-vv", argv[k], 3)) op->verbose += 2; else if (0 == memcmp("-v", argv[k], 2)) ++op->verbose; else if (0 == memcmp("-V", argv[k], 2)) { printf("%s version: %s\n", util_name, version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) { ++k; if ((k < argc) && (isdigit(*argv[k]) || ('-' == *argv[k]))) { if ('-' == *argv[k]) op->wait_ms = - atoi(argv[k] + 1); else op->wait_ms = atoi(argv[k]); } else break; } else if (0 == memcmp("-W", argv[k], 2)) op->c2e = SCSI_WRITE16; else if (*argv[k] == '-') { pr2serr_lk("Unrecognized switch: %s\n", argv[k]); return 1; } else op->dev_names.push_back(argv[k]); } if (0 == op->dev_names.size()) { usage(); return 1; } if (op->hi_lba && (op->lba > op->hi_lba)) { cerr << "lba,hi_lba range is illegal" << endl; return 1; } try { struct stat a_stat; for (k = 0; k < (int)op->dev_names.size(); ++k) { dev_name = op->dev_names[k]; if (stat(dev_name, &a_stat) < 0) { snprintf(b, sizeof(b), "could not stat() %s", dev_name); perror(b); return 1; } if (! S_ISCHR(a_stat.st_mode)) { pr2serr_lk("%s should be a sg device which is a char " "device. %s\n", dev_name, dev_name); pr2serr_lk("is not a char device and damage could be done " "if it is a BLOCK\ndevice, exiting ...\n"); return 1; } if (! force) { res = do_inquiry_prod_id(dev_name, op->block, b, sizeof(b)); if (res) { pr2serr_lk("INQUIRY failed on %s\n", dev_name); return 1; } // For safety, since written to, only permit scsi_debug // devices. Bypass this with '-f' option. if (0 != memcmp("scsi_debug", b, 10)) { pr2serr_lk("Since this utility may write to LBAs, " "only devices with the\n" "product ID 'scsi_debug' accepted. Use '-f' " "to override.\n"); return 2; } } if (UINT_MAX == op->hi_lba) { unsigned int last_lba; unsigned int blk_sz; res = do_read_capacity(dev_name, op->block, &last_lba, &blk_sz); if (2 == res) res = do_read_capacity(dev_name, op->block, &last_lba, &blk_sz); if (res) { pr2serr_lk("READ CAPACITY(10) failed on %s\n", dev_name); return 1; } op->hi_lbas.push_back(last_lba); if (blk_sz != (unsigned int)op->lb_sz) pr2serr_lk(">>> warning: Logical block size (%d) of %s\n" " differs from command line option (or " "default)\n", blk_sz, dev_name); } } start_tm.tv_sec = 0; start_tm.tv_nsec = 0; if (clock_gettime(CLOCK_MONOTONIC, &start_tm) < 0) perror("clock_gettime failed"); vector vt; /* start multi-threaded section */ for (k = 0; k < num_threads; ++k) { thread * tp = new thread {work_thread, k, op}; vt.push_back(tp); } // g++ 4.7.3 didn't like range-for loop here for (k = 0; k < (int)vt.size(); ++k) vt[k]->join(); /* end multi-threaded section, just this main thread left */ for (k = 0; k < (int)vt.size(); ++k) delete vt[k]; n = uniq_pack_id.load() - 1; if ((n > 0) && (0 == clock_gettime(CLOCK_MONOTONIC, &end_tm))) { struct timespec res_tm; double a, b; res_tm.tv_sec = end_tm.tv_sec - start_tm.tv_sec; res_tm.tv_nsec = end_tm.tv_nsec - start_tm.tv_nsec; if (res_tm.tv_nsec < 0) { --res_tm.tv_sec; res_tm.tv_nsec += 1000000000; } a = res_tm.tv_sec; a += (0.000001 * (res_tm.tv_nsec / 1000)); b = (double)n; if (a > 0.000001) { printf("Time to complete %d commands was %d.%06d seconds\n", n, (int)res_tm.tv_sec, (int)(res_tm.tv_nsec / 1000)); printf("Implies %.0f IOPS\n", (b / a)); } } if (op->verbose) { cout << "Number of async_starts: " << async_starts.load() << endl; cout << "Number of async_finishes: " << async_finishes.load() << endl; cout << "Last pack_id: " << n << endl; cout << "Number of EBUSYs: " << ebusy_count.load() << endl; cout << "Number of EAGAINs: " << eagain_count.load() << endl; } } catch(system_error& e) { cerr << "got a system_error exception: " << e.what() << '\n'; auto ec = e.code(); cerr << "category: " << ec.category().name() << '\n'; cerr << "value: " << ec.value() << '\n'; cerr << "message: " << ec.message() << '\n'; cerr << "\nNote: if g++ may need '-pthread' or similar in " "compile/link line" << '\n'; } catch(...) { cerr << "got another exception: " << '\n'; } return 0; } sg3_utils-1.40/examples/sg_persist_tst.sh0000775000175000017500000000702712346326270017614 0ustar douggdougg#!/bin/sh # This script is meant as an example of using the sg_persist utility # in the sg3_utils package. This script works as expected on the # author's Fujitsu MAM3184, Seagate ST373455 and ST9146803SS disks. # # Version 1.9 20140612 # N.B. make sure the device name is correct for your environment. key="123abc" key2="333aaa" kk=${key} rtype="1" verbose="" usage() { echo "Usage: sg_persist_tst.sh [-e] [-h] [-s] [-v] " echo " where:" echo -n " -e, --exclusive exclusive access (def: write " echo "exclusive)" echo " -h, --help print usage message" echo " -s, --second use second key" echo " -v, --verbose more verbose output" echo " -vv even more verbose output" echo " -vvv even more verbose output" echo "" echo "Test SCSI Persistent Reservations with sg_persist utility." echo "Default key is ${key} and alternate, second key is ${key2} ." echo "Should be harmless (unless one of those keys is already in use)." echo "The APTPL bit is not set in the PR register so a power cycle" echo "on the device will clear the reservation if this script stops" echo "(or is stopped) before clearing it. Tape drives only seem to " echo "support 'exclusive access' type (so use '-e')." } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in e|-exclusive) rtype="3" ;; h|-help) usage ; exit 0 ;; s|-second) kk=${key2} ;; vvv) verbose="-vvv" ;; vv) verbose="-vv" ;; v|-verbose) verbose="-v" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi echo ">>> try to report capabilities:" sg_persist -c ${verbose} $1 res=$? case "$res" in 0) ;; 1) echo " syntax error" ;; 2) echo " not ready" ;; 3) echo " medium error" ;; 5) echo " illegal request, report capabilities not supported?" ;; 6) echo " unit attention" ;; 9) echo " illegal request, Persistent Reserve (In) not supported" ;; 11) echo " aborted command" ;; 15) echo " file error with $1 " ;; 20) echo " no sense" ;; 21) echo " recovered error" ;; 33) echo " timeout" ;; 97) echo " response fails sanity" ;; 98) echo " other SCSI error" ;; 99) echo " other error" ;; *) echo " unknown exit status for sg_persist: $res" ;; esac echo "" sleep 1 echo ">>> check if any keys are registered:" sg_persist --no-inquiry --read-keys ${verbose} $1 sleep 1 echo echo ">>> register a key:" sg_persist -n --out --register --param-sark=${kk} ${verbose} $1 sleep 1 echo echo ">>> now key ${kk} should be registered:" sg_persist -n --read-keys ${verbose} $1 sleep 1 echo echo ">>> reserve the device (based on key ${kk}):" sg_persist -n --out --reserve --param-rk=${kk} --prout-type=${rtype} ${verbose} $1 sleep 1 echo echo ">>> check if the device is reserved (it should be now):" sg_persist -n --read-reservation ${verbose} $1 sleep 1 echo echo ">>> try to 'read full status' (may not be supported):" sg_persist -n --read-full-status ${verbose} $1 sleep 1 echo echo ">>> now release reservation:" sg_persist -n --out --release --param-rk=${kk} --prout-type=${rtype} ${verbose} $1 sleep 1 echo echo ">>> check if the device is reserved (it should _not_ be now):" sg_persist -n --read-reservation ${verbose} $1 sleep 1 echo echo ">>> unregister key ${kk}:" sg_persist -n --out --register --param-rk=${kk} ${verbose} $1 sleep 1 echo echo ">>> now key ${kk} should not be registered:" sg_persist -n -k ${verbose} $1 sleep 1 sg3_utils-1.40/examples/sdiag_sas_p1_stop.txt0000664000175000017500000000054710640357443020345 0ustar douggdougg# This is the hex for a SAS protocol specific diagnostic # page. It will attempt to stop phy identifier 1 of the # given device producing a test pattern. # N.B. This should make phy id 1 usable for SAS protocols again. # # Usage example: 'sg_senddiag --pf --raw=- /dev/sg2 < {this_file}' # 3f,6,0,1c,1,0,2,9, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 sg3_utils-1.40/examples/sg_sat_smart_rd_data.c0000664000175000017500000001505710640357271020513 0ustar douggdougg/* * Copyright (c) 2006-2007 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program performs a ATA PASS-THROUGH (16) SCSI command in order to perform an ATA SMART/READ DATA command. See http://www.t10.org SAT draft at time of writing: sat-r08.pdf Invocation: sg_sat_smart_rd_data [-v] [-V] */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ATA_SMART 0xb0 #define ATA_SMART_READ_DATA 0xd0 #define SMART_READ_DATA_RESPONSE_LEN 512 #define EBUFF_SZ 256 static char * version_str = "1.02 20070130"; int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char inBuff[SMART_READ_DATA_RESPONSE_LEN]; unsigned char sense_buffer[32]; int verbose = 0; int extend = 0; int chk_cond = 0; /* set to 1 to read register(s) back */ int protocol = 4; /* PIO data-in */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ const unsigned char * ucp = NULL; for (k = 1; k < argc; ++k) { if (0 == strcmp(argv[k], "-v")) ++verbose; else if (0 == strcmp(argv[k], "-vv")) verbose += 2; else if (0 == strcmp(argv[k], "-vvv")) verbose += 3; else if (0 == strcmp(argv[k], "-V")) { fprintf(stderr, "version: %s\n", version_str); exit(0); } else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_sat_smart_rd_data [-v] [-V] '\n"); return 1; } if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_sat_smart_rd_data: error opening file: %s", file_name); perror(ebuff); return 1; } /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[4] = ATA_SMART_READ_DATA; /* feature (7:0) */ aptCmdBlk[6] = 1; /* number of block (sector count) */ aptCmdBlk[10] = 0x4f; /* lba_mid (7:0) */ aptCmdBlk[12] = 0xc2; /* lba_high (7:0) */ aptCmdBlk[14] = ATA_SMART; aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; if (verbose) { fprintf(stderr, " ata pass through(16) cdb: "); for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k) fprintf(stderr, "%02x ", aptCmdBlk[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(aptCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = SMART_READ_DATA_RESPONSE_LEN; io_hdr.dxferp = inBuff; io_hdr.cmdp = aptCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_sat_smart_rd_data: SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: ucp = sg_scsi_sense_desc_find(sense_buffer, sizeof(sense_buffer), SAT_ATA_RETURN_DESC); if (NULL == ucp) { if (verbose > 1) printf("ATA Return Descriptor expected in sense but not " "found\n"); sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); } else if (verbose) sg_chk_n_print3("ATA Return Descriptor", &io_hdr, 1); if (ucp && ucp[3]) printf("error=0x%x, status=0x%x\n", ucp[3], ucp[13]); else ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ printf("Response:\n"); dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); } close(sg_fd); return 0; } sg3_utils-1.40/examples/sdiag_sas_p1_idle.txt0000664000175000017500000000106011214266022020252 0ustar douggdougg# This is the hex for a SAS protocol specific diagnostic # page. It will attempt to put phy identifier 1 of the # given device into IDLE (continuously transmit idle dwords) mode. # Physical transmission speed is 3 Gbps (last number on first # active line can be 8 for 1.5Gbps, 9 for 3Gbps and 10 for 6Gbps). # See sdiag_sas_p1_stop.txt to turn off this test pattern. # N.B. This will turn the receiver off on phy id 1. # # Usage example: 'sg_senddiag --pf --raw=- /dev/sg2 < {this_file}' # 3f,6,0,1c,1,1,12,9, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0 sg3_utils-1.40/examples/sg_simple4.c0000664000175000017500000001641111021562517016403 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This is a simple program executing a SCSI INQUIRY command and a TEST UNIT READY command using the SCSI generic (sg) driver This variant shows mmap-ed IO being used to read the data returned by the INQUIRY command. * Copyright (C) 2001 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. Invocation: sg_simple4 [-x] Version 1.01 (20020113) 6 byte INQUIRY command: [0x12][ |lu][pg cde][res ][al len][cntrl ] 6 byte TEST UNIT READY command: [0x00][ |lu][res ][res ][res ][res ] */ #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif /* since /usr/include/scsi/sg.h doesn't know about this yet */ #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 #define TUR_CMD_LEN 6 #define EBUFF_SZ 256 int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char turCmdBlk [TUR_CMD_LEN] = {0x00, 0, 0, 0, 0, 0}; unsigned char * inqBuff; unsigned char * inqBuff2; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char sense_buffer[32]; int do_extra = 0; for (k = 1; k < argc; ++k) { if (0 == memcmp("-x", argv[k], 2)) do_extra = 1; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'sg_simple4 [-x] '\n"); return 1; } /* N.B. An access mode of O_RDWR is required for some SCSI commands */ if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_simple4: error opening file: %s", file_name); perror(ebuff); return 1; } /* Just to be safe, check we have a new sg device by trying an ioctl */ if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30122)) { printf("sg_simple4: %s needs sg driver version >= 3.1.22\n", file_name); close(sg_fd); return 1; } /* since I know this program will only read from inqBuff then I use PROT_READ rather than PROT_READ | PROT_WRITE */ inqBuff = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0); if (MAP_FAILED == inqBuff) { snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() on " "file: %s", file_name); perror(ebuff); return 1; } if (inqBuff[0]) printf("non-null char at inqBuff[0]\n"); if (inqBuff[5000]) printf("non-null char at inqBuff[5000]\n"); /* Prepare INQUIRY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; /* io_hdr.dxferp = inqBuff; // ignored in mmap-ed IO */ io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ io_hdr.flags = SG_FLAG_MMAP_IO; /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple4: Inquiry SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on INQUIRY, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; int f = (int)*(p + 7); printf("Some of the INQUIRY command's results:\n"); printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[wide=%d sync=%d cmdque=%d sftre=%d]\n", !!(f & 0x20), !!(f & 0x10), !!(f & 2), !!(f & 1)); /* Extra info, not necessary to look at */ if (do_extra) printf("INQUIRY duration=%u millisecs, resid=%d, msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); } /* Prepare TEST UNIT READY command */ memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(turCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.cmdp = turCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_simple4: Test Unit Ready SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: printf("Recovered error on Test Unit Ready, continuing\n"); ok = 1; break; default: /* won't bother decoding other categories */ sg_chk_n_print3("Test Unit Ready command error", &io_hdr, 1); break; } if (ok) printf("Test Unit Ready successful so unit is ready!\n"); else printf("Test Unit Ready failed so unit may _not_ be ready!\n"); if (do_extra) printf("TEST UNIT READY duration=%u millisecs, resid=%d, " "msg_status=%d\n", io_hdr.duration, io_hdr.resid, (int)io_hdr.msg_status); /* munmap(inqBuff, 8000); */ /* could call munmap(inqBuff, INQ_REPLY_LEN) here but following close() causes this too happen anyway */ #if 1 inqBuff2 = (unsigned char *)mmap(NULL, 8000, PROT_READ | PROT_WRITE, MAP_SHARED, sg_fd, 0); if (MAP_FAILED == inqBuff2) { snprintf(ebuff, EBUFF_SZ, "sg_simple4: error using mmap() 2 on " "file: %s", file_name); perror(ebuff); return 1; } if (inqBuff2[0]) printf("non-null char at inqBuff2[0]\n"); if (inqBuff2[5000]) printf("non-null char at inqBuff2[5000]\n"); { pid_t pid; pid = fork(); if (pid) { inqBuff2[5000] = 33; munmap(inqBuff, 8000); sleep(3); } else { inqBuff[5000] = 0xaa; munmap(inqBuff, 8000); sleep(1); } } #endif close(sg_fd); return 0; } sg3_utils-1.40/examples/sg__sat_identify.c0000664000175000017500000001711310640357271017654 0ustar douggdougg/* * Copyright (c) 2006-2007 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program uses a ATA PASS-THROUGH (16) SCSI command to package an ATA IDENTIFY DEVICE (A1h) command. If the '-p' option is given, it will package an ATA IDENTIFY PACKET DEVICE (Ech) instead (for ATAPI device like cd/dvd drives) See http://www.t10.org SAT draft at time of writing: sat-r08a.pdf Invocation: sg__sat_identify [-p] [-v] [-V] With SAT, the user can find out whether a device is an ATA disk or an ATAPI device. The ATA Information VPD page contains a "command code" field in byte 56. Its values are either ECh for a (s/p)ATA disk, A1h for a (s/p)ATAPI device, or 0 for unknown. */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ATA_IDENTIFY_DEVICE 0xec #define ATA_IDENTIFY_PACKET_DEVICE 0xa1 #define ID_RESPONSE_LEN 512 #define EBUFF_SZ 256 static char * version_str = "1.02 20070130"; static void usage() { fprintf(stderr, "Usage: " "sg__sat_identify [-p] [-v] [-V] \n" " where: -p do IDENTIFY PACKET DEVICE (def: IDENTIFY " "DEVICE) command\n" " -v increase verbosity\n" " -V print version string and exit\n\n" "Performs a IDENTIFY (PACKET) DEVICE ATA command via a SAT " "pass through\n"); } int main(int argc, char * argv[]) { int sg_fd, k, ok; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sg_io_hdr_t io_hdr; char * file_name = 0; char ebuff[EBUFF_SZ]; unsigned char inBuff[ID_RESPONSE_LEN]; unsigned char sense_buffer[32]; int do_packet = 0; int verbose = 0; int extend = 0; int chk_cond = 0; /* set to 1 to read register(s) back */ int protocol = 4; /* PIO data-in */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ const unsigned char * cucp; memset(inBuff, 0, sizeof(inBuff)); for (k = 1; k < argc; ++k) { if (0 == strcmp(argv[k], "-p")) ++do_packet; else if (0 == strcmp(argv[k], "-v")) ++verbose; else if (0 == strcmp(argv[k], "-vv")) verbose += 2; else if (0 == strcmp(argv[k], "-vvv")) verbose += 3; else if (0 == strcmp(argv[k], "-V")) { fprintf(stderr, "version: %s\n", version_str); exit(0); } else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { printf("too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { usage(); return 1; } if ((sg_fd = open(file_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg__sat_identify: error opening file: %s", file_name); perror(ebuff); return 1; } /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[6] = 1; /* sector count */ aptCmdBlk[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; if (verbose) { fprintf(stderr, " ata pass through(16) cdb: "); for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k) fprintf(stderr, "%02x ", aptCmdBlk[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(aptCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = ID_RESPONSE_LEN; io_hdr.dxferp = inBuff; io_hdr.cmdp = aptCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg__sat_identify: SG_IO ioctl error"); close(sg_fd); return 1; } /* now for the error processing */ ok = 0; switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: if (verbose) sg_chk_n_print3(">>> ATA_16 command", &io_hdr, 1); /* check for ATA Return Descriptor */ cucp = sg_scsi_sense_desc_find(io_hdr.sbp, io_hdr.sb_len_wr, SAT_ATA_RETURN_DESC); if (cucp && (cucp[3])) { if (cucp[3] & 0x4) { printf("error in returned FIS: aborted command\n"); printf(" try again with%s '-p' option\n", (do_packet ? "out" : "")); break; } } ok = 1; /* not sure what is happening so output response */ if (0 == verbose) { printf(">>> Recovered error on ATA_16, may have failed\n"); printf(" Add '-v' for more information\n"); } break; default: /* won't bother decoding other categories */ sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ printf("Response for IDENTIFY %sDEVICE ATA command:\n", (do_packet ? "PACKET " : "")); dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); } close(sg_fd); return 0; } sg3_utils-1.40/examples/sg__sat_phy_event.c0000664000175000017500000003012312142450532020027 0ustar douggdougg/* * Copyright (c) 2006-2007 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" /* This program uses a ATA PASS-THROUGH (16) SCSI command defined by SAT to package an ATA READ LOG EXT (2Fh) command to fetch log page 11h. That page contains SATA phy event counters. For SAT see http://www.t10.org [draft prior to standard: sat-r09.pdf] For ATA READ LOG EXT command see ATA-8/ACS at www.t13.org . For SATA phy counter definitions see SATA 2.5 . Invocation: sg_sat_phy_event [-v] [-V] */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_RETURN_DESC 9 /* ATA Return Descriptor */ #define ATA_READ_LOG_EXT 0x2f #define SATA_PHY_EVENT_LPAGE 0x11 #define READ_LOG_EXT_RESPONSE_LEN 512 #define EBUFF_SZ 256 static const char * version_str = "1.00 20070507"; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"ignore", no_argument, 0, 'i'}, {"raw", no_argument, 0, 'r'}, {"reset", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_sat_phy_event [--help] [--hex] [--raw] [--reset] [--verbose]\n" " [--version] DEVICE\n" " where:\n" " --help|-h print this usage message then exit\n" " --hex|-H output response in hex bytes, use twice for\n" " hex words\n" " --ignore|-i ignore identifier names, output id value " "instead\n" " --raw|-r output response in binary to stdout\n" " --reset|-R reset counters (after read)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n\n" "Sends an ATA READ LOG EXT command via a SAT pass through to " "fetch\nlog page 11h which contains SATA phy event counters\n"); } struct phy_event_t { int id; const char * desc; }; static struct phy_event_t phy_event_arr[] = { {0x1, "Command failed and ICRC error bit set in Error register"}, {0x2, "R_ERR(p) response for data FIS"}, {0x3, "R_ERR(p) response for device-to-host data FIS"}, {0x4, "R_ERR(p) response for host-to-device data FIS"}, {0x5, "R_ERR(p) response for non-data FIS"}, {0x6, "R_ERR(p) response for device-to-host non-data FIS"}, {0x7, "R_ERR(p) response for host-to-device non-data FIS"}, {0x8, "Device-to-host non-data FIS retries"}, {0x9, "Transition from drive PHYRDY to drive PHYRDYn"}, {0xa, "Signature device-to-host register FISes due to COMRESET"}, {0xb, "CRC errors within host-to-device FIS"}, {0xd, "non CRC errors within host-to-device FIS"}, {0xf, "R_ERR(p) response for host-to-device data FIS, CRC"}, {0x10, "R_ERR(p) response for host-to-device data FIS, non-CRC"}, {0x12, "R_ERR(p) response for host-to-device non-data FIS, CRC"}, {0x13, "R_ERR(p) response for host-to-device non-data FIS, non-CRC"}, {0xc00, "PM: host-to-device non-data FIS, R_ERR(p) due to collision"}, {0xc01, "PM: signature register - device-to-host FISes"}, {0xc02, "PM: corrupts CRC propagation of device-to-host FISes"}, {0x0, NULL}, }; static const char * find_phy_desc(int id) { const struct phy_event_t * pep; for (pep = phy_event_arr; pep->desc; ++pep) { if ((id & 0xfff) == pep->id) return pep->desc; } return NULL; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, c, k, j, ok, res, id, len, vendor; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sg_io_hdr_t io_hdr; char * device_name = 0; char ebuff[EBUFF_SZ]; unsigned char inBuff[READ_LOG_EXT_RESPONSE_LEN]; unsigned char sense_buffer[64]; int hex = 0; int ignore = 0; int raw = 0; int reset = 0; int verbose = 0; int extend = 0; int chk_cond = 0; /* set to 1 to read register(s) back */ int protocol = 4; /* PIO data-in */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ const unsigned char * cucp; int ret = 0; uint64_t ull; const char * cp; memset(inBuff, 0, sizeof(inBuff)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHirRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': usage(); exit(0); case 'H': ++hex; break; case 'i': ++ignore; break; case 'r': ++raw; break; case 'R': ++reset; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); exit(0); default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (0 == device_name) { fprintf(stderr, "no DEVICE name detected\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((sg_fd = open(device_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_sat_phy_event: error opening file: %s", device_name); perror(ebuff); return SG_LIB_FILE_ERROR; } /* Prepare SCSI ATA PASS-THROUGH COMMAND (16) command */ if (reset > 0) aptCmdBlk[4] = 1; /* features (7:0) */ aptCmdBlk[6] = 1; /* sector count */ aptCmdBlk[8] = SATA_PHY_EVENT_LPAGE; /* lba_low (7:0) */ aptCmdBlk[14] = ATA_READ_LOG_EXT; /* command */ aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (chk_cond << 5) | (t_dir << 3) | (byte_block << 2) | t_length; if (verbose) { fprintf(stderr, " ata pass through(16) cdb: "); for (k = 0; k < SAT_ATA_PASS_THROUGH16_LEN; ++k) fprintf(stderr, "%02x ", aptCmdBlk[k]); fprintf(stderr, "\n"); } memset(&io_hdr, 0, sizeof(sg_io_hdr_t)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(aptCmdBlk); /* io_hdr.iovec_count = 0; */ /* memset takes care of this */ io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = READ_LOG_EXT_RESPONSE_LEN; io_hdr.dxferp = inBuff; io_hdr.cmdp = aptCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ /* io_hdr.flags = 0; */ /* take defaults: indirect IO, etc */ /* io_hdr.pack_id = 0; */ /* io_hdr.usr_ptr = NULL; */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("sg_sat_phy_event: SG_IO ioctl error"); close(sg_fd); return SG_LIB_CAT_OTHER; } /* now for the error processing */ ok = 0; ret = sg_err_category3(&io_hdr); switch (ret) { case SG_LIB_CAT_CLEAN: ok = 1; break; case SG_LIB_CAT_RECOVERED: if (verbose) sg_chk_n_print3(">>> ATA_16 command", &io_hdr, 1); /* check for ATA Return Descriptor */ cucp = sg_scsi_sense_desc_find(io_hdr.sbp, io_hdr.sb_len_wr, SAT_ATA_RETURN_DESC); if (cucp && (cucp[3])) { if (cucp[3] & 0x4) { fprintf(stderr, "error in returned FIS: aborted command\n"); break; } } ret = 0; ok = 1; /* not sure what is happening so output response */ if (0 == verbose) { fprintf(stderr, ">>> Recovered error on ATA_16, may have " "failed\n"); fprintf(stderr, " Add '-v' for more information\n"); } break; default: /* won't bother decoding other categories */ sg_chk_n_print3("ATA_16 command error", &io_hdr, 1); break; } if (ok) { /* output result if it is available */ if (raw > 0) dStrRaw((const char *)inBuff, 512); else { if (verbose && hex) fprintf(stderr, "Response to READ LOG EXT (page=11h):\n"); if (1 == hex) dStrHex((const char *)inBuff, 512, 0); else if (hex > 1) dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); else { printf("SATA phy event counters:\n"); for (k = 4; k < 512; k += (len + 2)) { id = (inBuff[k + 1] << 8) + inBuff[k]; if (0 == id) break; len = ((id >> 12) & 0x7) * 2; vendor = !!(id & 0x8000); id = id & 0xfff; ull = 0; for (j = len - 1; j >= 0; --j) { if (j < (len - 1)) ull <<= 8; ull |= inBuff[k + 2 + j]; } cp = NULL; if ((0 == vendor) && (0 == ignore)) cp = find_phy_desc(id); if (cp) printf(" %s: %" PRIu64 "\n", cp, ull); else printf(" id=0x%x, vendor=%d, data_len=%d, " "val=%" PRIu64 "\n", id, vendor, len, ull); } } } } res = close(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/examples/scsi_inquiry.c0000664000175000017500000001004011021562517017046 0ustar douggdougg#include #include #include #include #include #include #include #include #include #include #include /* #include */ /* glibc hides this file sometimes */ /* Test code for D. Gilbert's extensions to the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 1999 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. This program does a SCSI inquiry command on the given device and outputs some of the result. This program highlights the use of the SCSI_IOCTL_SEND_COMMAND ioctl. This should be able to be applied to any SCSI device file descriptor (not just one related to sg). [Whether this is a good idea on a disk while it is mounted is debatable. No detrimental effects when this was tested ...] Version 0.14 20011218 */ typedef struct my_scsi_ioctl_command { unsigned int inlen; /* _excluding_ scsi command length */ unsigned int outlen; unsigned char data[1]; /* was 0 but that's not ISO C!! */ /* on input, scsi command starts here then opt. data */ } My_Scsi_Ioctl_Command; #define OFF (2 * sizeof(unsigned int)) #ifndef SCSI_IOCTL_SEND_COMMAND #define SCSI_IOCTL_SEND_COMMAND 1 #endif #define INQUIRY_CMD 0x12 #define INQUIRY_CMDLEN 6 #define INQUIRY_REPLY_LEN 96 int main(int argc, char * argv[]) { int s_fd, res, k, to; unsigned char inqCmdBlk [INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, INQUIRY_REPLY_LEN, 0}; unsigned char * inqBuff = (unsigned char *) malloc(OFF + sizeof(inqCmdBlk) + 512); unsigned char * buffp = inqBuff + OFF; My_Scsi_Ioctl_Command * ishp = (My_Scsi_Ioctl_Command *)inqBuff; char * file_name = 0; int do_nonblock = 0; int oflags = 0; for (k = 1; k < argc; ++k) { if (0 == strcmp(argv[k], "-n")) do_nonblock = 1; else if (*argv[k] != '-') file_name = argv[k]; else { printf("Unrecognized argument '%s'\n", argv[k]); file_name = 0; break; } } if (0 == file_name) { printf("Usage: 'scsi_inquiry [-n] '\n"); printf(" where: -n open device in non-blocking mode\n"); printf(" Examples: scsi_inquiry /dev/sda\n"); printf(" scsi_inquiry /dev/sg0\n"); printf(" scsi_inquiry -n /dev/scd0\n"); return 1; } if (do_nonblock) oflags = O_NONBLOCK; s_fd = open(file_name, oflags | O_RDWR); if (s_fd < 0) { if ((EROFS == errno) || (EACCES == errno)) { s_fd = open(file_name, oflags | O_RDONLY); if (s_fd < 0) { perror("scsi_inquiry: open error"); return 1; } } else { perror("scsi_inquiry: open error"); return 1; } } /* Don't worry, being very careful not to write to a none-scsi file ... */ res = ioctl(s_fd, SCSI_IOCTL_GET_BUS_NUMBER, &to); if (res < 0) { /* perror("ioctl on scsi device, error"); */ printf("scsi_inquiry: not a scsi device\n"); return 1; } ishp->inlen = 0; ishp->outlen = INQUIRY_REPLY_LEN; memcpy(buffp, inqCmdBlk, INQUIRY_CMDLEN); res = ioctl(s_fd, SCSI_IOCTL_SEND_COMMAND, inqBuff); if (0 == res) { to = (int)*(buffp + 7); printf(" %.8s %.16s %.4s, byte_7=0x%x\n", buffp + 8, buffp + 16, buffp + 32, to); } else if (res < 0) perror("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND err"); else printf("scsi_inquiry: SCSI_IOCTL_SEND_COMMAND status=0x%x\n", res); res = close(s_fd); if (res < 0) { perror("scsi_inquiry: close error"); return 1; } return 0; } sg3_utils-1.40/examples/sg_tst_excl3.cpp0000664000175000017500000004653512400160337017304 0ustar douggdougg/* * Copyright (c) 2013-2014 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_pt.h" static const char * version_str = "1.05 20140828"; static const char * util_name = "sg_tst_excl3"; /* This is a test program for checking O_EXCL on open() works. It uses * multiple threads and can be run as multiple processes and attempts * to "break" O_EXCL. The strategy is to open a device O_EXCL|O_NONBLOCK * and do a double increment on a LB then close it from a single thread. * the remaining threads open that device O_NONBLOCK and do a read and * note of the number is odd. Assuming the count starts as an even * (typically 0) then it should remain even. Odd instances * are counted and reported at the end of the program, after all threads * have completed. * * This is C++ code with some things from C++11 (e.g. threads) and was * only just able to compile (when some things were reverted) with gcc/g++ * version 4.7.3 found in Ubuntu 13.04 . C++11 "feature complete" support * was not available until g++ version 4.8.1 and that is found in Fedora * 19 and Ubuntu 13.10 . * * The build uses various object files from the /lib directory * which is assumed to be a sibling of this examples directory. Those * object files in the lib directory can be built with: * cd ; ./configure ; cd lib; make * Then to build sg_tst_excl3 concatenate the next 3 lines: * g++ -Wall -std=c++11 -pthread -I ../include ../lib/sg_lib.o * ../lib/sg_lib_data.o ../lib/sg_pt_linux.o -o sg_tst_excl3 * sg_tst_excl3.cpp * Alternatively use 'make -f Makefile.cplus sg_tst_excl3' * * BEWARE: this utility modifies a logical block (default LBA 1000) on the * given device. * * Test breaks sg driver in lk 3.10.4 but works with proposed fix so should * work soon thereafter. It works on standard block driver (e.g. /dev/sdc) * in lk 3.10.4 (most of the time). It fails on bsg driver in lk 3.10.4 * because it ignores the O_EXCL flag (and that is unlikely to change in * the short term). * */ using namespace std; using namespace std::chrono; #define DEF_NUM_PER_THREAD 200 #define DEF_NUM_THREADS 4 #define DEF_WAIT_MS 0 /* 0: yield; -1: don't wait; -2: sleep(0) */ #define DEF_LBA 1000 #define EBUFF_SZ 256 static mutex odd_count_mutex; static mutex console_mutex; static unsigned int odd_count; static unsigned int ebusy_count; static void usage(void) { printf("Usage: %s [-b] [-f] [-h] [-l ] [-n ]\n" " [-R] [-t ] [-V] [-w ] " "[-x]\n" " \n", util_name); printf(" where\n"); printf(" -b block on open (def: O_NONBLOCK)\n"); printf(" -f force: any SCSI disk (def: only " "scsi_debug)\n"); printf(" WARNING: written to\n"); printf(" -h print this usage message then exit\n"); printf(" -l logical block to increment (def: %u)\n", DEF_LBA); printf(" -n number of loops per thread " "(def: %d)\n", DEF_NUM_PER_THREAD); printf(" -R all readers; so first thread (id=0) " "just reads\n"); printf(" -t number of threads (def: %d)\n", DEF_NUM_THREADS); printf(" -V print version number then exit\n"); printf(" -w >0: sleep_for(); =0: " "yield(); -1: no\n" " wait; -2: sleep(0) (def: %d)\n", DEF_WAIT_MS); printf(" -x don't use O_EXCL on first thread " "(def: use\n" " O_EXCL on first thread)\n\n"); printf("Test O_EXCL open flag with pass-through drivers. First thread " "(id=0) does\nopen/close cycle with the O_EXCL flag then does a " "double increment on\nlba (using its first 4 bytes). Remaining " "theads read (without\nO_EXCL flag on open) and check the " "value is even.\n"); } /* Assumed a lock (mutex) held when pt_err() is called */ static int pt_err(int res) { if (res < 0) fprintf(stderr, " pass through os error: %s\n", safe_strerror(-res)); else if (SCSI_PT_DO_BAD_PARAMS == res) fprintf(stderr, " bad pass through setup\n"); else if (SCSI_PT_DO_TIMEOUT == res) fprintf(stderr, " pass through timeout\n"); else fprintf(stderr, " do_scsi_pt error=%d\n", res); return -1; } /* Assumed a lock (mutex) held when pt_cat_no_good() is called */ static int pt_cat_no_good(int cat, struct sg_pt_base * ptp, const unsigned char * sbp) { int slen; char b[256]; const int bl = (int)sizeof(b); switch (cat) { case SCSI_PT_RESULT_STATUS: /* other than GOOD and CHECK CONDITION */ sg_get_scsi_status_str(get_scsi_pt_status_response(ptp), bl, b); fprintf(stderr, " scsi status: %s\n", b); break; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptp); sg_get_sense_str("", sbp, slen, 1, bl, b); fprintf(stderr, "%s", b); break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptp, bl, b); fprintf(stderr, " transport: %s", b); break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptp, bl, b); fprintf(stderr, " os: %s", b); break; default: fprintf(stderr, " unknown pt result category (%d)\n", cat); break; } return -1; } #define READ16_REPLY_LEN 512 #define READ16_CMD_LEN 16 #define WRITE16_REPLY_LEN 512 #define WRITE16_CMD_LEN 16 /* Opens dev_name and spins if busy (i.e. gets EBUSY), sleeping for * wait_ms milliseconds if wait_ms is positive. Reads lba and treats the * first 4 bytes as an int (SCSI endian), increments it and writes it back. * Repeats so that happens twice. Then closes dev_name. If an error occurs * returns -1 else returns 0 if first int read is even otherwise returns 1. */ static int do_rd_inc_wr_twice(const char * dev_name, int read_only, unsigned int lba, int block, int excl, int wait_ms, unsigned int & ebusys) { int k, sg_fd, res, cat; int odd = 0; unsigned int u = 0; struct sg_pt_base * ptp = NULL; unsigned char r16CmdBlk [READ16_CMD_LEN] = {0x88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char w16CmdBlk [WRITE16_CMD_LEN] = {0x8a, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}; unsigned char sense_buffer[64]; unsigned char lb[READ16_REPLY_LEN]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; r16CmdBlk[6] = w16CmdBlk[6] = (lba >> 24) & 0xff; r16CmdBlk[7] = w16CmdBlk[7] = (lba >> 16) & 0xff; r16CmdBlk[8] = w16CmdBlk[8] = (lba >> 8) & 0xff; r16CmdBlk[9] = w16CmdBlk[9] = lba & 0xff; if (! block) open_flags |= O_NONBLOCK; if (excl) open_flags |= O_EXCL; while (((sg_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == sg_fd)) { ++ebusys; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_rd_inc_wr_twice: error opening file: %s", dev_name); { lock_guard lg(console_mutex); perror(ebuff); } return -1; } ptp = construct_scsi_pt_obj(); for (k = 0; k < 2; ++k) { /* Prepare READ_16 command */ clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, r16CmdBlk, sizeof(r16CmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_in(ptp, lb, READ16_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "READ_16 do_scsi_pt() submission error\n"); res = pt_err(res); } goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { { lock_guard lg(console_mutex); fprintf(stderr, "READ_16 do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); } goto err; } u = (lb[0] << 24) + (lb[1] << 16) + (lb[2] << 8) + lb[3]; // Assuming u starts test as even (probably 0), expect it to stay even if (0 == k) odd = (1 == (u % 2)); if (wait_ms > 0) /* allow daylight for bad things ... */ this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? if (read_only) break; ++u; lb[0] = (u >> 24) & 0xff; lb[1] = (u >> 16) & 0xff; lb[2] = (u >> 8) & 0xff; lb[3] = u & 0xff; /* Prepare WRITE_16 command */ clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, w16CmdBlk, sizeof(w16CmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_out(ptp, lb, WRITE16_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { { lock_guard lg(console_mutex); fprintf(stderr, "WRITE_16 do_scsi_pt() submission error\n"); res = pt_err(res); } goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { { lock_guard lg(console_mutex); fprintf(stderr, "WRITE_16 do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); } goto err; } } err: if (ptp) destruct_scsi_pt_obj(ptp); scsi_pt_close_device(sg_fd); return odd; } #define INQ_REPLY_LEN 96 #define INQ_CMD_LEN 6 /* Send INQUIRY and fetches response. If okay puts PRODUCT ID field * in b (up to m_blen bytes). Does not use O_EXCL flag. Returns 0 on success, * else -1 . */ static int do_inquiry_prod_id(const char * dev_name, int block, int wait_ms, unsigned int & ebusys, char * b, int b_mlen) { int sg_fd, res, cat; struct sg_pt_base * ptp = NULL; unsigned char inqCmdBlk [INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; unsigned char inqBuff[INQ_REPLY_LEN]; unsigned char sense_buffer[64]; char ebuff[EBUFF_SZ]; int open_flags = O_RDWR; /* since O_EXCL | O_RDONLY gives EPERM */ if (! block) open_flags |= O_NONBLOCK; while (((sg_fd = scsi_pt_open_flags(dev_name, open_flags, 0)) < 0) && (-EBUSY == sg_fd)) { ++ebusys; if (wait_ms > 0) this_thread::sleep_for(milliseconds{wait_ms}); else if (0 == wait_ms) this_thread::yield(); // thread yield else if (-2 == wait_ms) sleep(0); // process yield ?? } if (sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, "do_inquiry_prod_id: error opening file: %s", dev_name); perror(ebuff); return -1; } /* Prepare INQUIRY command */ ptp = construct_scsi_pt_obj(); clear_scsi_pt_obj(ptp); set_scsi_pt_cdb(ptp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptp, sense_buffer, sizeof(sense_buffer)); set_scsi_pt_data_in(ptp, inqBuff, INQ_REPLY_LEN); res = do_scsi_pt(ptp, sg_fd, 20 /* secs timeout */, 1); if (res) { fprintf(stderr, "INQUIRY do_scsi_pt() submission error\n"); res = pt_err(res); goto err; } cat = get_scsi_pt_result_category(ptp); if (SCSI_PT_RESULT_GOOD != cat) { fprintf(stderr, "INQUIRY do_scsi_pt() category problem\n"); res = pt_cat_no_good(cat, ptp, sense_buffer); goto err; } /* Good, so fetch Product ID from response, copy to 'b' */ if (b_mlen > 0) { if (b_mlen > 16) { memcpy(b, inqBuff + 16, 16); b[16] = '\0'; } else { memcpy(b, inqBuff + 16, b_mlen - 1); b[b_mlen - 1] = '\0'; } } err: if (ptp) destruct_scsi_pt_obj(ptp); close(sg_fd); return res; } static void work_thread(const char * dev_name, unsigned int lba, int id, int block, int excl, bool all_readers, int num, int wait_ms) { unsigned int thr_odd_count = 0; unsigned int thr_ebusy_count = 0; int k, res; int reader = ((id > 0) || (all_readers)); { lock_guard lg(console_mutex); cerr << "Enter work_thread id=" << id << " excl=" << excl << " block=" << block << " reader=" << reader << endl; } for (k = 0; k < num; ++k) { res = do_rd_inc_wr_twice(dev_name, reader, lba, block, excl, wait_ms, thr_ebusy_count); if (res < 0) break; if (res) ++thr_odd_count; } { lock_guard lg(console_mutex); if (k < num) cerr << "thread id=" << id << " FAILed at iteration: " << k << '\n'; else cerr << "thread id=" << id << " normal exit" << '\n'; } { lock_guard lg(odd_count_mutex); odd_count += thr_odd_count; ebusy_count += thr_ebusy_count; } } int main(int argc, char * argv[]) { int k, res; int block = 0; int force = 0; unsigned int lba = DEF_LBA; int num_per_thread = DEF_NUM_PER_THREAD; bool all_readers = false; int num_threads = DEF_NUM_THREADS; int wait_ms = DEF_WAIT_MS; int exclude_o_excl = 0; char * dev_name = NULL; char b[64]; for (k = 1; k < argc; ++k) { if (0 == memcmp("-b", argv[k], 2)) ++block; else if (0 == memcmp("-f", argv[k], 2)) ++force; else if (0 == memcmp("-h", argv[k], 2)) { usage(); return 0; } else if (0 == memcmp("-l", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) lba = (unsigned int)atoi(argv[k]); else break; } else if (0 == memcmp("-n", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_per_thread = atoi(argv[k]); else break; } else if (0 == memcmp("-t", argv[k], 2)) { ++k; if ((k < argc) && isdigit(*argv[k])) num_threads = atoi(argv[k]); else break; } else if (0 == memcmp("-R", argv[k], 2)) all_readers = true; else if (0 == memcmp("-V", argv[k], 2)) { printf("%s version: %s\n", util_name, version_str); return 0; } else if (0 == memcmp("-w", argv[k], 2)) { ++k; if ((k < argc) && (isdigit(*argv[k]) || ('-' == *argv[k]))) { if ('-' == *argv[k]) wait_ms = - atoi(argv[k] + 1); else wait_ms = atoi(argv[k]); } else break; } else if (0 == memcmp("-x", argv[k], 2)) ++exclude_o_excl; else if (*argv[k] == '-') { printf("Unrecognized switch: %s\n", argv[k]); dev_name = NULL; break; } else if (! dev_name) dev_name = argv[k]; else { printf("too many arguments\n"); dev_name = 0; break; } } if (0 == dev_name) { usage(); return 1; } try { if (! force) { res = do_inquiry_prod_id(dev_name, block, wait_ms, ebusy_count, b, sizeof(b)); if (res) { fprintf(stderr, "INQUIRY failed on %s\n", dev_name); return 1; } // For safety, since written to, only permit scsi_debug // devices. Bypass this with '-f' option. if (0 != memcmp("scsi_debug", b, 10)) { fprintf(stderr, "Since this utility writes to LBA %d, only " "devices with scsi_debug\nproduct ID accepted.\n", lba); return 2; } } vector vt; for (k = 0; k < num_threads; ++k) { int excl = ((0 == k) && (! exclude_o_excl)) ? 1 : 0; thread * tp = new thread {work_thread, dev_name, lba, k, block, excl, all_readers, num_per_thread, wait_ms}; vt.push_back(tp); } for (k = 0; k < (int)vt.size(); ++k) vt[k]->join(); for (k = 0; k < (int)vt.size(); ++k) delete vt[k]; cout << "Expecting odd count of 0, got " << odd_count << endl; cout << "Number of EBUSYs: " << ebusy_count << endl; } catch(system_error& e) { cerr << "got a system_error exception: " << e.what() << '\n'; auto ec = e.code(); cerr << "category: " << ec.category().name() << '\n'; cerr << "value: " << ec.value() << '\n'; cerr << "message: " << ec.message() << '\n'; cerr << "\nNote: if g++ may need '-pthread' or similar in " "compile/link line" << '\n'; } catch(...) { cerr << "got another exception: " << '\n'; } return 0; } sg3_utils-1.40/aclocal.m40000664000175000017500000126263712335161436014235 0ustar douggdougg# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool 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 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) case `/usr/bin/file conftest.o` in *x86-64*) LD="${LD-ld} -m elf32_x86_64" ;; *) LD="${LD-ld} -m elf_i386" ;; esac ;; powerpc64le-*) LD="${LD-ld} -m elf32lppclinux" ;; powerpc64-*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; powerpcle-*) LD="${LD-ld} -m elf64lppc" ;; powerpc-*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len" && \ test undefined != "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless 'enable' is passed literally. # For symmetry, 'disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode], am_maintainer_other[ make rules and dependencies not useful (and sometimes confusing) to the casual installer])], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # -*- Autoconf -*- # Obsolete and "removed" macros, that must however still report explicit # error messages when used, to smooth transition. # # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. AC_DEFUN([AM_CONFIG_HEADER], [AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl AC_CONFIG_HEADERS($@)]) AC_DEFUN([AM_PROG_CC_STDC], [AC_PROG_CC am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should simply use the 'AC][_PROG_CC' macro instead. Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', but upon 'ac_cv_prog_cc_stdc'.])]) AC_DEFUN([AM_C_PROTOTYPES], [AC_FATAL([automatic de-ANSI-fication support has been removed])]) AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR sg3_utils-1.40/config.guess0000775000175000017500000013036112234470316014676 0ustar douggdougg#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2013 Free Software Foundation, Inc. timestamp='2013-06-10' # This file 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 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; or1k:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: sg3_utils-1.40/include/0000755000175000017500000000000012431015530013763 5ustar douggdouggsg3_utils-1.40/include/Makefile.am0000664000175000017500000000142212156455364016041 0ustar douggdougg scsiincludedir = $(includedir)/scsi scsiinclude_HEADERS = \ sg_lib.h \ sg_lib_data.h \ sg_cmds.h \ sg_cmds_basic.h \ sg_cmds_extra.h \ sg_cmds_mmc.h \ sg_pt.h if OS_LINUX scsiinclude_HEADERS += \ sg_linux_inc.h \ sg_io_linux.h noinst_HEADERS = \ sg_pt_win32.h endif if OS_WIN32_MINGW scsiinclude_HEADERS += sg_pt_win32.h noinst_HEADERS = \ sg_linux_inc.h \ sg_io_linux.h endif if OS_WIN32_CYGWIN scsiinclude_HEADERS += sg_pt_win32.h noinst_HEADERS = \ sg_linux_inc.h \ sg_io_linux.h endif if OS_FREEBSD noinst_HEADERS = \ sg_linux_inc.h \ sg_io_linux.h \ sg_pt_win32.h endif if OS_SOLARIS noinst_HEADERS = \ sg_linux_inc.h \ sg_io_linux.h \ sg_pt_win32.h endif if OS_OSF noinst_HEADERS = \ sg_linux_inc.h \ sg_io_linux.h \ sg_pt_win32.h endif sg3_utils-1.40/include/sg_pt_win32.h0000664000175000017500000001107612061626602016310 0ustar douggdougg#ifndef SG_PT_WIN32_H #define SG_PT_WIN32_H /* * The information in this file was obtained from scsi-wnt.h by * Richard Stemmer, rs@epost.de . He in turn gives credit to * Jay A. Key (for scsipt.c). * The plscsi program (by Pat LaVarre ) has * also been used as a reference. * Much of the information in this header can also be obtained * from msdn.microsoft.com . * Updated for cygwin version 1.7.17 changes 20121026 */ #include #define SCSI_MAX_SENSE_LEN 64 #define SCSI_MAX_CDB_LEN 16 #define SCSI_MAX_INDIRECT_DATA 16384 typedef struct { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; ULONG_PTR DataBufferOffset; /* was ULONG; problem in 64 bit */ ULONG SenseInfoOffset; UCHAR Cdb[SCSI_MAX_CDB_LEN]; } SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH; typedef struct { USHORT Length; UCHAR ScsiStatus; UCHAR PathId; UCHAR TargetId; UCHAR Lun; UCHAR CdbLength; UCHAR SenseInfoLength; UCHAR DataIn; ULONG DataTransferLength; ULONG TimeOutValue; PVOID DataBuffer; ULONG SenseInfoOffset; UCHAR Cdb[SCSI_MAX_CDB_LEN]; } SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT; typedef struct { SCSI_PASS_THROUGH spt; /* plscsi shows a follow on 16 bytes allowing 32 byte cdb */ ULONG Filler; UCHAR ucSenseBuf[SCSI_MAX_SENSE_LEN]; UCHAR ucDataBuf[SCSI_MAX_INDIRECT_DATA]; } SCSI_PASS_THROUGH_WITH_BUFFERS, *PSCSI_PASS_THROUGH_WITH_BUFFERS; typedef struct { SCSI_PASS_THROUGH_DIRECT spt; ULONG Filler; UCHAR ucSenseBuf[SCSI_MAX_SENSE_LEN]; } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, *PSCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; typedef struct { UCHAR NumberOfLogicalUnits; UCHAR InitiatorBusId; ULONG InquiryDataOffset; } SCSI_BUS_DATA, *PSCSI_BUS_DATA; typedef struct { UCHAR NumberOfBusses; SCSI_BUS_DATA BusData[1]; } SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO; typedef struct { UCHAR PathId; UCHAR TargetId; UCHAR Lun; BOOLEAN DeviceClaimed; ULONG InquiryDataLength; ULONG NextInquiryDataOffset; UCHAR InquiryData[1]; } SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA; typedef struct { ULONG Length; UCHAR PortNumber; UCHAR PathId; UCHAR TargetId; UCHAR Lun; } SCSI_ADDRESS, *PSCSI_ADDRESS; /* * method codes */ #define METHOD_BUFFERED 0 #define METHOD_IN_DIRECT 1 #define METHOD_OUT_DIRECT 2 #define METHOD_NEITHER 3 /* * file access values */ #define FILE_ANY_ACCESS 0 #ifndef FILE_READ_ACCESS #define FILE_READ_ACCESS 0x0001 #endif #ifndef FILE_WRITE_ACCESS #define FILE_WRITE_ACCESS 0x0002 #endif #define IOCTL_SCSI_BASE 0x00000004 /* * constants for DataIn member of SCSI_PASS_THROUGH* structures */ #define SCSI_IOCTL_DATA_OUT 0 #define SCSI_IOCTL_DATA_IN 1 #define SCSI_IOCTL_DATA_UNSPECIFIED 2 /* * Standard IOCTL define */ #ifndef CTL_CODE #define CTL_CODE(DevType, Function, Method, Access) \ (((DevType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) #endif #define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, \ METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, \ METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, \ METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, \ METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, \ METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS) #define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, \ METHOD_BUFFERED, FILE_ANY_ACCESS) #endif sg3_utils-1.40/include/Makefile.in0000664000175000017500000004210012401205666016037 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @OS_LINUX_TRUE@am__append_1 = \ @OS_LINUX_TRUE@ sg_linux_inc.h \ @OS_LINUX_TRUE@ sg_io_linux.h @OS_WIN32_MINGW_TRUE@am__append_2 = sg_pt_win32.h @OS_WIN32_CYGWIN_TRUE@am__append_3 = sg_pt_win32.h subdir = include DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(am__noinst_HEADERS_DIST) $(am__scsiinclude_HEADERS_DIST) ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__noinst_HEADERS_DIST = sg_linux_inc.h sg_io_linux.h sg_pt_win32.h am__scsiinclude_HEADERS_DIST = sg_lib.h sg_lib_data.h sg_cmds.h \ sg_cmds_basic.h sg_cmds_extra.h sg_cmds_mmc.h sg_pt.h \ sg_linux_inc.h sg_io_linux.h sg_pt_win32.h am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(scsiincludedir)" HEADERS = $(noinst_HEADERS) $(scsiinclude_HEADERS) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ scsiincludedir = $(includedir)/scsi scsiinclude_HEADERS = sg_lib.h sg_lib_data.h sg_cmds.h sg_cmds_basic.h \ sg_cmds_extra.h sg_cmds_mmc.h sg_pt.h $(am__append_1) \ $(am__append_2) $(am__append_3) @OS_FREEBSD_TRUE@noinst_HEADERS = \ @OS_FREEBSD_TRUE@ sg_linux_inc.h \ @OS_FREEBSD_TRUE@ sg_io_linux.h \ @OS_FREEBSD_TRUE@ sg_pt_win32.h @OS_LINUX_TRUE@noinst_HEADERS = \ @OS_LINUX_TRUE@ sg_pt_win32.h @OS_OSF_TRUE@noinst_HEADERS = \ @OS_OSF_TRUE@ sg_linux_inc.h \ @OS_OSF_TRUE@ sg_io_linux.h \ @OS_OSF_TRUE@ sg_pt_win32.h @OS_SOLARIS_TRUE@noinst_HEADERS = \ @OS_SOLARIS_TRUE@ sg_linux_inc.h \ @OS_SOLARIS_TRUE@ sg_io_linux.h \ @OS_SOLARIS_TRUE@ sg_pt_win32.h @OS_WIN32_CYGWIN_TRUE@noinst_HEADERS = \ @OS_WIN32_CYGWIN_TRUE@ sg_linux_inc.h \ @OS_WIN32_CYGWIN_TRUE@ sg_io_linux.h @OS_WIN32_MINGW_TRUE@noinst_HEADERS = \ @OS_WIN32_MINGW_TRUE@ sg_linux_inc.h \ @OS_WIN32_MINGW_TRUE@ sg_io_linux.h all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu include/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs install-scsiincludeHEADERS: $(scsiinclude_HEADERS) @$(NORMAL_INSTALL) @list='$(scsiinclude_HEADERS)'; test -n "$(scsiincludedir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(scsiincludedir)'"; \ $(MKDIR_P) "$(DESTDIR)$(scsiincludedir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(scsiincludedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(scsiincludedir)" || exit $$?; \ done uninstall-scsiincludeHEADERS: @$(NORMAL_UNINSTALL) @list='$(scsiinclude_HEADERS)'; test -n "$(scsiincludedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(scsiincludedir)'; $(am__uninstall_files_from_dir) ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(HEADERS) installdirs: for dir in "$(DESTDIR)$(scsiincludedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-scsiincludeHEADERS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-scsiincludeHEADERS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ clean-libtool cscopelist-am ctags ctags-am distclean \ distclean-generic distclean-libtool distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-data install-data-am install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am \ install-scsiincludeHEADERS install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ uninstall-am uninstall-scsiincludeHEADERS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/include/sg_lib.h0000664000175000017500000004652312335161436015421 0ustar douggdougg#ifndef SG_LIB_H #define SG_LIB_H /* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * * On 5th October 2004 a FreeBSD license was added to this file. * The intention is to keep this file and the related sg_lib.c file * as open source and encourage their unencumbered use. * * Current version number is in the sg_lib.c file and can be accessed * with the sg_lib_version() function. */ /* * This header file contains defines and function declarations that may * be useful to applications that communicate with devices that use a * SCSI command set. These command sets have names like SPC-4, SBC-3, * SSC-3, SES-2 and draft standards defining them can be found at * http://www.t10.org . Virtually all devices in the Linux SCSI subsystem * utilize SCSI command sets. Many devices in other Linux device subsystems * utilize SCSI command sets either natively or via emulation (e.g. a * parallel ATA disk in a USB enclosure). */ #include #include #ifdef __cplusplus extern "C" { #endif /* SCSI Peripheral Device Types (PDT) [5 bit field] */ #define PDT_DISK 0x0 /* direct access block device (disk) */ #define PDT_TAPE 0x1 /* sequential access device (magnetic tape) */ #define PDT_PRINTER 0x2 /* printer device (see SSC-1) */ #define PDT_PROCESSOR 0x3 /* processor device (e.g. SAFTE device) */ #define PDT_WO 0x4 /* write once device (some optical disks) */ #define PDT_MMC 0x5 /* CD/DVD/BD (multi-media) */ #define PDT_SCANNER 0x6 /* obsolete */ #define PDT_OPTICAL 0x7 /* optical memory device (some optical disks) */ #define PDT_MCHANGER 0x8 /* media changer device (e.g. tape robot) */ #define PDT_COMMS 0x9 /* communications device (obsolete) */ #define PDT_SAC 0xc /* storage array controller device */ #define PDT_SES 0xd /* SCSI Enclosure Services (SES) device */ #define PDT_RBC 0xe /* Reduced Block Commands (simplified PDT_DISK) */ #define PDT_OCRW 0xf /* optical card read/write device */ #define PDT_BCC 0x10 /* bridge controller commands */ #define PDT_OSD 0x11 /* Object Storage Device (OSD) */ #define PDT_ADC 0x12 /* Automation/drive commands (ADC) */ #define PDT_SMD 0x13 /* Security Manager Device (SMD) */ #define PDT_ZBC 0x14 /* Zoned Block Commands (ZBC) */ #define PDT_WLUN 0x1e /* Well known logical unit (WLUN) */ #define PDT_UNKNOWN 0x1f /* Unknown or no device type */ #ifndef SAM_STAT_GOOD /* The SCSI status codes as found in SAM-4 at www.t10.org */ #define SAM_STAT_GOOD 0x0 #define SAM_STAT_CHECK_CONDITION 0x2 #define SAM_STAT_CONDITION_MET 0x4 #define SAM_STAT_BUSY 0x8 #define SAM_STAT_INTERMEDIATE 0x10 /* obsolete in SAM-4 */ #define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 /* obsolete in SAM-4 */ #define SAM_STAT_RESERVATION_CONFLICT 0x18 #define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */ #define SAM_STAT_TASK_SET_FULL 0x28 #define SAM_STAT_ACA_ACTIVE 0x30 #define SAM_STAT_TASK_ABORTED 0x40 #endif /* The SCSI sense key codes as found in SPC-4 at www.t10.org */ #define SPC_SK_NO_SENSE 0x0 #define SPC_SK_RECOVERED_ERROR 0x1 #define SPC_SK_NOT_READY 0x2 #define SPC_SK_MEDIUM_ERROR 0x3 #define SPC_SK_HARDWARE_ERROR 0x4 #define SPC_SK_ILLEGAL_REQUEST 0x5 #define SPC_SK_UNIT_ATTENTION 0x6 #define SPC_SK_DATA_PROTECT 0x7 #define SPC_SK_BLANK_CHECK 0x8 #define SPC_SK_VENDOR_SPECIFIC 0x9 #define SPC_SK_COPY_ABORTED 0xa #define SPC_SK_ABORTED_COMMAND 0xb #define SPC_SK_RESERVED 0xc #define SPC_SK_VOLUME_OVERFLOW 0xd #define SPC_SK_MISCOMPARE 0xe #define SPC_SK_COMPLETED 0xf /* Transport protocol identifiers or just Protocol identifiers */ #define TPROTO_FCP 0 #define TPROTO_SPI 1 #define TPROTO_SSA 2 #define TPROTO_1394 3 #define TPROTO_SRP 4 #define TPROTO_ISCSI 5 #define TPROTO_SAS 6 #define TPROTO_ADT 7 #define TPROTO_ATA 8 #define TPROTO_UAS 9 /* USB attached SCSI */ #define TPROTO_SOP 0xa /* SCSI over PCIe */ #define TPROTO_NONE 0xf /* The format of the version string is like this: "1.87 20130731" */ const char * sg_lib_version(); /* Returns length of SCSI command given the opcode (first byte). * Yields the wrong answer for variable length commands (opcode=0x7f) * and potentially some vendor specific commands. */ int sg_get_command_size(unsigned char cdb_byte0); /* Command name given pointer to the cdb. Certain command names * depend on peripheral type (give 0 if unknown). Places command * name into buff and will write no more than buff_len bytes. */ void sg_get_command_name(const unsigned char * cdbp, int peri_type, int buff_len, char * buff); /* Command name given only the first byte (byte 0) of a cdb and * peripheral type. */ void sg_get_opcode_name(unsigned char cdb_byte0, int peri_type, int buff_len, char * buff); /* Command name given opcode (byte 0), service action and peripheral type. * If no service action give 0, if unknown peripheral type give 0. */ void sg_get_opcode_sa_name(unsigned char cdb_byte0, int service_action, int peri_type, int buff_len, char * buff); /* Fetch scsi status string. */ void sg_get_scsi_status_str(int scsi_status, int buff_len, char * buff); /* This is a slightly stretched SCSI sense "descriptor" format header. * The addition is to allow the 0x70 and 0x71 response codes. The idea * is to place the salient data of both "fixed" and "descriptor" sense * format into one structure to ease application processing. * The original sense buffer should be kept around for those cases * in which more information is required (e.g. the LBA of a MEDIUM ERROR). */ struct sg_scsi_sense_hdr { unsigned char response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */ unsigned char sense_key; unsigned char asc; unsigned char ascq; unsigned char byte4; unsigned char byte5; unsigned char byte6; unsigned char additional_length; }; /* Maps the salient data from a sense buffer which is in either fixed or * descriptor format into a structure mimicking a descriptor format * header (i.e. the first 8 bytes of sense descriptor format). * If zero response code returns 0. Otherwise returns 1 and if 'sshp' is * non-NULL then zero all fields and then set the appropriate fields in * that structure. sshp::additional_length is always 0 for response * codes 0x70 and 0x71 (fixed format). */ int sg_scsi_normalize_sense(const unsigned char * sensep, int sense_len, struct sg_scsi_sense_hdr * sshp); /* Attempt to find the first SCSI sense data descriptor that matches the * given 'desc_type'. If found return pointer to start of sense data * descriptor; otherwise (including fixed format sense data) returns NULL. */ const unsigned char * sg_scsi_sense_desc_find(const unsigned char * sensep, int sense_len, int desc_type); /* Get sense key from sense buffer. If successful returns a sense key value * between 0 and 15. If sense buffer cannot be decode, returns -1 . */ int sg_get_sense_key(const unsigned char * sensep, int sense_len); /* Yield string associated with sense_key value. Returns 'buff'. */ char * sg_get_sense_key_str(int sense_key, int buff_len, char * buff); /* Yield string associated with ASC/ASCQ values. Returns 'buff'. */ char * sg_get_asc_ascq_str(int asc, int ascq, int buff_len, char * buff); /* Returns 1 if valid bit set, 0 if valid bit clear. Irrespective the * information field is written out via 'info_outp' (except when it is * NULL). Handles both fixed and descriptor sense formats. */ int sg_get_sense_info_fld(const unsigned char * sensep, int sb_len, uint64_t * info_outp); /* Returns 1 if any of the 3 bits (i.e. FILEMARK, EOM or ILI) are set. * In descriptor format if the stream commands descriptor not found * then returns 0. Writes 1 or 0 corresponding to these bits to the * last three arguments if they are non-NULL. */ int sg_get_sense_filemark_eom_ili(const unsigned char * sensep, int sb_len, int * filemark_p, int * eom_p, int * ili_p); /* Returns 1 if SKSV is set and sense key is NO_SENSE or NOT_READY. Also * returns 1 if progress indication sense data descriptor found. Places * progress field from sense data where progress_outp points. If progress * field is not available returns 0. Handles both fixed and descriptor * sense formats. N.B. App should multiply by 100 and divide by 65536 * to get percentage completion from given value. */ int sg_get_sense_progress_fld(const unsigned char * sensep, int sb_len, int * progress_outp); /* Closely related to sg_print_sense(). Puts decoded sense data in 'buff'. * Usually multiline with multiple '\n' including one trailing. If * 'raw_sinfo' set appends sense buffer in hex. */ void sg_get_sense_str(const char * leadin, const unsigned char * sense_buffer, int sb_len, int raw_sinfo, int buff_len, char * buff); /* Yield string associated with peripheral device type (pdt). Returns * 'buff'. If 'pdt' out of range yields "bad pdt" string. */ char * sg_get_pdt_str(int pdt, int buff_len, char * buff); /* Yield string associated with transport protocol identifier (tpi). Returns * 'buff'. If 'tpi' out of range yields "bad tpi" string. */ char * sg_get_trans_proto_str(int tpi, int buff_len, char * buff); extern FILE * sg_warnings_strm; void sg_set_warnings_strm(FILE * warnings_strm); /* The following "print" functions send ACSII to 'sg_warnings_strm' file * descriptor (default value is stderr) */ void sg_print_command(const unsigned char * command); void sg_print_sense(const char * leadin, const unsigned char * sense_buffer, int sb_len, int raw_info); void sg_print_scsi_status(int scsi_status); /* Utilities can use these exit status values for syntax errors and * file (device node) problems (e.g. not found or permissions). */ #define SG_LIB_SYNTAX_ERROR 1 /* command line syntax problem */ #define SG_LIB_FILE_ERROR 15 /* device or other file problem */ /* The sg_err_category_sense() function returns one of the following. * These may be used as exit status values (from a process). Notice that * some of the lower values correspond to SCSI sense key values. */ #define SG_LIB_CAT_CLEAN 0 /* No errors or other information */ /* Value 1 left unused for utilities to use SG_LIB_SYNTAX_ERROR */ #define SG_LIB_CAT_NOT_READY 2 /* sense key, unit stopped? */ /* [sk,asc,ascq: 0x2,*,*] */ #define SG_LIB_CAT_MEDIUM_HARD 3 /* medium or hardware error, blank check */ /* [sk,asc,ascq: 0x3/0x4/0x8,*,*] */ #define SG_LIB_CAT_ILLEGAL_REQ 5 /* Illegal request (other than invalid */ /* opcode): [sk,asc,ascq: 0x5,*,*] */ #define SG_LIB_CAT_UNIT_ATTENTION 6 /* sense key, device state changed */ /* [sk,asc,ascq: 0x6,*,*] */ /* was SG_LIB_CAT_MEDIA_CHANGED earlier [sk,asc,ascq: 0x6,0x28,*] */ #define SG_LIB_CAT_DATA_PROTECT 7 /* sense key, media write protected? */ /* [sk,asc,ascq: 0x7,*,*] */ #define SG_LIB_CAT_INVALID_OP 9 /* (Illegal request,) Invalid opcode: */ /* [sk,asc,ascq: 0x5,0x20,0x0] */ #define SG_LIB_CAT_COPY_ABORTED 10 /* sense key, some data transferred */ /* [sk,asc,ascq: 0xa,*,*] */ #define SG_LIB_CAT_ABORTED_COMMAND 11 /* interpreted from sense buffer */ /* [sk,asc,ascq: 0xb,! 0x10,*] */ #define SG_LIB_CAT_MISCOMPARE 14 /* sense key, probably verify */ /* [sk,asc,ascq: 0xe,*,*] */ #define SG_LIB_CAT_NO_SENSE 20 /* sense data with key of "no sense" */ /* [sk,asc,ascq: 0x0,*,*] */ #define SG_LIB_CAT_RECOVERED 21 /* Successful command after recovered err */ /* [sk,asc,ascq: 0x1,*,*] */ #define SG_LIB_CAT_RES_CONFLICT SAM_STAT_RESERVATION_CONFLICT /* 24: this is a SCSI status, not sense. */ /* It indicates reservation by another */ /* machine blocks this command */ #define SG_LIB_CAT_PROTECTION 40 /* subset of aborted command (for PI, DIF) */ /* [sk,asc,ascq: 0xb,0x10,*] */ #define SG_LIB_CAT_MALFORMED 97 /* Response to SCSI command malformed */ #define SG_LIB_CAT_SENSE 98 /* Something else is in the sense buffer */ #define SG_LIB_CAT_OTHER 99 /* Some other error/warning has occurred */ /* (e.g. a transport or driver error) */ /* Returns a SG_LIB_CAT_* value. If cannot decode sense_buffer or a less * common sense key then return SG_LIB_CAT_SENSE .*/ int sg_err_category_sense(const unsigned char * sense_buffer, int sb_len); /* Here are some additional sense data categories that are not returned * by sg_err_category_sense() but are returned by some related functions. */ #define SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO 17 /* Illegal request (other than */ /* invalid opcode) plus 'info' field: */ /* [sk,asc,ascq: 0x5,*,*] */ #define SG_LIB_CAT_MEDIUM_HARD_WITH_INFO 18 /* medium or hardware error */ /* sense key plus 'info' field: */ /* [sk,asc,ascq: 0x3/0x4,*,*] */ #define SG_LIB_CAT_PROTECTION_WITH_INFO 41 /* aborted command sense key, */ /* protection plus 'info' field: */ /* [sk,asc,ascq: 0xb,0x10,*] */ #define SG_LIB_CAT_TIMEOUT 33 /* Yield string associated with sense category. Returns 'buff' (or pointer * to "Bad sense category" if 'buff' is NULL). If sense_cat unknown then * yield "Sense category: " string. */ const char * sg_get_category_sense_str(int sense_cat, int buff_len, char * buff, int verbose); /* Iterates to next designation descriptor in the device identification * VPD page. The 'initial_desig_desc' should point to start of first * descriptor with 'page_len' being the number of valid bytes in that * and following descriptors. To start, 'off' should point to a negative * value, thereafter it should point to the value yielded by the previous * call. If 0 returned then 'initial_desig_desc + *off' should be a valid * descriptor; returns -1 if normal end condition and -2 for an abnormal * termination. Matches association, designator_type and/or code_set when * any of those values are greater than or equal to zero. */ int sg_vpd_dev_id_iter(const unsigned char * initial_desig_desc, int page_len, int * off, int m_assoc, int m_desig_type, int m_code_set); /* <<< General purpose (i.e. not SCSI specific) utility functions >>> */ /* Always returns valid string even if errnum is wild (or library problem). * If errnum is negative, flip its sign. */ char * safe_strerror(int errnum); /* Print (to stdout) 'str' of bytes in hex, 16 bytes per line optionally * followed at the right hand side of the line with an ASCII interpretation. * Each line is prefixed with an address, starting at 0 for str[0]..str[15]. * All output numbers are in hex. 'no_ascii' allows for 3 output types: * > 0 each line has address then up to 16 ASCII-hex bytes * = 0 in addition, the bytes are listed in ASCII to the right * < 0 only the ASCII-hex bytes are listed (i.e. without address) */ void dStrHex(const char* str, int len, int no_ascii); /* Print (to sg_warnings_strm (stderr)) 'str' of bytes in hex, 16 bytes per * line optionally followed at right by its ASCII interpretation. Same * logic as dStrHex() with different output stream (i.e. stderr). */ void dStrHexErr(const char* str, int len, int no_ascii); /* Read 'len' bytes from 'str' and output as ASCII-Hex bytes (space * separated) to 'b' not to exceed 'b_len' characters. Each line * starts with 'leadin' (NULL for no leadin) and there are 16 bytes * per line with an extra space between the 8th and 9th bytes. 'format' * is unused, set to 0 . */ void dStrHexStr(const char* str, int len, const char * leadin, int format, int b_len, char * b); /* Returns 1 when executed on big endian machine; else returns 0. * Useful for displaying ATA identify words (which need swapping on a * big endian machine). */ int sg_is_big_endian(); /* Extract character sequence from ATA words as in the model string * in a IDENTIFY DEVICE response. Returns number of characters * written to 'ochars' before 0 character is found or 'num' words * are processed. */ int sg_ata_get_chars(const unsigned short * word_arr, int start_word, int num_words, int is_big_endian, char * ochars); /* Print (to stdout) 16 bit 'words' in hex, 8 words per line optionally * followed at the right hand side of the line with an ASCII interpretation * (pairs of ASCII characters in big endian order (upper first)). * Each line is prefixed with an address, starting at 0. * All output numbers are in hex. 'no_ascii' allows for 3 output types: * > 0 each line has address then up to 8 ASCII-hex words * = 0 in addition, the words are listed in ASCII pairs to the right * = -1 only the ASCII-hex words are listed (i.e. without address) * = -2 only the ASCII-hex words, formatted for "hdparm --Istdin" * < -2 same as -1 * If 'swapb' non-zero then bytes in each word swapped. Needs to be set * for ATA IDENTIFY DEVICE response on big-endian machines. */ void dWordHex(const unsigned short* words, int num, int no_ascii, int swapb); /* If the number in 'buf' can not be decoded or the multiplier is unknown * then -1 is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H') * suffix. Otherwise a decimal multiplier suffix may be given. Recognised * multipliers: c C *1; w W *2; b B *512; k K KiB *1,024; * KB *1,000; m M MiB *1,048,576; MB *1,000,000; g G GiB *1,073,741,824; * GB *1,000,000,000 and x which multiplies by . Ignore leading * spaces and tabs; accept comma, space, tab and hash as terminator. */ int sg_get_num(const char * buf); /* If the number in 'buf' can not be decoded then -1 is returned. Accepts a * hex prefix (0x or 0X) or a 'h' (or 'H') suffix; otherwise decimal is * assumed. Does not accept multipliers. Accept a comma (","), a whitespace * or newline as terminator. */ int sg_get_num_nomult(const char * buf); /* If the number in 'buf' can not be decoded or the multiplier is unknown * then -1LL is returned. Accepts a hex prefix (0x or 0X) or a 'h' (or 'H') * suffix. Otherwise a decimal multiplier suffix may be given. In addition * to supporting the multipliers of sg_get_num(), this function supports: * t T TiB *(2**40); TB *(10**12); p P PiB *(2**50); PB *(10**15) . * Ignore leading spaces and tabs; accept comma, space, tab and hash as * terminator. */ int64_t sg_get_llnum(const char * buf); /* <<< Architectural support functions [is there a better place?] >>> */ /* Non Unix OSes distinguish between text and binary files. * Set text mode on fd. Does nothing in Unix. Returns negative number on * failure. */ int sg_set_text_mode(int fd); /* Set binary mode on fd. Does nothing in Unix. Returns negative number on * failure. */ int sg_set_binary_mode(int fd); #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_cmds_basic.h0000664000175000017500000003102212346326270016727 0ustar douggdougg#ifndef SG_CMDS_BASIC_H #define SG_CMDS_BASIC_H /* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * Error, warning and verbose output is sent to the file pointed to by * sg_warnings_strm which is declared in sg_lib.h and can be set with * the sg_set_warnings_strm() function. If not given sg_warnings_strm * defaults to stderr. * If 'noisy' and 'verbose' are both zero then following functions should * not output anything to sg_warnings_strm. If 'noisy' is non-zero and * 'verbose' is zero then Unit Attention, Recovered, Medium and Hardware * errors (sense keys) send output to sg_warnings_strm. Increasing values * of 'verbose' send increasing amounts of (debug) output to * sg_warnings_strm. */ #ifdef __cplusplus extern "C" { #endif /* Invokes a SCSI INQUIRY command and yields the response * Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_ABORTED_COMMAND, -1 -> other errors */ int sg_ll_inquiry(int sg_fd, int cmddt, int evpd, int pg_op, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI LOG SELECT command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Log Select not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_NOT_READY -> device not ready, * -1 -> other failure */ int sg_ll_log_select(int sg_fd, int pcr, int sp, int pc, int pg_code, int subpg_code, unsigned char * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI LOG SENSE command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Log Sense not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_log_sense(int sg_fd, int ppc, int sp, int pc, int pg_code, int subpg_code, int paramp, unsigned char * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI MODE SELECT (6) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ -> * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_mode_select6(int sg_fd, int pf, int sp, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI MODE SELECT (10) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ -> * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_mode_select10(int sg_fd, int pf, int sp, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI MODE SENSE (6) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ -> * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_mode_sense6(int sg_fd, int dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI MODE SENSE (10) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_ILLEGAL_REQ -> * bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_mode_sense10(int sg_fd, int llbaa, int dbd, int pc, int pg_code, int sub_pg_code, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI PREVENT ALLOW MEDIUM REMOVAL command (SPC-3) * prevent==0 allows removal, prevent==1 prevents removal ... * Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> command not supported * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_prevent_allow(int sg_fd, int prevent, int noisy, int verbose); /* Invokes a SCSI READ CAPACITY (10) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_UNIT_ATTENTION * -> perhaps media changed, SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_readcap_10(int sg_fd, int pmi, unsigned int lba, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI READ CAPACITY (16) command. Returns 0 -> success, * SG_LIB_CAT_UNIT_ATTENTION -> media changed??, SG_LIB_CAT_INVALID_OP * -> cdb not supported, SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_readcap_16(int sg_fd, int pmi, uint64_t llba, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI REPORT LUNS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Report Luns not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */ int sg_ll_report_luns(int sg_fd, int select_report, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI REQUEST SENSE command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Request Sense not supported??, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_request_sense(int sg_fd, int desc, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI START STOP UNIT command (SBC + MMC). * Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Start stop unit not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure * SBC-3 and MMC partially overlap on the power_condition_modifier(sbc) and * format_layer_number(mmc) fields. They also overlap on the noflush(sbc) * and fl(mmc) one bit field. This is the cause of the awkardly named * pc_mod__fl_num and noflush__fl arguments to this function. */ int sg_ll_start_stop_unit(int sg_fd, int immed, int pc_mod__fl_num, int power_cond, int noflush__fl, int loej, int start, int noisy, int verbose); /* Invokes a SCSI SYNCHRONIZE CACHE (10) command. Return of 0 -> success, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_INVALID_OP -> cdb not supported, * SG_LIB_CAT_IlLEGAL_REQ -> bad field in cdb * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */ int sg_ll_sync_cache_10(int sg_fd, int sync_nv, int immed, int group, unsigned int lba, unsigned int count, int noisy, int verbose); /* Invokes a SCSI TEST UNIT READY command. * 'pack_id' is just for diagnostics, safe to set to 0. * Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_ABORTED_COMMAND, -1 -> other failure */ int sg_ll_test_unit_ready(int sg_fd, int pack_id, int noisy, int verbose); /* Invokes a SCSI TEST UNIT READY command. * 'pack_id' is just for diagnostics, safe to set to 0. * Looks for progress indicator if 'progress' non-NULL; * if found writes value [0..65535] else write -1. * Return of 0 -> success, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_ABORTED_COMMAND, SG_LIB_CAT_NOT_READY -> * device not ready, -1 -> other failure */ int sg_ll_test_unit_ready_progress(int sg_fd, int pack_id, int * progress, int noisy, int verbose); struct sg_simple_inquiry_resp { unsigned char peripheral_qualifier; unsigned char peripheral_type; unsigned char byte_1; /* was 'rmb' prior to version 1.39 */ /* now rmb == !!(0x80 & byte_1) */ unsigned char version; /* as per recent drafts: whole of byte 2 */ unsigned char byte_3; unsigned char byte_5; unsigned char byte_6; unsigned char byte_7; char vendor[9]; /* T10 field is 8 bytes, NUL char appended */ char product[17]; char revision[5]; }; /* Yields most of first 36 bytes of a standard INQUIRY (evpd==0) response. * Returns 0 when successful, SG_LIB_CAT_INVALID_OP -> not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other errors */ int sg_simple_inquiry(int sg_fd, struct sg_simple_inquiry_resp * inq_data, int noisy, int verbose); /* MODE SENSE commands yield a response that has block descriptors followed * by mode pages. In most cases users are interested in the first mode page. * This function returns the (byte) offset of the start of the first mode * page. Set mode_sense_6 to 1 for MODE SENSE (6) and 0 for MODE SENSE (10). * Returns >= 0 is successful or -1 if failure. If there is a failure * a message is written to err_buff. */ int sg_mode_page_offset(const unsigned char * resp, int resp_len, int mode_sense_6, char * err_buff, int err_buff_len); /* Fetches current, changeable, default and/or saveable modes pages as * indicated by pcontrol_arr for given pg_code and sub_pg_code. If * mode6==0 then use MODE SENSE (10) else use MODE SENSE (6). If * flexible set and mode data length seems wrong then try and * fix (compensating hack for bad device or driver). pcontrol_arr * should have 4 elements for output of current, changeable, default * and saved values respectively. Each element should be NULL or * at least mx_mpage_len bytes long. * Return of 0 -> overall success, SG_LIB_CAT_INVALID_OP -> invalid opcode, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, * SG_LIB_CAT_MALFORMED -> bad response, -1 -> other failure. * If success_mask pointer is not NULL then first zeros it. Then set bits * 0, 1, 2 and/or 3 if the current, changeable, default and saved values * respectively have been fetched. If error on current page * then stops and returns that error; otherwise continues if an error is * detected but returns the first error encountered. */ int sg_get_mode_page_controls(int sg_fd, int mode6, int pg_code, int sub_pg_code, int dbd, int flexible, int mx_mpage_len, int * success_mask, void * pcontrol_arr[], int * reported_len, int verbose); /* Returns file descriptor >= 0 if successful. If error in Unix returns negated errno. Implementation calls scsi_pt_open_device(). */ int sg_cmds_open_device(const char * device_name, int read_only, int verbose); /* Returns file descriptor >= 0 if successful. If error in Unix returns negated errno. Implementation calls scsi_pt_open_flags(). */ int sg_cmds_open_flags(const char * device_name, int flags, int verbose); /* Returns 0 if successful. If error in Unix returns negated errno. Implementation calls scsi_pt_close_device(). */ int sg_cmds_close_device(int device_fd); const char * sg_cmds_version(); struct sg_pt_base; /* This is a helper function used by sg_cmds_* implementations after the * call to the pass-through. pt_res is returned from do_scsi_pt(). If valid * sense data is found it is decoded and output to sg_warnings_strm (def: * stderr); depending on the 'noisy' and 'verbose' settings. Returns -2 for * sense data (may not be fatal), -1 for failed, 0, or a positive number. If * 'mx_di_len > 0' then asks pass-through for resid and returns * (mx_di_len - resid); otherwise returns 0. So for data-in it should return * the actual number of bytes received. For data-out (to device) or no data * call with 'mx_di_len' set to 0 or less. If -2 returned then sense category * output via 'o_sense_cat' pointer (if not NULL). Note that several sense * categories also have data in bytes received; -2 is still returned. */ int sg_cmds_process_resp(struct sg_pt_base * ptvp, const char * leadin, int pt_res, int mx_di_len, const unsigned char * sense_b, int noisy, int verbose, int * o_sense_cat); #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_linux_inc.h0000664000175000017500000000367010671112741016633 0ustar douggdougg#ifndef SG_LINUX_INC_H #define SG_LINUX_INC_H #ifdef SG_KERNEL_INCLUDES #define __user typedef unsigned char u8; #include "/usr/src/linux/include/scsi/sg.h" #include "/usr/src/linux/include/scsi/scsi.h" #else #ifdef SG_TRICK_GNU_INCLUDES #include #include #else #include #include #endif #endif #ifdef BLKGETSIZE64 #ifndef u64 #include /* C99 header for exact integer types */ typedef uint64_t u64; /* problems with BLKGETSIZE64 ioctl in lk 2.4 */ #endif #endif /* Getting the correct include files for the sg interface can be an ordeal. In a perfect world, one would just write: #include #include This would include the files found in the /usr/include/scsi directory. Those files are maintained with the GNU library which may or may not agree with the kernel and version of sg driver that is running. Any many cases this will not matter. However in some it might, for example glibc 2.1's include files match the sg driver found in the lk 2.2 series. Hence if glibc 2.1 is used with lk 2.4 then the additional sg v3 interface will not be visible. If this is a problem then defining SG_KERNEL_INCLUDES will access the kernel supplied header files (assuming they are in the normal place). The GNU library maintainers and various kernel people don't like this approach (but it does work). The technique selected by defining SG_TRICK_GNU_INCLUDES worked (and was used) prior to glibc 2.2 . Prior to that version /usr/include/linux was a symbolic link to /usr/src/linux/include/linux . There are other approaches if this include "mixup" causes pain. These would involve include files being copied or symbolic links being introduced. Sorry about the inconvenience. Typically neither SG_KERNEL_INCLUDES nor SG_TRICK_GNU_INCLUDES is defined. dpg 20010415, 20030522 */ #endif sg3_utils-1.40/include/sg_io_linux.h0000664000175000017500000001432112207377272016475 0ustar douggdougg#ifndef SG_IO_LINUX_H #define SG_IO_LINUX_H /* * Copyright (c) 2004-2012 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * Version 1.03 [20120914] */ /* * This header file contains linux specific information related to the SCSI * command pass through in the SCSI generic (sg) driver and the linux * block layer. */ #include "sg_lib.h" #include "sg_linux_inc.h" #ifdef __cplusplus extern "C" { #endif /* The following are 'host_status' codes */ #ifndef DID_OK #define DID_OK 0x00 #endif #ifndef DID_NO_CONNECT #define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ #define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ #define DID_TIME_OUT 0x03 /* Timed out for some other reason */ #define DID_BAD_TARGET 0x04 /* Bad target (id?) */ #define DID_ABORT 0x05 /* Told to abort for some other reason */ #define DID_PARITY 0x06 /* Parity error (on SCSI bus) */ #define DID_ERROR 0x07 /* Internal error */ #define DID_RESET 0x08 /* Reset by somebody */ #define DID_BAD_INTR 0x09 /* Received an unexpected interrupt */ #define DID_PASSTHROUGH 0x0a /* Force command past mid-level */ #define DID_SOFT_ERROR 0x0b /* The low-level driver wants a retry */ #endif #ifndef DID_IMM_RETRY #define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ #endif #ifndef DID_REQUEUE #define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also * without decrementing the retry count */ #endif #ifndef DID_TRANSPORT_DISRUPTED #define DID_TRANSPORT_DISRUPTED 0xe #endif #ifndef DID_TRANSPORT_FAILFAST #define DID_TRANSPORT_FAILFAST 0xf #endif #ifndef DID_TARGET_FAILURE #define DID_TARGET_FAILURE 0x10 #endif #ifndef DID_NEXUS_FAILURE #define DID_NEXUS_FAILURE 0x11 #endif /* These defines are to isolate applications from kernel define changes */ #define SG_LIB_DID_OK DID_OK #define SG_LIB_DID_NO_CONNECT DID_NO_CONNECT #define SG_LIB_DID_BUS_BUSY DID_BUS_BUSY #define SG_LIB_DID_TIME_OUT DID_TIME_OUT #define SG_LIB_DID_BAD_TARGET DID_BAD_TARGET #define SG_LIB_DID_ABORT DID_ABORT #define SG_LIB_DID_PARITY DID_PARITY #define SG_LIB_DID_ERROR DID_ERROR #define SG_LIB_DID_RESET DID_RESET #define SG_LIB_DID_BAD_INTR DID_BAD_INTR #define SG_LIB_DID_PASSTHROUGH DID_PASSTHROUGH #define SG_LIB_DID_SOFT_ERROR DID_SOFT_ERROR #define SG_LIB_DID_IMM_RETRY DID_IMM_RETRY #define SG_LIB_DID_REQUEUE DID_REQUEUE #define SG_LIB_TRANSPORT_DISRUPTED DID_TRANSPORT_DISRUPTED #define SG_LIB_DID_TRANSPORT_FAILFAST DID_TRANSPORT_FAILFAST #define SG_LIB_DID_TARGET_FAILURE DID_TARGET_FAILURE #define SG_LIB_DID_NEXUS_FAILURE DID_NEXUS_FAILURE /* The following are 'driver_status' codes */ #ifndef DRIVER_OK #define DRIVER_OK 0x00 #endif #ifndef DRIVER_BUSY #define DRIVER_BUSY 0x01 #define DRIVER_SOFT 0x02 #define DRIVER_MEDIA 0x03 #define DRIVER_ERROR 0x04 #define DRIVER_INVALID 0x05 #define DRIVER_TIMEOUT 0x06 #define DRIVER_HARD 0x07 #define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ /* Following "suggests" are "or-ed" with one of previous 8 entries */ #define SUGGEST_RETRY 0x10 #define SUGGEST_ABORT 0x20 #define SUGGEST_REMAP 0x30 #define SUGGEST_DIE 0x40 #define SUGGEST_SENSE 0x80 #define SUGGEST_IS_OK 0xff #endif #ifndef DRIVER_MASK #define DRIVER_MASK 0x0f #endif #ifndef SUGGEST_MASK #define SUGGEST_MASK 0xf0 #endif /* These defines are to isolate applications from kernel define changes */ #define SG_LIB_DRIVER_OK DRIVER_OK #define SG_LIB_DRIVER_BUSY DRIVER_BUSY #define SG_LIB_DRIVER_SOFT DRIVER_SOFT #define SG_LIB_DRIVER_MEDIA DRIVER_MEDIA #define SG_LIB_DRIVER_ERROR DRIVER_ERROR #define SG_LIB_DRIVER_INVALID DRIVER_INVALID #define SG_LIB_DRIVER_TIMEOUT DRIVER_TIMEOUT #define SG_LIB_DRIVER_HARD DRIVER_HARD #define SG_LIB_DRIVER_SENSE DRIVER_SENSE #define SG_LIB_SUGGEST_RETRY SUGGEST_RETRY #define SG_LIB_SUGGEST_ABORT SUGGEST_ABORT #define SG_LIB_SUGGEST_REMAP SUGGEST_REMAP #define SG_LIB_SUGGEST_DIE SUGGEST_DIE #define SG_LIB_SUGGEST_SENSE SUGGEST_SENSE #define SG_LIB_SUGGEST_IS_OK SUGGEST_IS_OK #define SG_LIB_DRIVER_MASK DRIVER_MASK #define SG_LIB_SUGGEST_MASK SUGGEST_MASK void sg_print_masked_status(int masked_status); void sg_print_host_status(int host_status); void sg_print_driver_status(int driver_status); /* sg_chk_n_print() returns 1 quietly if there are no errors/warnings else it prints errors/warnings (prefixed by 'leadin') to 'sg_warnings_fd' and returns 0. raw_sinfo indicates whether the raw sense buffer (in ASCII hex) should be printed. */ int sg_chk_n_print(const char * leadin, int masked_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len, int raw_sinfo); /* The following function declaration is for the sg version 3 driver. */ struct sg_io_hdr; /* sg_chk_n_print3() returns 1 quietly if there are no errors/warnings; else it prints errors/warnings (prefixed by 'leadin') to 'sg_warnings_fd' and returns 0. */ int sg_chk_n_print3(const char * leadin, struct sg_io_hdr * hp, int raw_sinfo); /* Calls sg_scsi_normalize_sense() after obtaining the sense buffer and its length from the struct sg_io_hdr pointer. If these cannot be obtained, 0 is returned. */ int sg_normalize_sense(const struct sg_io_hdr * hp, struct sg_scsi_sense_hdr * sshp); int sg_err_category(int masked_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len); int sg_err_category_new(int scsi_status, int host_status, int driver_status, const unsigned char * sense_buffer, int sb_len); /* The following function declaration is for the sg version 3 driver. */ int sg_err_category3(struct sg_io_hdr * hp); /* Note about SCSI status codes found in older versions of Linux. Linux has traditionally used a 1 bit right shifted and masked version of SCSI standard status codes. Now CHECK_CONDITION and friends (in ) are deprecated. */ #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_cmds_extra.h0000664000175000017500000004106612270322342016772 0ustar douggdougg#ifndef SG_CMDS_EXTRA_H #define SG_CMDS_EXTRA_H /* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #ifdef __cplusplus extern "C" { #endif /* Note: all functions that have an 'int timeout_secs' argument will use * that value if it is > 0. Otherwise they will set an internal default * which is currently 60 seconds. This timeout is typically applied in the * SCSI stack above the initiator. If it goes off then the SCSI command is * aborted and there can be other unwelcome side effects. Note that some * commands (e.g. FORMAT UNIT and the Third Party copy commands) can take * a lot longer than the default timeout. */ /* Invokes a ATA PASS-THROUGH (12 or 16) SCSI command (SAT). If cdb_len is * 12 then a ATA PASS-THROUGH (12) command is called. If cdb_len is 16 then * a ATA PASS-THROUGH (16) command is called. If cdb_len is any other value * -1 is returned. After copying from cdbp to an internal buffer, the first * byte (i.e. offset 0) is set to 0xa1 if cdb_len is 12; or is set to 0x85 * if cdb_len is 16. The last byte (offset 11 or offset 15) is set to 0x0 in * the internal buffer. For data in or out transfers set dinp or doutp, and * dlen to the number of bytes to transfer. If dlen is zero then no data * transfer is assumed. If sense buffer obtained then it is written to * sensep, else sensep[0] is set to 0x0. If ATA return descriptor is obtained * then written to ata_return_dp, else ata_return_dp[0] is set to 0x0. Either * sensep or ata_return_dp (or both) may be NULL pointers. Returns SCSI * status value (>= 0) or -1 if other error. Users are expected to check the * sense buffer themselves. If available the data in resid is written to * residp. Note in SAT-2 and later, fixed format sense data may be placed in * *sensep in which case sensep[0]==0x70 . */ int sg_ll_ata_pt(int sg_fd, const unsigned char * cdbp, int cdb_len, int timeout_secs, void * dinp, void * doutp, int dlen, unsigned char * sensep, int max_sense_len, unsigned char * ata_return_dp, int max_ata_return_len, int * residp, int verbose); /* Invokes a FORMAT UNIT (SBC-3) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Format unit not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_format_unit(int sg_fd, int fmtpinfo, int longlist, int fmtdata, int cmplist, int dlist_format, int timeout_secs, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI GET LBA STATUS command (SBC). Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> GET LBA STATUS not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */ int sg_ll_get_lba_status(int sg_fd, uint64_t start_llba, void * resp, int alloc_len, int noisy, int verbose); /* Invokes a SCSI PERSISTENT RESERVE IN command (SPC). Returns 0 * when successful, SG_LIB_CAT_INVALID_OP if command not supported, * SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_persistent_reserve_in(int sg_fd, int rq_servact, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI PERSISTENT RESERVE OUT command (SPC). Returns 0 * when successful, SG_LIB_CAT_INVALID_OP if command not supported, * SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_persistent_reserve_out(int sg_fd, int rq_servact, int rq_scope, unsigned int rq_type, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI READ BLOCK LIMITS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> READ BLOCK LIMITS not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_NOT_READY (shouldn't happen), -1 -> other failure */ int sg_ll_read_block_limits(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI READ BUFFER command (SPC). Return of 0 -> * success, SG_LIB_CAT_INVALID_OP -> invalid opcode, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_read_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI READ DEFECT DATA (10) command (SBC). Return of 0 -> * success, SG_LIB_CAT_INVALID_OP -> invalid opcode, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_read_defect10(int sg_fd, int req_plist, int req_glist, int dl_format, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI READ LONG (10) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> READ LONG(10) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_read_long10(int sg_fd, int pblock, int correct, unsigned int lba, void * resp, int xfer_len, int * offsetp, int noisy, int verbose); /* Invokes a SCSI READ LONG (16) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> READ LONG(16) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_read_long16(int sg_fd, int pblock, int correct, uint64_t llba, void * resp, int xfer_len, int * offsetp, int noisy, int verbose); /* Invokes a SCSI READ MEDIA SERIAL NUMBER command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Read media serial number not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_read_media_serial_num(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI REASSIGN BLOCKS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> invalid opcode, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_NOT_READY -> device not ready, -1 -> other failure */ int sg_ll_reassign_blocks(int sg_fd, int longlba, int longlist, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI RECEIVE DIAGNOSTIC RESULTS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Receive diagnostic results not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_receive_diag(int sg_fd, int pcv, int pg_code, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI REPORT IDENTIFYING INFORMATION command. This command was * called REPORT DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Report identifying information not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_report_id_info(int sg_fd, int itype, void * resp, int max_resp_len, int noisy, int verbose); /* Invokes a SCSI REPORT TARGET PORT GROUPS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Report Target Port Groups not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */ int sg_ll_report_tgt_prt_grp(int sg_fd, void * resp, int mx_resp_len, int noisy, int verbose); int sg_ll_report_tgt_prt_grp2(int sg_fd, void * resp, int mx_resp_len, int extended, int noisy, int verbose); /* Invokes a SCSI SET TARGET PORT GROUPS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Report Target Port Groups not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */ int sg_ll_set_tgt_prt_grp(int sg_fd, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI REPORT REFERRALS command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Report Referrals not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */ int sg_ll_report_referrals(int sg_fd, uint64_t start_llba, int one_seg, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI SEND DIAGNOSTIC command. Foreground, extended self tests can * take a long time, if so set long_duration flag in which case the timout * is set to 7200 seconds; if the value of long_duration is > 7200 then that * value is taken as the timeout value in seconds. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Send diagnostic not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_send_diag(int sg_fd, int sf_code, int pf_bit, int sf_bit, int devofl_bit, int unitofl_bit, int long_duration, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI SET IDENTIFYING INFORMATION command. This command was * called SET DEVICE IDENTIFIER prior to spc4r07. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Set identifying information not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_set_id_info(int sg_fd, int itype, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI UNMAP (SBC-3) command. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> command not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, -1 -> other failure */ int sg_ll_unmap(int sg_fd, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI UNMAP (SBC-3) command. Version 2 adds anchor field * (sbc3r22). Otherwise same as sg_ll_unmap() . */ int sg_ll_unmap_v2(int sg_fd, int anchor, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose); /* Invokes a SCSI VERIFY (10) command (SBC and MMC). * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes. * Returns of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Verify(10) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_MEDIUM_HARD -> medium or hardware error, no valid info, * SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> as previous, with valid info, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_MISCOMPARE, -1 -> other failure */ int sg_ll_verify10(int sg_fd, int vrprotect, int dpo, int bytechk, unsigned int lba, int veri_len, void * data_out, int data_out_len, unsigned int * infop, int noisy, int verbose); /* Invokes a SCSI VERIFY (16) command (SBC). * Note that 'veri_len' is in blocks while 'data_out_len' is in bytes. * Returns of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Verify(16) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_MEDIUM_HARD -> medium or hardware error, no valid info, * SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> as previous, with valid info, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_MISCOMPARE, -1 -> other failure */ int sg_ll_verify16(int sg_fd, int vrprotect, int dpo, int bytechk, uint64_t llba, int veri_len, int group_num, void * data_out, int data_out_len, uint64_t * infop, int noisy, int verbose); /* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 -> * success, SG_LIB_CAT_INVALID_OP -> invalid opcode, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_write_buffer(int sg_fd, int mode, int buffer_id, int buffer_offset, void * paramp, int param_len, int noisy, int verbose); /* Need a sg_ll_write_buffer_v2() function because SPC-4 rev32 has added * a "mode specific" field. Wait for next rev change of this library */ /* Invokes a SCSI WRITE LONG (10) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> WRITE LONG(10) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_write_long10(int sg_fd, int cor_dis, int wr_uncor, int pblock, unsigned int lba, void * data_out, int xfer_len, int * offsetp, int noisy, int verbose); /* Invokes a SCSI WRITE LONG (16) command (SBC). Note that 'xfer_len' * is in bytes. Returns 0 -> success, * SG_LIB_CAT_INVALID_OP -> WRITE LONG(16) not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, * SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO -> bad field in cdb, with info * field written to 'offsetp', SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_write_long16(int sg_fd, int cor_dis, int wr_uncor, int pblock, uint64_t llba, void * data_out, int xfer_len, int * offsetp, int noisy, int verbose); /* Invokes a SPC-3 SCSI RECEIVE COPY RESULTS command. In SPC-4 this function * supports all service action variants of the THIRD-PARTY COPY IN opcode. * SG_LIB_CAT_INVALID_OP -> Receive copy results not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_receive_copy_results(int sg_fd, int sa, int list_id, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI EXTENDED COPY(LID1) command. For EXTENDED COPY(LID4) * including POPULATE TOKEN and WRITE USING TOKEN use * sg_ll_3party_copy_out(). Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Extended copy not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_extended_copy(int sg_fd, void * paramp, int param_len, int noisy, int verbose); /* Handles various service actions associated with opcode 0x83 which is * called THIRD PARTY COPY OUT. These include the EXTENDED COPY(LID4), * POPULATE TOKEN and WRITE USING TOKEN commands. Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> opcode 0x83 not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_3party_copy_out(int sg_fd, int sa, unsigned int list_id, int group_num, int timeout_secs, void * paramp, int param_len, int noisy, int verbose); #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_unaligned.h0000664000175000017500000001472312406465611016617 0ustar douggdougg#ifndef SG_UNALIGNED_H #define SG_UNALIGNED_H /* * Copyright (c) 2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #ifdef __cplusplus extern "C" { #endif /* Borrowed from the Linux kernel, via mhvtl */ /* In the first section below, functions that copy unsigned integers in * a computer's native format, to and from an unaligned big endian sequence * of bytes. Big endian byte format "on the wire" is the default used by * SCSI standards (www.t10.org). */ static inline uint16_t __get_unaligned_be16(const uint8_t *p) { return p[0] << 8 | p[1]; } static inline uint32_t __get_unaligned_be32(const uint8_t *p) { return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; } static inline uint64_t __get_unaligned_be64(const uint8_t *p) { return (uint64_t)__get_unaligned_be32(p) << 32 | __get_unaligned_be32(p + 4); } static inline void __put_unaligned_be16(uint16_t val, uint8_t *p) { *p++ = val >> 8; *p++ = val; } static inline void __put_unaligned_be32(uint32_t val, uint8_t *p) { __put_unaligned_be16(val >> 16, p); __put_unaligned_be16(val, p + 2); } static inline void __put_unaligned_be64(uint64_t val, uint8_t *p) { __put_unaligned_be32(val >> 32, p); __put_unaligned_be32(val, p + 4); } static inline uint16_t sg_get_unaligned_be16(const void *p) { return __get_unaligned_be16((const uint8_t *)p); } static inline uint32_t sg_get_unaligned_be24(const uint8_t *p) { return p[0] << 16 | p[1] << 8 | p[2]; } static inline uint32_t sg_get_unaligned_be32(const void *p) { return __get_unaligned_be32((const uint8_t *)p); } static inline uint64_t sg_get_unaligned_be64(const void *p) { return __get_unaligned_be64((const uint8_t *)p); } static inline void sg_put_unaligned_be16(uint16_t val, void *p) { __put_unaligned_be16(val, (uint8_t *)p); } static inline void sg_put_unaligned_be24(uint32_t val, void *p) { ((uint8_t *)p)[0] = (val >> 16) & 0xff; ((uint8_t *)p)[1] = (val >> 8) & 0xff; ((uint8_t *)p)[2] = val & 0xff; } static inline void sg_put_unaligned_be32(uint32_t val, void *p) { __put_unaligned_be32(val, (uint8_t *)p); } static inline void sg_put_unaligned_be64(uint64_t val, void *p) { __put_unaligned_be64(val, (uint8_t *)p); } /* Since cdb and parameter blocks are often memset to zero before these * unaligned function partially fill them, then check for a val of zero * and ignore if it is with these variants. */ static inline void sg_nz_put_unaligned_be16(uint16_t val, void *p) { if (val) __put_unaligned_be16(val, (uint8_t *)p); } static inline void sg_nz_put_unaligned_be24(uint32_t val, void *p) { if (val) { ((uint8_t *)p)[0] = (val >> 16) & 0xff; ((uint8_t *)p)[1] = (val >> 8) & 0xff; ((uint8_t *)p)[2] = val & 0xff; } } static inline void sg_nz_put_unaligned_be32(uint32_t val, void *p) { if (val) __put_unaligned_be32(val, (uint8_t *)p); } static inline void sg_nz_put_unaligned_be64(uint64_t val, void *p) { if (val) __put_unaligned_be64(val, (uint8_t *)p); } /* Below are the little endian equivalents of the big endian functions * above. Little endian is used by ATA, networking and PCI. * This section could take advantage of the * 'uint32_t htonl(uint32_t hostlong)' [and the complementary ntohl()] * family of functions but that would introduce a dependency on the * header. Also they don't address moving to and from * an unaligned sequence of bytes. The latter would still need to be * done. */ static inline uint16_t __get_unaligned_le16(const uint8_t *p) { return p[1] << 8 | p[0]; } static inline uint32_t __get_unaligned_le32(const uint8_t *p) { return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0]; } static inline uint64_t __get_unaligned_le64(const uint8_t *p) { return (uint64_t)__get_unaligned_le32(p + 4) << 32 | __get_unaligned_le32(p); } static inline void __put_unaligned_le16(uint16_t val, uint8_t *p) { *p++ = val; *p++ = val >> 8; } static inline void __put_unaligned_le32(uint32_t val, uint8_t *p) { __put_unaligned_le16(val >> 16, p + 2); __put_unaligned_le16(val, p); } static inline void __put_unaligned_le64(uint64_t val, uint8_t *p) { __put_unaligned_le32(val >> 32, p + 4); __put_unaligned_le32(val, p); } static inline uint16_t sg_get_unaligned_le16(const void *p) { return __get_unaligned_le16((const uint8_t *)p); } static inline uint32_t sg_get_unaligned_le24(const uint8_t *p) { return p[2] << 16 | p[1] << 8 | p[0]; } static inline uint32_t sg_get_unaligned_le32(const void *p) { return __get_unaligned_le32((const uint8_t *)p); } static inline uint64_t sg_get_unaligned_le64(const void *p) { return __get_unaligned_le64((const uint8_t *)p); } static inline void sg_put_unaligned_le16(uint16_t val, void *p) { __put_unaligned_le16(val, (uint8_t *)p); } static inline void sg_put_unaligned_le24(uint32_t val, void *p) { ((uint8_t *)p)[2] = (val >> 16) & 0xff; ((uint8_t *)p)[1] = (val >> 8) & 0xff; ((uint8_t *)p)[0] = val & 0xff; } static inline void sg_put_unaligned_le32(uint32_t val, void *p) { __put_unaligned_le32(val, (uint8_t *)p); } static inline void sg_put_unaligned_le64(uint64_t val, void *p) { __put_unaligned_le64(val, (uint8_t *)p); } /* Since cdb and parameter blocks are often memset to zero before these * unaligned function partially fill them, then check for a val of zero * and ignore if it is with these variants. */ static inline void sg_nz_put_unaligned_le16(uint16_t val, void *p) { if (val) __put_unaligned_le16(val, (uint8_t *)p); } static inline void sg_nz_put_unaligned_le24(uint32_t val, void *p) { if (val) { ((uint8_t *)p)[2] = (val >> 16) & 0xff; ((uint8_t *)p)[1] = (val >> 8) & 0xff; ((uint8_t *)p)[0] = val & 0xff; } } static inline void sg_nz_put_unaligned_le32(uint32_t val, void *p) { if (val) __put_unaligned_le32(val, (uint8_t *)p); } static inline void sg_nz_put_unaligned_le64(uint64_t val, void *p) { if (val) __put_unaligned_le64(val, (uint8_t *)p); } #ifdef __cplusplus } #endif #endif /* SG_UNALIGNED_H */ sg3_utils-1.40/include/sg_cmds_mmc.h0000664000175000017500000000376212207377272016440 0ustar douggdougg#ifndef SG_CMDS_MMC_H #define SG_CMDS_MMC_H /* * Copyright (c) 2008-2013 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #ifdef __cplusplus extern "C" { #endif /* Invokes a SCSI GET CONFIGURATION command (MMC-3...6). * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_get_config(int sg_fd, int rt, int starting, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI GET PERFORMANCE command (MMC-3...6). * Returns 0 when successful, SG_LIB_CAT_INVALID_OP if command not * supported, SG_LIB_CAT_ILLEGAL_REQ if field in cdb not supported, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND, else -1 */ int sg_ll_get_performance(int sg_fd, int data_type, unsigned int starting_lba, int max_num_desc, int type, void * resp, int mx_resp_len, int noisy, int verbose); /* Invokes a SCSI SET CD SPEED command (MMC). * Return of 0 -> success, SG_LIB_CAT_INVALID_OP -> command not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ int sg_ll_set_cd_speed(int sg_fd, int rot_control, int drv_read_speed, int drv_write_speed, int noisy, int verbose); /* Invokes a SCSI SET STREAMING command (MMC). Return of 0 -> success, * SG_LIB_CAT_INVALID_OP -> Set Streaming not supported, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_ABORTED_COMMAND, * SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_NOT_READY -> device not ready, * -1 -> other failure */ int sg_ll_set_streaming(int sg_fd, int type, void * paramp, int param_len, int noisy, int verbose); #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_lib_data.h0000664000175000017500000000572512326640175016413 0ustar douggdougg#ifndef SG_LIB_DATA_H #define SG_LIB_DATA_H /* * Copyright (c) 2007-2012 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * This header file contains some structure declarations and array name * declarations which are defined in the sg_lib_data.c . * Typically this header does not need to be exposed to users of the * sg_lib interface declared in sg_libs.h . */ #include #ifdef __cplusplus extern "C" { #endif /* Commands with service actions that change the command name */ #define SG_EXTENDED_COPY 0x83 /* since spc4r34 called: Third party copy out */ #define SG_RECEIVE_COPY 0x84 /* since spc4r34 called: Third party copy in */ #define SG_MAINTENANCE_IN 0xa3 #define SG_MAINTENANCE_OUT 0xa4 #define SG_PERSISTENT_RESERVE_IN 0x5e #define SG_PERSISTENT_RESERVE_OUT 0x5f #define SG_READ_BUFFER 0x3c #define SG_SANITIZE 0x48 #define SG_SERVICE_ACTION_BIDI 0x9d #define SG_SERVICE_ACTION_IN_12 0xab #define SG_SERVICE_ACTION_IN_16 0x9e #define SG_SERVICE_ACTION_OUT_12 0xa9 #define SG_SERVICE_ACTION_OUT_16 0x9f #define SG_VARIABLE_LENGTH_CMD 0x7f #define SG_WRITE_BUFFER 0x3b struct sg_lib_value_name_t { int value; int peri_dev_type; /* 0 -> SPC and/or PDT_DISK, >0 -> PDT */ const char * name; }; struct sg_lib_asc_ascq_t { unsigned char asc; /* additional sense code */ unsigned char ascq; /* additional sense code qualifier */ const char * text; }; struct sg_lib_asc_ascq_range_t { unsigned char asc; /* additional sense code (ASC) */ unsigned char ascq_min; /* ASCQ minimum in range */ unsigned char ascq_max; /* ASCQ maximum in range */ const char * text; }; extern const char * sg_lib_version_str; extern struct sg_lib_value_name_t sg_lib_normal_opcodes[]; extern struct sg_lib_value_name_t sg_lib_read_buff_arr[]; extern struct sg_lib_value_name_t sg_lib_write_buff_arr[]; extern struct sg_lib_value_name_t sg_lib_maint_in_arr[]; extern struct sg_lib_value_name_t sg_lib_maint_out_arr[]; extern struct sg_lib_value_name_t sg_lib_pr_in_arr[]; extern struct sg_lib_value_name_t sg_lib_pr_out_arr[]; extern struct sg_lib_value_name_t sg_lib_sanitize_sa_arr[]; extern struct sg_lib_value_name_t sg_lib_serv_in12_arr[]; extern struct sg_lib_value_name_t sg_lib_serv_out12_arr[]; extern struct sg_lib_value_name_t sg_lib_serv_in16_arr[]; extern struct sg_lib_value_name_t sg_lib_serv_out16_arr[]; extern struct sg_lib_value_name_t sg_lib_serv_bidi_arr[]; extern struct sg_lib_value_name_t sg_lib_xcopy_sa_arr[]; extern struct sg_lib_value_name_t sg_lib_rec_copy_sa_arr[]; extern struct sg_lib_value_name_t sg_lib_variable_length_arr[]; extern struct sg_lib_asc_ascq_range_t sg_lib_asc_ascq_range[]; extern struct sg_lib_asc_ascq_t sg_lib_asc_ascq[]; extern const char * sg_lib_sense_key_desc[]; extern const char * sg_lib_pdt_strs[]; extern const char * sg_lib_transport_proto_strs[]; #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_pt.h0000664000175000017500000001404012343463464015270 0ustar douggdougg#ifndef SG_PT_H #define SG_PT_H /* * Copyright (c) 2005-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #ifdef __cplusplus extern "C" { #endif /* This declaration hides the fact that each implementation has its own * structure "derived" (using a C++ term) from this one. It compiles * because 'struct sg_pt_base' is only referenced (by pointer: 'objp') * in this interface. An instance of this structure represents the * context of one SCSI command. */ struct sg_pt_base; /* The format of the version string is like this: "2.01 20090201". * The leading digit will be incremented if this interface changes * in a way that may impact backward compatibility. */ const char * scsi_pt_version(); /* Returns >= 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_open_device(const char * device_name, int read_only, int verbose); /* Similar to scsi_pt_open_device() but takes Unix style open flags OR-ed * together. Returns valid file descriptor( >= 0 ) if successful, otherwise * returns -1 or a negated errno. * In Win32 O_EXCL translated to equivalent. */ int scsi_pt_open_flags(const char * device_name, int flags, int verbose); /* Returns 0 if successful. If error in Unix returns negated errno. */ int scsi_pt_close_device(int device_fd); /* Creates an object that can be used to issue one or more SCSI commands * (or task management functions). Returns NULL if problem. * Once this object has been created it should be destroyed with * destruct_scsi_pt_obj() when it is no longer needed. */ struct sg_pt_base * construct_scsi_pt_obj(void); /* Clear state information held in *objp . This allows this object to be * used to issue more than one SCSI command. */ void clear_scsi_pt_obj(struct sg_pt_base * objp); /* Set the CDB (command descriptor block) */ void set_scsi_pt_cdb(struct sg_pt_base * objp, const unsigned char * cdb, int cdb_len); /* Set the sense buffer and the maximum length that it can handle */ void set_scsi_pt_sense(struct sg_pt_base * objp, unsigned char * sense, int max_sense_len); /* Set a pointer and length to be used for data transferred from device */ void set_scsi_pt_data_in(struct sg_pt_base * objp, /* from device */ unsigned char * dxferp, int dxfer_len); /* Set a pointer and length to be used for data transferred to device */ void set_scsi_pt_data_out(struct sg_pt_base * objp, /* to device */ const unsigned char * dxferp, int dxfer_len); /* The following "set_"s implementations may be dummies */ void set_scsi_pt_packet_id(struct sg_pt_base * objp, int pack_id); void set_scsi_pt_tag(struct sg_pt_base * objp, uint64_t tag); void set_scsi_pt_task_management(struct sg_pt_base * objp, int tmf_code); void set_scsi_pt_task_attr(struct sg_pt_base * objp, int attribute, int priority); /* Following is a guard which is defined when set_scsi_pt_flags() is * present. Older versions of this library may not have this function. */ #define SCSI_PT_FLAGS_FUNCTION 1 /* If neither QUEUE_AT_HEAD nor QUEUE_AT_TAIL are given, or both * are given, use the pass-through default. */ #define SCSI_PT_FLAGS_QUEUE_AT_TAIL 0x10 #define SCSI_PT_FLAGS_QUEUE_AT_HEAD 0x20 /* Set (potentially OS dependant) flags for pass-through mechanism. * Apart from contradictions, flags can be OR-ed together. */ void set_scsi_pt_flags(struct sg_pt_base * objp, int flags); #define SCSI_PT_DO_START_OK 0 #define SCSI_PT_DO_BAD_PARAMS 1 #define SCSI_PT_DO_TIMEOUT 2 /* If OS error prior to or during command submission then returns negated * error value (e.g. Unix '-errno'). This includes interrupted system calls * (e.g. by a signal) in which case -EINTR would be returned. Note that * system call errors also can be fetched with get_scsi_pt_os_err(). * Return 0 if okay (i.e. at the very least: command sent). Positive * return values are errors (see SCSI_PT_DO_* defines). */ int do_scsi_pt(struct sg_pt_base * objp, int fd, int timeout_secs, int verbose); #define SCSI_PT_RESULT_GOOD 0 #define SCSI_PT_RESULT_STATUS 1 /* other than GOOD and CHECK CONDITION */ #define SCSI_PT_RESULT_SENSE 2 #define SCSI_PT_RESULT_TRANSPORT_ERR 3 #define SCSI_PT_RESULT_OS_ERR 4 /* highest numbered applicable category returned */ int get_scsi_pt_result_category(const struct sg_pt_base * objp); /* If not available return 0 */ int get_scsi_pt_resid(const struct sg_pt_base * objp); /* Returns SCSI status value (from device that received the command). */ int get_scsi_pt_status_response(const struct sg_pt_base * objp); /* Actual sense length returned. If sense data is present but actual sense length is not known, return 'max_sense_len' */ int get_scsi_pt_sense_len(const struct sg_pt_base * objp); /* If not available return 0 */ int get_scsi_pt_os_err(const struct sg_pt_base * objp); char * get_scsi_pt_os_err_str(const struct sg_pt_base * objp, int max_b_len, char * b); /* If not available return 0 */ int get_scsi_pt_transport_err(const struct sg_pt_base * objp); char * get_scsi_pt_transport_err_str(const struct sg_pt_base * objp, int max_b_len, char * b); /* If not available return -1 */ int get_scsi_pt_duration_ms(const struct sg_pt_base * objp); /* Should be invoked once per objp after other processing is complete in * order to clean up resources. For ever successful construct_scsi_pt_obj() * call there should be one destruct_scsi_pt_obj(). */ void destruct_scsi_pt_obj(struct sg_pt_base * objp); #ifdef SG_LIB_WIN32 #define SG_LIB_WIN32_DIRECT 1 /* Request SPT direct interface when state_direct is 1, state_direct set * to 0 for the SPT indirect interface. Default setting selected by build * (i.e. library compile time) and is usually indirect. */ void scsi_pt_win32_direct(int state_direct); /* Returns current SPT interface state, 1 for direct, 0 for indirect */ int scsi_pt_win32_spt_state(void); #endif #ifdef __cplusplus } #endif #endif sg3_utils-1.40/include/sg_cmds.h0000664000175000017500000000151710756351213015572 0ustar douggdougg#ifndef SG_CMDS_H #define SG_CMDS_H /******************************************************************** * This header did contain wrapper declarations for many SCSI commands * up until sg3_utils version 1.22 . In that version, the command * wrappers were broken into two groups, the 'basic' ones found in the * "sg_cmds_basic.h" header and the 'extra' ones found in the * "sg_cmds_extra.h" header. This header now simply includes those two * headers. * In sg3_utils version 1.26 the sg_cmds_mmc.h header was added and * contains some MMC specific commands. * The corresponding function definitions are found in the sg_cmds_basic.c, * sg_cmds_extra.c and sg_cmds_mmc.c files. ********************************************************************/ #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_cmds_mmc.h" #endif sg3_utils-1.40/install-sh0000775000175000017500000003325512234470316014366 0ustar douggdougg#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: sg3_utils-1.40/README.iscsi0000664000175000017500000000242311672775076014364 0ustar douggdouggiSCSI support for sg3-utils is available from external patches. To build sg3-utils from sources and activate built-in iSCSI support you need both sg3-utils and the external user-space iSCSI library hosted at : https://github.com/sahlberg/libiscsi This library provides a client library for accessing remote iSCSI devices and also comes with patches to the sg3-utils source code distribution to compile a special version of sg3-utils with iSCSI support. No support for iSCSI is provided by the sg3-utils maintainer. Once sg3-utils is compiler and installed with libiscsi support, you can specify remote iSCSI devices through a special URL format instead of the normal /dev/* syntax. Example: sg_inq iscsi://ronnie%password@10.1.1.27/iqn.ronnie.test/1 standard INQUIRY: PQual=0 Device_type=0 RMB=0 version=0x05 [SPC-3] [AERC=0] [TrmTsk=1] NormACA=0 HiSUP=0 Resp_data_format=2 SCCS=0 ACC=0 TPGS=0 3PC=0 Protect=0 BQue=0 EncServ=0 MultiP=0 [MChngr=0] [ACKREQQ=0] Addr16=0 [RelAdr=0] WBus16=0 Sync=0 Linked=0 [TranDis=0] CmdQue=1 [SPI: Clocking=0x0 QAS=0 IUS=0] length=66 (0x42) Peripheral device type: disk Vendor identification: IET Product identification: VIRTUAL-DISK Product revision level: 0001 Unit serial number: beaf11 sg3_utils-1.40/autogen.sh0000775000175000017500000013014111171450106014345 0ustar douggdougg#!/bin/sh # a u t o g e n . s h # # Copyright (c) 2005-2007 United States Government as represented by # the U.S. Army Research Laboratory. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # 3. The name of the author may not be used to endorse or promote # products derived from this software without specific prior written # permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ### # # Script for automatically preparing the sources for compilation by # performing the myrid of necessary steps. The script attempts to # detect proper version support, and outputs warnings about particular # systems that have autotool peculiarities. # # Basically, if everything is set up and installed correctly, the # script will validate that minimum versions of the GNU Build System # tools are installed, account for several common configuration # issues, and then simply run autoreconf for you. # # If autoreconf fails, which can happen for many valid configurations, # this script proceeds to run manual preparation steps effectively # providing a POSIX shell script (mostly complete) reimplementation of # autoreconf. # # The AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER # environment variables and corresponding _OPTIONS variables (e.g. # AUTORECONF_OPTIONS) may be used to override the default automatic # detection behaviors. Similarly the _VERSION variables will override # the minimum required version numbers. # # Examples: # # To obtain help on usage: # ./autogen.sh --help # # To obtain verbose output: # ./autogen.sh --verbose # # To skip autoreconf and prepare manually: # AUTORECONF=false ./autogen.sh # # To verbosely try running with an older (unsupported) autoconf: # AUTOCONF_VERSION=2.50 ./autogen.sh --verbose # # Author: Christopher Sean Morrison # ###################################################################### # set to minimum acceptible version of autoconf if [ "x$AUTOCONF_VERSION" = "x" ] ; then AUTOCONF_VERSION=2.52 fi # set to minimum acceptible version of automake if [ "x$AUTOMAKE_VERSION" = "x" ] ; then AUTOMAKE_VERSION=1.6.0 fi # set to minimum acceptible version of libtool if [ "x$LIBTOOL_VERSION" = "x" ] ; then LIBTOOL_VERSION=1.4.2 fi ################## # ident function # ################## ident ( ) { # extract copyright from header __copyright="`grep Copyright $AUTOGEN_SH | head -${HEAD_N}1 | awk '{print $4}'`" if [ "x$__copyright" = "x" ] ; then __copyright="`date +%Y`" fi # extract version from CVS Id string __id="$Id: autogen.sh,v 14.97 2007/06/18 22:25:02 brlcad Exp $" __version="`echo $__id | sed 's/.*\([0-9][0-9][0-9][0-9]\)[-\/]\([0-9][0-9]\)[-\/]\([0-9][0-9]\).*/\1\2\3/'`" if [ "x$__version" = "x" ] ; then __version="" fi echo "autogen.sh build preparation script by Christopher Sean Morrison" echo "revised 3-clause BSD-style license, copyright (c) $__copyright" echo "script version $__version, ISO/IEC 9945 POSIX shell script" } ################## # USAGE FUNCTION # ################## usage ( ) { echo "Usage: $AUTOGEN_SH [-h|--help] [-v|--verbose] [-q|--quiet] [--version]" echo " --help Help on $NAME_OF_AUTOGEN usage" echo " --verbose Verbose progress output" echo " --quiet Quiet suppressed progress output" echo " --version Only perform GNU Build System version checks" echo echo "Description: This script will validate that minimum versions of the" echo "GNU Build System tools are installed and then run autoreconf for you." echo "Should autoreconf fail, manual preparation steps will be run" echo "potentially accounting for several common preparation issues. The" echo "AUTORECONF, AUTOCONF, AUTOMAKE, LIBTOOLIZE, ACLOCAL, AUTOHEADER," echo "PROJECT, & CONFIGURE environment variables and corresponding _OPTIONS" echo "variables (e.g. AUTORECONF_OPTIONS) may be used to override the" echo "default automatic detection behavior." echo ident return 0 } ########################## # VERSION_ERROR FUNCTION # ########################## version_error ( ) { if [ "x$1" = "x" ] ; then echo "INTERNAL ERROR: version_error was not provided a version" exit 1 fi if [ "x$2" = "x" ] ; then echo "INTERNAL ERROR: version_error was not provided an application name" exit 1 fi $ECHO $ECHO "ERROR: To prepare the ${PROJECT} build system from scratch," $ECHO " at least version $1 of $2 must be installed." $ECHO $ECHO "$NAME_OF_AUTOGEN does not need to be run on the same machine that will" $ECHO "run configure or make. Either the GNU Autotools will need to be installed" $ECHO "or upgraded on this system, or $NAME_OF_AUTOGEN must be run on the source" $ECHO "code on another system and then transferred to here. -- Cheers!" $ECHO } ########################## # VERSION_CHECK FUNCTION # ########################## version_check ( ) { if [ "x$1" = "x" ] ; then echo "INTERNAL ERROR: version_check was not provided a minimum version" exit 1 fi _min="$1" if [ "x$2" = "x" ] ; then echo "INTERNAL ERROR: version check was not provided a comparison version" exit 1 fi _cur="$2" # needed to handle versions like 1.10 and 1.4-p6 _min="`echo ${_min}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _cur="`echo ${_cur}. | sed 's/[^0-9]/./g' | sed 's/\.\././g'`" _min_major="`echo $_min | cut -d. -f1`" _min_minor="`echo $_min | cut -d. -f2`" _min_patch="`echo $_min | cut -d. -f3`" _cur_major="`echo $_cur | cut -d. -f1`" _cur_minor="`echo $_cur | cut -d. -f2`" _cur_patch="`echo $_cur | cut -d. -f3`" if [ "x$_min_major" = "x" ] ; then _min_major=0 fi if [ "x$_min_minor" = "x" ] ; then _min_minor=0 fi if [ "x$_min_patch" = "x" ] ; then _min_patch=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_major=0 fi if [ "x$_cur_minor" = "x" ] ; then _cur_minor=0 fi if [ "x$_cur_patch" = "x" ] ; then _cur_patch=0 fi $VERBOSE_ECHO "Checking if ${_cur_major}.${_cur_minor}.${_cur_patch} is greater than ${_min_major}.${_min_minor}.${_min_patch}" if [ $_min_major -lt $_cur_major ] ; then return 0 elif [ $_min_major -eq $_cur_major ] ; then if [ $_min_minor -lt $_cur_minor ] ; then return 0 elif [ $_min_minor -eq $_cur_minor ] ; then if [ $_min_patch -lt $_cur_patch ] ; then return 0 elif [ $_min_patch -eq $_cur_patch ] ; then return 0 fi fi fi return 1 } ###################################### # LOCATE_CONFIGURE_TEMPLATE FUNCTION # ###################################### locate_configure_template ( ) { _pwd="`pwd`" if test -f "./configure.ac" ; then echo "./configure.ac" elif test -f "./configure.in" ; then echo "./configure.in" elif test -f "$_pwd/configure.ac" ; then echo "$_pwd/configure.ac" elif test -f "$_pwd/configure.in" ; then echo "$_pwd/configure.in" elif test -f "$PATH_TO_AUTOGEN/configure.ac" ; then echo "$PATH_TO_AUTOGEN/configure.ac" elif test -f "$PATH_TO_AUTOGEN/configure.in" ; then echo "$PATH_TO_AUTOGEN/configure.in" fi } ################## # argument check # ################## ARGS="$*" PATH_TO_AUTOGEN="`dirname $0`" NAME_OF_AUTOGEN="`basename $0`" AUTOGEN_SH="$PATH_TO_AUTOGEN/$NAME_OF_AUTOGEN" LIBTOOL_M4="${PATH_TO_AUTOGEN}/misc/libtool.m4" if [ "x$HELP" = "x" ] ; then HELP=no fi if [ "x$QUIET" = "x" ] ; then QUIET=no fi if [ "x$VERBOSE" = "x" ] ; then VERBOSE=no fi if [ "x$VERSION_ONLY" = "x" ] ; then VERSION_ONLY=no fi if [ "x$AUTORECONF_OPTIONS" = "x" ] ; then AUTORECONF_OPTIONS="-i -f" fi if [ "x$AUTOCONF_OPTIONS" = "x" ] ; then AUTOCONF_OPTIONS="-f" fi if [ "x$AUTOMAKE_OPTIONS" = "x" ] ; then AUTOMAKE_OPTIONS="-a -c -f" fi ALT_AUTOMAKE_OPTIONS="-a -c" if [ "x$LIBTOOLIZE_OPTIONS" = "x" ] ; then LIBTOOLIZE_OPTIONS="--automake -c -f" fi ALT_LIBTOOLIZE_OPTIONS="--automake --copy --force" if [ "x$ACLOCAL_OPTIONS" = "x" ] ; then ACLOCAL_OPTIONS="" fi if [ "x$AUTOHEADER_OPTIONS" = "x" ] ; then AUTOHEADER_OPTIONS="" fi for arg in $ARGS ; do case "x$arg" in x--help) HELP=yes ;; x-[hH]) HELP=yes ;; x--quiet) QUIET=yes ;; x-[qQ]) QUIET=yes ;; x--verbose) VERBOSE=yes ;; x-[vV]) VERBOSE=yes ;; x--version) VERSION_ONLY=yes ;; *) echo "Unknown option: $arg" echo usage exit 1 ;; esac done ##################### # environment check # ##################### # sanity check before recursions potentially begin if [ ! -f "$AUTOGEN_SH" ] ; then echo "INTERNAL ERROR: $AUTOGEN_SH does not exist" if [ ! "x$0" = "x$AUTOGEN_SH" ] ; then echo "INTERNAL ERROR: dirname/basename inconsistency: $0 != $AUTOGEN_SH" fi exit 1 fi # force locale setting to C so things like date output as expected LC_ALL=C # commands that this script expects for __cmd in echo head tail pwd ; do echo "test" | $__cmd > /dev/null 2>&1 if [ $? != 0 ] ; then echo "INTERNAL ERROR: '${__cmd}' command is required" exit 2 fi done echo "test" | grep "test" > /dev/null 2>&1 if test ! x$? = x0 ; then echo "INTERNAL ERROR: grep command is required" exit 1 fi echo "test" | sed "s/test/test/" > /dev/null 2>&1 if test ! x$? = x0 ; then echo "INTERNAL ERROR: sed command is required" exit 1 fi # determine the behavior of echo case `echo "testing\c"; echo 1,2,3`,`echo -n testing; echo 1,2,3` in *c*,-n*) ECHO_N= ECHO_C=' ' ECHO_T=' ' ;; *c*,* ) ECHO_N=-n ECHO_C= ECHO_T= ;; *) ECHO_N= ECHO_C='\c' ECHO_T= ;; esac # determine the behavior of head case "x`echo 'head' | head -n 1 2>&1`" in *xhead*) HEAD_N="n " ;; *) HEAD_N="" ;; esac # determine the behavior of tail case "x`echo 'tail' | tail -n 1 2>&1`" in *xtail*) TAIL_N="n " ;; *) TAIL_N="" ;; esac VERBOSE_ECHO=: ECHO=: if [ "x$QUIET" = "xyes" ] ; then if [ "x$VERBOSE" = "xyes" ] ; then echo "Verbose output quelled by quiet option. Further output disabled." fi else ECHO=echo if [ "x$VERBOSE" = "xyes" ] ; then echo "Verbose output enabled" VERBOSE_ECHO=echo fi fi # allow a recursive run to disable further recursions if [ "x$RUN_RECURSIVE" = "x" ] ; then RUN_RECURSIVE=yes fi ################################################ # check for help arg and bypass version checks # ################################################ if [ "x`echo $ARGS | sed 's/.*[hH][eE][lL][pP].*/help/'`" = "xhelp" ] ; then HELP=yes fi if [ "x$HELP" = "xyes" ] ; then usage $ECHO "---" $ECHO "Help was requested. No preparation or configuration will be performed." exit 0 fi ####################### # set up signal traps # ####################### untrap_abnormal ( ) { for sig in 1 2 13 15; do trap - $sig done } # do this cleanup whenever we exit. trap ' # start from the root if test -d "$START_PATH" ; then cd "$START_PATH" fi # restore/delete backup files if test "x$PFC_INIT" = "x1" ; then recursive_restore fi ' 0 # trap SIGHUP (1), SIGINT (2), SIGPIPE (13), SIGTERM (15) for sig in 1 2 13 15; do trap ' $ECHO "" $ECHO "Aborting $NAME_OF_AUTOGEN: caught signal '$sig'" # start from the root if test -d "$START_PATH" ; then cd "$START_PATH" fi # clean up on abnormal exit $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache if test -f "acinclude.m4.$$.backup" ; then $VERBOSE_ECHO "cat acinclude.m4.$$.backup > acinclude.m4" chmod u+w acinclude.m4 cat acinclude.m4.$$.backup > acinclude.m4 $VERBOSE_ECHO "rm -f acinclude.m4.$$.backup" rm -f acinclude.m4.$$.backup fi { (exit 1); exit 1; } ' $sig done ############################# # look for a configure file # ############################# if [ "x$CONFIGURE" = "x" ] ; then CONFIGURE="`locate_configure_template`" if [ ! "x$CONFIGURE" = "x" ] ; then $VERBOSE_ECHO "Found a configure template: $CONFIGURE" fi else $ECHO "Using CONFIGURE environment variable override: $CONFIGURE" fi if [ "x$CONFIGURE" = "x" ] ; then if [ "x$VERSION_ONLY" = "xyes" ] ; then CONFIGURE=/dev/null else $ECHO $ECHO "A configure.ac or configure.in file could not be located implying" $ECHO "that the GNU Build System is at least not used in this directory. In" $ECHO "any case, there is nothing to do here without one of those files." $ECHO $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" exit 1 fi fi #################### # get project name # #################### if [ "x$PROJECT" = "x" ] ; then PROJECT="`grep AC_INIT $CONFIGURE | grep -v '.*#.*AC_INIT' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_INIT(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if [ "x$PROJECT" = "xAC_INIT" ] ; then # projects might be using the older/deprecated arg-less AC_INIT .. look for AM_INIT_AUTOMAKE instead PROJECT="`grep AM_INIT_AUTOMAKE $CONFIGURE | grep -v '.*#.*AM_INIT_AUTOMAKE' | tail -${TAIL_N}1 | sed 's/^[ ]*AM_INIT_AUTOMAKE(\([^,)]*\).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" fi if [ "x$PROJECT" = "xAM_INIT_AUTOMAKE" ] ; then PROJECT="project" fi if [ "x$PROJECT" = "x" ] ; then PROJECT="project" fi else $ECHO "Using PROJECT environment variable override: $PROJECT" fi $ECHO "Preparing the $PROJECT build system...please wait" $ECHO ######################## # check for autoreconf # ######################## HAVE_AUTORECONF=no if [ "x$AUTORECONF" = "x" ] ; then for AUTORECONF in autoreconf ; do $VERBOSE_ECHO "Checking autoreconf version: $AUTORECONF --version" $AUTORECONF --version > /dev/null 2>&1 if [ $? = 0 ] ; then HAVE_AUTORECONF=yes break fi done else HAVE_AUTORECONF=yes $ECHO "Using AUTORECONF environment variable override: $AUTORECONF" fi ########################## # autoconf version check # ########################## _acfound=no if [ "x$AUTOCONF" = "x" ] ; then for AUTOCONF in autoconf ; do $VERBOSE_ECHO "Checking autoconf version: $AUTOCONF --version" $AUTOCONF --version > /dev/null 2>&1 if [ $? = 0 ] ; then _acfound=yes break fi done else _acfound=yes $ECHO "Using AUTOCONF environment variable override: $AUTOCONF" fi _report_error=no if [ ! "x$_acfound" = "xyes" ] ; then $ECHO "ERROR: Unable to locate GNU Autoconf." _report_error=yes else _version="`$AUTOCONF --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Autoconf version $_version" version_check "$AUTOCONF_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$AUTOCONF_VERSION" "GNU Autoconf" exit 1 fi ########################## # automake version check # ########################## _amfound=no if [ "x$AUTOMAKE" = "x" ] ; then for AUTOMAKE in automake ; do $VERBOSE_ECHO "Checking automake version: $AUTOMAKE --version" $AUTOMAKE --version > /dev/null 2>&1 if [ $? = 0 ] ; then _amfound=yes break fi done else _amfound=yes $ECHO "Using AUTOMAKE environment variable override: $AUTOMAKE" fi _report_error=no if [ ! "x$_amfound" = "xyes" ] ; then $ECHO $ECHO "ERROR: Unable to locate GNU Automake." _report_error=yes else _version="`$AUTOMAKE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Automake version $_version" version_check "$AUTOMAKE_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$AUTOMAKE_VERSION" "GNU Automake" exit 1 fi ######################## # check for libtoolize # ######################## HAVE_LIBTOOLIZE=yes HAVE_ALT_LIBTOOLIZE=no _ltfound=no if [ "x$LIBTOOLIZE" = "x" ] ; then LIBTOOLIZE=libtoolize $VERBOSE_ECHO "Checking libtoolize version: $LIBTOOLIZE --version" $LIBTOOLIZE --version > /dev/null 2>&1 if [ ! $? = 0 ] ; then HAVE_LIBTOOLIZE=no $ECHO if [ "x$HAVE_AUTORECONF" = "xno" ] ; then $ECHO "Warning: libtoolize does not appear to be available." else $ECHO "Warning: libtoolize does not appear to be available. This means that" $ECHO "the automatic build preparation via autoreconf will probably not work." $ECHO "Preparing the build by running each step individually, however, should" $ECHO "work and will be done automatically for you if autoreconf fails." fi # look for some alternates for tool in glibtoolize libtoolize15 libtoolize14 libtoolize13 ; do $VERBOSE_ECHO "Checking libtoolize alternate: $tool --version" _glibtoolize="`$tool --version > /dev/null 2>&1`" if [ $? = 0 ] ; then $VERBOSE_ECHO "Found $tool --version" _glti="`which $tool`" if [ "x$_glti" = "x" ] ; then $VERBOSE_ECHO "Cannot find $tool with which" continue; fi if test ! -f "$_glti" ; then $VERBOSE_ECHO "Cannot use $tool, $_glti is not a file" continue; fi _gltidir="`dirname $_glti`" if [ "x$_gltidir" = "x" ] ; then $VERBOSE_ECHO "Cannot find $tool path with dirname of $_glti" continue; fi if test ! -d "$_gltidir" ; then $VERBOSE_ECHO "Cannot use $tool, $_gltidir is not a directory" continue; fi HAVE_ALT_LIBTOOLIZE=yes LIBTOOLIZE="$tool" $ECHO $ECHO "Fortunately, $tool was found which means that your system may simply" $ECHO "have a non-standard or incomplete GNU Autotools install. If you have" $ECHO "sufficient system access, it may be possible to quell this warning by" $ECHO "running:" $ECHO sudo -V > /dev/null 2>&1 if [ $? = 0 ] ; then $ECHO " sudo ln -s $_glti $_gltidir/libtoolize" $ECHO else $ECHO " ln -s $_glti $_gltidir/libtoolize" $ECHO $ECHO "Run that as root or with proper permissions to the $_gltidir directory" $ECHO fi _ltfound=yes break fi done else _ltfound=yes fi else _ltfound=yes $ECHO "Using LIBTOOLIZE environment variable override: $LIBTOOLIZE" fi ############################ # libtoolize version check # ############################ _report_error=no if [ ! "x$_ltfound" = "xyes" ] ; then $ECHO $ECHO "ERROR: Unable to locate GNU Libtool." _report_error=yes else _version="`$LIBTOOLIZE --version | head -${HEAD_N}1 | sed 's/[^0-9]*\([0-9\.][0-9\.]*\)/\1/'`" if [ "x$_version" = "x" ] ; then _version="0.0.0" fi $ECHO "Found GNU Libtool version $_version" version_check "$LIBTOOL_VERSION" "$_version" if [ $? -ne 0 ] ; then _report_error=yes fi fi if [ "x$_report_error" = "xyes" ] ; then version_error "$LIBTOOL_VERSION" "GNU Libtool" exit 1 fi ##################### # check for aclocal # ##################### if [ "x$ACLOCAL" = "x" ] ; then for ACLOCAL in aclocal ; do $VERBOSE_ECHO "Checking aclocal version: $ACLOCAL --version" $ACLOCAL --version > /dev/null 2>&1 if [ $? = 0 ] ; then break fi done else $ECHO "Using ACLOCAL environment variable override: $ACLOCAL" fi ######################## # check for autoheader # ######################## if [ "x$AUTOHEADER" = "x" ] ; then for AUTOHEADER in autoheader ; do $VERBOSE_ECHO "Checking autoheader version: $AUTOHEADER --version" $AUTOHEADER --version > /dev/null 2>&1 if [ $? = 0 ] ; then break fi done else $ECHO "Using AUTOHEADER environment variable override: $AUTOHEADER" fi ######################### # check if version only # ######################### $VERBOSE_ECHO "Checking whether to only output version information" if [ "x$VERSION_ONLY" = "xyes" ] ; then $ECHO ident $ECHO "---" $ECHO "Version requested. No preparation or configuration will be performed." exit 0 fi ################################# # PROTECT_FROM_CLOBBER FUNCTION # ################################# protect_from_clobber ( ) { PFC_INIT=1 # protect COPYING & INSTALL from overwrite by automake. the # automake force option will (inappropriately) ignore the existing # contents of a COPYING and/or INSTALL files (depending on the # version) instead of just forcing *missing* files like it does # for AUTHORS, NEWS, and README. this is broken but extremely # prevalent behavior, so we protect against it by keeping a backup # of the file that can later be restored. if test -f COPYING ; then if test -f COPYING.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "Already backed up COPYING in `pwd`" else $VERBOSE_ECHO "Backing up COPYING in `pwd`" $VERBOSE_ECHO "cp -p COPYING COPYING.$$.protect_from_automake.backup" cp -p COPYING COPYING.$$.protect_from_automake.backup fi fi if test -f INSTALL ; then if test -f INSTALL.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "Already backed up INSTALL in `pwd`" else $VERBOSE_ECHO "Backing up INSTALL in `pwd`" $VERBOSE_ECHO "cp -p INSTALL INSTALL.$$.protect_from_automake.backup" cp -p INSTALL INSTALL.$$.protect_from_automake.backup fi fi } ############################## # RECURSIVE_PROTECT FUNCTION # ############################## recursive_protect ( ) { # for projects using recursive configure, run the build # preparation steps for the subdirectories. this function assumes # START_PATH was set to pwd before recursion begins so that # relative paths work. # git 'r done, protect COPYING and INSTALL from being clobbered protect_from_clobber if test -d autom4te.cache ; then $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache fi # find configure template _configure="`locate_configure_template`" if [ "x$_configure" = "x" ] ; then return fi # $VERBOSE_ECHO "Looking for configure template found `pwd`/$_configure" # look for subdirs # $VERBOSE_ECHO "Looking for subdirs in `pwd`" _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" CHECK_DIRS="" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" fi done # process subdirs if [ ! "x$CHECK_DIRS" = "x" ] ; then $VERBOSE_ECHO "Recursively scanning the following directories:" $VERBOSE_ECHO " $CHECK_DIRS" for dir in $CHECK_DIRS ; do $VERBOSE_ECHO "Protecting files from automake in $dir" cd "$START_PATH" eval "cd $dir" # recursively git 'r done recursive_protect done fi } # end of recursive_protect ############################# # RESTORE_CLOBBERED FUNCION # ############################# restore_clobbered ( ) { # The automake (and autoreconf by extension) -f/--force-missing # option may overwrite COPYING and INSTALL even if they do exist. # Here we restore the files if necessary. spacer=no # COPYING if test -f COPYING.$$.protect_from_automake.backup ; then if test -f COPYING ; then # compare entire content, restore if needed if test "x`cat COPYING`" != "x`cat COPYING.$$.protect_from_automake.backup`" ; then if test "x$spacer" = "xno" ; then $VERBOSE_ECHO spacer=yes fi # restore the backup $VERBOSE_ECHO "Restoring COPYING from backup (automake -f likely clobbered it)" $VERBOSE_ECHO "rm -f COPYING" rm -f COPYING $VERBOSE_ECHO "mv COPYING.$$.protect_from_automake.backup COPYING" mv COPYING.$$.protect_from_automake.backup COPYING fi # check contents elif test -f COPYING.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "mv COPYING.$$.protect_from_automake.backup COPYING" mv COPYING.$$.protect_from_automake.backup COPYING fi # -f COPYING # just in case $VERBOSE_ECHO "rm -f COPYING.$$.protect_from_automake.backup" rm -f COPYING.$$.protect_from_automake.backup fi # -f COPYING.$$.protect_from_automake.backup # INSTALL if test -f INSTALL.$$.protect_from_automake.backup ; then if test -f INSTALL ; then # compare entire content, restore if needed if test "x`cat INSTALL`" != "x`cat INSTALL.$$.protect_from_automake.backup`" ; then if test "x$spacer" = "xno" ; then $VERBOSE_ECHO spacer=yes fi # restore the backup $VERBOSE_ECHO "Restoring INSTALL from backup (automake -f likely clobbered it)" $VERBOSE_ECHO "rm -f INSTALL" rm -f INSTALL $VERBOSE_ECHO "mv INSTALL.$$.protect_from_automake.backup INSTALL" mv INSTALL.$$.protect_from_automake.backup INSTALL fi # check contents elif test -f INSTALL.$$.protect_from_automake.backup ; then $VERBOSE_ECHO "mv INSTALL.$$.protect_from_automake.backup INSTALL" mv INSTALL.$$.protect_from_automake.backup INSTALL fi # -f INSTALL # just in case $VERBOSE_ECHO "rm -f INSTALL.$$.protect_from_automake.backup" rm -f INSTALL.$$.protect_from_automake.backup fi # -f INSTALL.$$.protect_from_automake.backup CONFIGURE="`locate_configure_template`" if [ "x$CONFIGURE" = "x" ] ; then return fi _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if test ! -d "$_aux_dir" ; then _aux_dir=. fi for file in config.guess config.sub ltmain.sh ; do if test -f "${_aux_dir}/${file}" ; then $VERBOSE_ECHO "rm -f \"${_aux_dir}/${file}.backup\"" rm -f "${_aux_dir}/${file}.backup" fi done } # end of restore_clobbered ############################## # RECURSIVE_RESTORE FUNCTION # ############################## recursive_restore ( ) { # restore COPYING and INSTALL from backup if they were clobbered # for each directory recursively. # git 'r undone restore_clobbered # find configure template _configure="`locate_configure_template`" if [ "x$_configure" = "x" ] ; then return fi # look for subdirs _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $_configure | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" CHECK_DIRS="" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then CHECK_DIRS="$CHECK_DIRS \"`pwd`/$dir\"" fi done # process subdirs if [ ! "x$CHECK_DIRS" = "x" ] ; then $VERBOSE_ECHO "Recursively scanning the following directories:" $VERBOSE_ECHO " $CHECK_DIRS" for dir in $CHECK_DIRS ; do $VERBOSE_ECHO "Checking files for automake damage in $dir" cd "$START_PATH" eval "cd $dir" # recursively git 'r undone recursive_restore done fi } # end of recursive_restore ####################### # INITIALIZE FUNCTION # ####################### initialize ( ) { # this routine performs a variety of directory-specific # initializations. some are sanity checks, some are preventive, # and some are necessary setup detection. # # this function sets: # CONFIGURE # SEARCH_DIRS # CONFIG_SUBDIRS ################################## # check for a configure template # ################################## CONFIGURE="`locate_configure_template`" if [ "x$CONFIGURE" = "x" ] ; then $ECHO $ECHO "A configure.ac or configure.in file could not be located implying" $ECHO "that the GNU Build System is at least not used in this directory. In" $ECHO "any case, there is nothing to do here without one of those files." $ECHO $ECHO "ERROR: No configure.in or configure.ac file found in `pwd`" exit 1 fi ##################### # detect an aux dir # ##################### _aux_dir="`grep AC_CONFIG_AUX_DIR $CONFIGURE | grep -v '.*#.*AC_CONFIG_AUX_DIR' | tail -${TAIL_N}1 | sed 's/^[ ]*AC_CONFIG_AUX_DIR(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" if test ! -d "$_aux_dir" ; then _aux_dir=. else $VERBOSE_ECHO "Detected auxillary directory: $_aux_dir" fi ################################ # detect a recursive configure # ################################ CONFIG_SUBDIRS="" _det_config_subdirs="`grep AC_CONFIG_SUBDIRS $CONFIGURE | grep -v '.*#.*AC_CONFIG_SUBDIRS' | sed 's/^[ ]*AC_CONFIG_SUBDIRS(\(.*\)).*/\1/' | sed 's/.*\[\(.*\)\].*/\1/'`" for dir in $_det_config_subdirs ; do if test -d "`pwd`/$dir" ; then $VERBOSE_ECHO "Detected recursive configure directory: `pwd`/$dir" CONFIG_SUBDIRS="$CONFIG_SUBDIRS `pwd`/$dir" fi done ########################################## # make sure certain required files exist # ########################################## for file in AUTHORS COPYING ChangeLog INSTALL NEWS README ; do if test ! -f $file ; then $VERBOSE_ECHO "Touching ${file} since it does not exist" touch $file fi done ################################################## # make sure certain generated files do not exist # ################################################## for file in config.guess config.sub ltmain.sh ; do if test -f "${_aux_dir}/${file}" ; then $VERBOSE_ECHO "mv -f \"${_aux_dir}/${file}\" \"${_aux_dir}/${file}.backup\"" mv -f "${_aux_dir}/${file}" "${_aux_dir}/${file}.backup" fi done ############################ # search alternate m4 dirs # ############################ SEARCH_DIRS="" for dir in m4 ; do if [ -d $dir ] ; then $VERBOSE_ECHO "Found extra aclocal search directory: $dir" SEARCH_DIRS="$SEARCH_DIRS -I $dir" fi done ###################################### # remove any previous build products # ###################################### if test -d autom4te.cache ; then $VERBOSE_ECHO "Found an autom4te.cache directory, deleting it" $VERBOSE_ECHO "rm -rf autom4te.cache" rm -rf autom4te.cache fi # tcl/tk (and probably others) have a customized aclocal.m4, so can't delete it # if test -f aclocal.m4 ; then # $VERBOSE_ECHO "Found an aclocal.m4 file, deleting it" # $VERBOSE_ECHO "rm -f aclocal.m4" # rm -f aclocal.m4 # fi } # end of initialize() ############## # initialize # ############## # stash path START_PATH="`pwd`" # Before running autoreconf or manual steps, some prep detection work # is necessary or useful. Only needs to occur once per directory, but # does need to traverse the entire subconfigure hierarchy to protect # files from being clobbered even by autoreconf. recursive_protect # start from where we started cd "$START_PATH" # get ready to process initialize ############################################ # prepare build via autoreconf or manually # ############################################ reconfigure_manually=no if [ "x$HAVE_AUTORECONF" = "xyes" ] ; then $ECHO $ECHO $ECHO_N "Automatically preparing build ... $ECHO_C" $VERBOSE_ECHO "$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS" autoreconf_output="`$AUTORECONF $SEARCH_DIRS $AUTORECONF_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$autoreconf_output" if [ ! $ret = 0 ] ; then if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then if [ ! "x`echo \"$autoreconf_output\" | grep libtoolize | grep \"No such file or directory\"`" = "x" ] ; then $ECHO $ECHO "Warning: autoreconf failed but due to what is usually a common libtool" $ECHO "misconfiguration issue. This problem is encountered on systems that" $ECHO "have installed libtoolize under a different name without providing a" $ECHO "symbolic link or without setting the LIBTOOLIZE environment variable." $ECHO $ECHO "Restarting the preparation steps with LIBTOOLIZE set to $LIBTOOLIZE" export LIBTOOLIZE RUN_RECURSIVE=no export RUN_RECURSIVE untrap_abnormal $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" exit $? fi fi $ECHO "Warning: $AUTORECONF failed" if test -f ltmain.sh ; then $ECHO "libtoolize being run by autoreconf is not creating ltmain.sh in the auxillary directory like it should" fi $ECHO "Attempting to run the preparation steps individually" reconfigure_manually=yes fi else reconfigure_manually=yes fi ############################ # LIBTOOL_FAILURE FUNCTION # ############################ libtool_failure ( ) { # libtool is rather error-prone in comparison to the other # autotools and this routine attempts to compensate for some # common failures. the output after a libtoolize failure is # parsed for an error related to AC_PROG_LIBTOOL and if found, we # attempt to inject a project-provided libtool.m4 file. _autoconf_output="$1" if [ "x$RUN_RECURSIVE" = "xno" ] ; then # we already tried the libtool.m4, don't try again return 1 fi if test -f "$LIBTOOL_M4" ; then found_libtool="`$ECHO $_autoconf_output | grep AC_PROG_LIBTOOL`" if test ! "x$found_libtool" = "x" ; then if test -f acinclude.m4 ; then rm -f acinclude.m4.$$.backup $VERBOSE_ECHO "cat acinclude.m4 > acinclude.m4.$$.backup" cat acinclude.m4 > acinclude.m4.$$.backup fi $VERBOSE_ECHO "cat \"$LIBTOOL_M4\" >> acinclude.m4" chmod u+w acinclude.m4 cat "$LIBTOOL_M4" >> acinclude.m4 # don't keep doing this RUN_RECURSIVE=no export RUN_RECURSIVE untrap_abnormal $ECHO $ECHO "Restarting the preparation steps with libtool macros in acinclude.m4" $VERBOSE_ECHO sh $AUTOGEN_SH "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" sh "$AUTOGEN_SH" "$1" "$2" "$3" "$4" "$5" "$6" "$7" "$8" "$9" exit $? fi fi } ########################### # MANUAL_AUTOGEN FUNCTION # ########################### manual_autogen ( ) { ################################################## # Manual preparation steps taken are as follows: # # aclocal [-I m4] # # libtoolize --automake -c -f # # aclocal [-I m4] # # autoconf -f # # autoheader # # automake -a -c -f # ################################################## ########### # aclocal # ########### $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$aclocal_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $ACLOCAL failed" && exit 2 ; fi ############## # libtoolize # ############## need_libtoolize=no for feature in AC_PROG_LIBTOOL LT_INIT ; do $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" found="`grep \"^$feature.*\" $CONFIGURE`" if [ ! "x$found" = "x" ] ; then need_libtoolize=yes break fi done if [ "x$need_libtoolize" = "xyes" ] ; then if [ "x$HAVE_LIBTOOLIZE" = "xyes" ] ; then $VERBOSE_ECHO "$LIBTOOLIZE $LIBTOOLIZE_OPTIONS" libtoolize_output="`$LIBTOOLIZE $LIBTOOLIZE_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$libtoolize_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi else if [ "x$HAVE_ALT_LIBTOOLIZE" = "xyes" ] ; then $VERBOSE_ECHO "$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS" libtoolize_output="`$LIBTOOLIZE $ALT_LIBTOOLIZE_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$libtoolize_output" if [ ! $ret = 0 ] ; then $ECHO "ERROR: $LIBTOOLIZE failed" && exit 2 ; fi fi fi ########### # aclocal # ########### # re-run again as instructed by libtoolize $VERBOSE_ECHO "$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS" aclocal_output="`$ACLOCAL $SEARCH_DIRS $ACLOCAL_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$aclocal_output" # libtoolize might put ltmain.sh in the wrong place if test -f ltmain.sh ; then if test ! -f "${_aux_dir}/ltmain.sh" ; then $ECHO $ECHO "Warning: $LIBTOOLIZE is creating ltmain.sh in the wrong directory" $ECHO $ECHO "Fortunately, the problem can be worked around by simply copying the" $ECHO "file to the appropriate location (${_aux_dir}/). This has been done for you." $ECHO $VERBOSE_ECHO "cp -p ltmain.sh \"${_aux_dir}/ltmain.sh\"" cp -p ltmain.sh "${_aux_dir}/ltmain.sh" $ECHO $ECHO_N "Continuing build preparation ... $ECHO_C" fi fi # ltmain.sh fi # need_libtoolize ############ # autoconf # ############ $VERBOSE_ECHO $VERBOSE_ECHO "$AUTOCONF $AUTOCONF_OPTIONS" autoconf_output="`$AUTOCONF $AUTOCONF_OPTIONS 2>&1`" ret=$? $VERBOSE_ECHO "$autoconf_output" if [ ! $ret = 0 ] ; then # retry without the -f and check for usage of macros that are too new ac2_59_macros="AC_C_RESTRICT AC_INCLUDES_DEFAULT AC_LANG_ASSERT AC_LANG_WERROR AS_SET_CATFILE" ac2_55_macros="AC_COMPILER_IFELSE AC_FUNC_MBRTOWC AC_HEADER_STDBOOL AC_LANG_CONFTEST AC_LANG_SOURCE AC_LANG_PROGRAM AC_LANG_CALL AC_LANG_FUNC_TRY_LINK AC_MSG_FAILURE AC_PREPROC_IFELSE" ac2_54_macros="AC_C_BACKSLASH_A AC_CONFIG_LIBOBJ_DIR AC_GNU_SOURCE AC_PROG_EGREP AC_PROG_FGREP AC_REPLACE_FNMATCH AC_FUNC_FNMATCH_GNU AC_FUNC_REALLOC AC_TYPE_MBSTATE_T" macros_to_search="" ac_major="`echo ${AUTOCONF_VERSION}. | cut -d. -f1 | sed 's/[^0-9]//g'`" ac_minor="`echo ${AUTOCONF_VERSION}. | cut -d. -f2 | sed 's/[^0-9]//g'`" if [ $ac_major -lt 2 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" else if [ $ac_minor -lt 54 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros $ac2_54_macros" elif [ $ac_minor -lt 55 ] ; then macros_to_search="$ac2_59_macros $ac2_55_macros" elif [ $ac_minor -lt 59 ] ; then macros_to_search="$ac2_59_macros" fi fi configure_ac_macros=__none__ for feature in $macros_to_search ; do $VERBOSE_ECHO "Searching for $feature in $CONFIGURE" found="`grep \"^$feature.*\" $CONFIGURE`" if [ ! "x$found" = "x" ] ; then if [ "x$configure_ac_macros" = "x__none__" ] ; then configure_ac_macros="$feature" else configure_ac_macros="$feature $configure_ac_macros" fi fi done if [ ! "x$configure_ac_macros" = "x__none__" ] ; then $ECHO $ECHO "Warning: Unsupported macros were found in $CONFIGURE" $ECHO $ECHO "The `echo $CONFIGURE | basename` file was scanned in order to determine if any" $ECHO "unsupported macros are used that exceed the minimum version" $ECHO "settings specified within this file. As such, the following macros" $ECHO "should be removed from configure.ac or the version numbers in this" $ECHO "file should be increased:" $ECHO $ECHO "$configure_ac_macros" $ECHO $ECHO $ECHO_N "Ignorantly continuing build preparation ... $ECHO_C" fi ################### # autoconf, retry # ################### $VERBOSE_ECHO $VERBOSE_ECHO "$AUTOCONF" autoconf_output="`$AUTOCONF 2>&1`" ret=$? $VERBOSE_ECHO "$autoconf_output" if [ ! $ret = 0 ] ; then # test if libtool is busted libtool_failure "$autoconf_output" # let the user know what went wrong cat <. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2013 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 \ | or1k | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or1k-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: sg3_utils-1.40/scripts/0000755000175000017500000000000012431015530014027 5ustar douggdouggsg3_utils-1.40/scripts/rescan-scsi-bus.sh0000775000175000017500000010216712270322342017403 0ustar douggdougg#!/bin/bash # Skript to rescan SCSI bus, using the # scsi add-single-device mechanism # (c) 1998--2010 Kurt Garloff , GNU GPL v2 or v3 # (c) 2006--2014 Hannes Reinecke, GNU GPL v2 or later # $Id: rescan-scsi-bus.sh,v 1.57 2012/03/31 14:08:48 garloff Exp $ SCAN_WILD_CARD=4294967295 setcolor () { red="\e[0;31m" green="\e[0;32m" yellow="\e[0;33m" bold="\e[0;1m" norm="\e[0;0m" } unsetcolor () { red=""; green="" yellow=""; norm="" } echo_debug() { if [ $debug -eq 1 ] ; then echo "$1" fi } # Output some text and return cursor to previous position # (only works for simple strings) # Stores length of string in LN and returns it print_and_scroll_back () { STRG="$1" LN=${#STRG} BK="" declare -i cntr=0 while test $cntr -lt $LN; do BK="$BK\e[D"; let cntr+=1; done echo -en "$STRG$BK" return $LN } # Overwrite a text of length $1 (fallback to $LN) with whitespace white_out () { BK=""; WH="" if test -n "$1"; then LN=$1; fi declare -i cntr=0 while test $cntr -lt $LN; do BK="$BK\e[D"; WH="$WH "; let cntr+=1; done echo -en "$WH$BK" } # Return hosts. sysfs must be mounted findhosts_26 () { hosts=`find /sys/class/scsi_host/host* -maxdepth 4 -type d -o -type l 2> /dev/null | awk -F'/' '{print $5}' | sed -e 's~host~~' | sort -nu` scsi_host_data=`echo "$hosts" | sed -e 's~^~/sys/class/scsi_host/host~'` for hostdir in $scsi_host_data; do hostno=${hostdir#/sys/class/scsi_host/host} if [ -f $hostdir/isp_name ] ; then hostname="qla2xxx" elif [ -f $hostdir/lpfc_drvr_version ] ; then hostname="lpfc" else hostname=`cat $hostdir/proc_name` fi #hosts="$hosts $hostno" echo_debug "Host adapter $hostno ($hostname) found." done if [ -z "$hosts" ] ; then echo "No SCSI host adapters found in sysfs" exit 1; fi # Not necessary just use double quotes around variable to preserve new lines #hosts=`echo $hosts | tr ' ' '\n'` } # Return hosts. /proc/scsi/HOSTADAPTER/? must exist findhosts () { hosts= for driverdir in /proc/scsi/*; do driver=${driverdir#/proc/scsi/} if test $driver = scsi -o $driver = sg -o $driver = dummy -o $driver = device_info; then continue; fi for hostdir in $driverdir/*; do name=${hostdir#/proc/scsi/*/} if test $name = add_map -o $name = map -o $name = mod_parm; then continue; fi num=$name driverinfo=$driver if test -r $hostdir/status; then num=$(printf '%d\n' `sed -n 's/SCSI host number://p' $hostdir/status`) driverinfo="$driver:$name" fi hosts="$hosts $num" echo "Host adapter $num ($driverinfo) found." done done } printtype () { local type=$1 case "$type" in 0) echo "Direct-Access " ;; 1) echo "Sequential-Access" ;; 2) echo "Printer " ;; 3) echo "Processor " ;; 4) echo "WORM " ;; 5) echo "CD-ROM " ;; 6) echo "Scanner " ;; 7) echo "Optical Device " ;; 8) echo "Medium Changer " ;; 9) echo "Communications " ;; 10) echo "Unknown " ;; 11) echo "Unknown " ;; 12) echo "RAID " ;; 13) echo "Enclosure " ;; 14) echo "Direct-Access-RBC" ;; *) echo "Unknown " ;; esac } print02i() { if [ "$1" = "*" ] ; then echo "00" else printf "%02i" "$1" fi } # Get /proc/scsi/scsi info for device $host:$channel:$id:$lun # Optional parameter: Number of lines after first (default = 2), # result in SCSISTR, return code 1 means empty. procscsiscsi () { if test -z "$1"; then LN=2; else LN=$1; fi CHANNEL=`print02i "$channel"` ID=`print02i "$id"` LUN=`print02i "$lun"` if [ -d /sys/class/scsi_device ]; then SCSIPATH="/sys/class/scsi_device/${host}:${channel}:${id}:${lun}" if [ -d "$SCSIPATH" ] ; then SCSISTR="Host: scsi${host} Channel: $CHANNEL Id: $ID Lun: $LUN" if [ "$LN" -gt 0 ] ; then IVEND=$(cat ${SCSIPATH}/device/vendor) IPROD=$(cat ${SCSIPATH}/device/model) IPREV=$(cat ${SCSIPATH}/device/rev) SCSIDEV=$(printf ' Vendor: %-08s Model: %-16s Rev: %-4s' "$IVEND" "$IPROD" "$IPREV") SCSISTR="$SCSISTR $SCSIDEV" fi if [ "$LN" -gt 1 ] ; then ILVL=$(cat ${SCSIPATH}/device/scsi_level) type=$(cat ${SCSIPATH}/device/type) ITYPE=$(printtype $type) SCSITMP=$(printf ' Type: %-16s ANSI SCSI revision: %02d' "$ITYPE" "$((ILVL - 1))") SCSISTR="$SCSISTR $SCSITMP" fi else return 1 fi else grepstr="scsi$host Channel: $CHANNEL Id: $ID Lun: $LUN" SCSISTR=`cat /proc/scsi/scsi | grep -A$LN -e"$grepstr"` fi if test -z "$SCSISTR"; then return 1; else return 0; fi } # Find sg device with 2.6 sysfs support sgdevice26 () { if test -e /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic; then SGDEV=`readlink /sys/class/scsi_device/$host\:$channel\:$id\:$lun/device/generic` SGDEV=`basename $SGDEV` else for SGDEV in /sys/class/scsi_generic/sg*; do DEV=`readlink $SGDEV/device` if test "${DEV##*/}" = "$host:$channel:$id:$lun"; then SGDEV=`basename $SGDEV`; return fi done SGDEV="" fi } # Find sg device with 2.4 report-devs extensions sgdevice24 () { if procscsiscsi 3; then SGDEV=`echo "$SCSISTR" | grep 'Attached drivers:' | sed 's/^ *Attached drivers: \(sg[0-9]*\).*/\1/'` fi } # Find sg device that belongs to SCSI device $host $channel $id $lun # and return in SGDEV sgdevice () { SGDEV= if test -d /sys/class/scsi_device; then sgdevice26 else DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null` repdevstat=$((1-$?)) if [ $repdevstat = 0 ]; then echo "scsi report-devs 1" >/proc/scsi/scsi DRV=`grep 'Attached drivers:' /proc/scsi/scsi 2>/dev/null` if [ $? = 1 ]; then return; fi fi if ! `echo $DRV | grep 'drivers: sg' >/dev/null`; then modprobe sg fi sgdevice24 if [ $repdevstat = 0 ]; then echo "scsi report-devs 0" >/proc/scsi/scsi fi fi } # Test if SCSI device is still responding to commands # Return values: # 0 device is present # 1 device has changed # 2 device has been removed testonline () { : testonline RC=0 if test ! -x /usr/bin/sg_turs; then return 0; fi sgdevice if test -z "$SGDEV"; then return 0; fi sg_turs /dev/$SGDEV >/dev/null 2>&1 RC=$? # Handle in progress of becoming ready and unit attention -- wait at max 11s declare -i ctr=0 if test $RC = 2 -o $RC = 6; then RMB=`sg_inq /dev/$SGDEV | grep 'RMB=' | sed 's/^.*RMB=\(.\).*$/\1/'` print_and_scroll_back "$host:$channel:$id:$lun $SGDEV ($RMB) " fi while test $RC = 2 -o $RC = 6 && test $ctr -le 8; do if test $RC = 2 -a "$RMB" != "1"; then echo -n "."; let LN+=1; sleep 1 else usleep 20000; fi let ctr+=1 sg_turs /dev/$SGDEV >/dev/null 2>&1 RC=$? done if test $ctr != 0; then white_out; fi # echo -e "\e[A\e[A\e[A${yellow}Test existence of $SGDEV = $RC ${norm} \n\n\n" if test $RC = 1; then return $RC; fi # Reset RC (might be !=0 for passive paths) RC=0 # OK, device online, compare INQUIRY string INQ=`sg_inq $sg_len_arg /dev/$SGDEV 2>/dev/null` IVEND=`echo "$INQ" | grep 'Vendor identification:' | sed 's/^[^:]*: \(.*\)$/\1/'` IPROD=`echo "$INQ" | grep 'Product identification:' | sed 's/^[^:]*: \(.*\)$/\1/'` IPREV=`echo "$INQ" | grep 'Product revision level:' | sed 's/^[^:]*: \(.*\)$/\1/'` STR=`printf " Vendor: %-08s Model: %-16s Rev: %-4s" "$IVEND" "$IPROD" "$IPREV"` IPTYPE=`echo "$INQ" | sed -n 's/.* Device_type=\([0-9]*\) .*/\1/p'` IPQUAL=`echo "$INQ" | sed -n 's/ *PQual=\([0-9]*\) Device.*/\1/p'` if [ "$IPQUAL" != 0 ] ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}LU not available (PQual $IPQUAL)${norm} \n\n\n" return 2 fi TYPE=$(printtype $IPTYPE) if ! procscsiscsi ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV removed.\n\n\n" return 2 fi TMPSTR=`echo "$SCSISTR" | grep 'Vendor:'` if [ "$TMPSTR" != "$STR" ]; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${SCSISTR#* } \nto: $STR ${norm} \n\n\n" return 1 fi TMPSTR=`echo "$SCSISTR" | sed -n 's/.*Type: *\(.*\) *ANSI.*/\1/p'` if [ $TMPSTR != $TYPE ] ; then echo -e "\e[A\e[A\e[A\e[A${red}$SGDEV changed: ${bold}\nfrom:${TMPSTR} \nto: $TYPE ${norm} \n\n\n" return 1 fi return $RC } # Test if SCSI device $host $channen $id $lun exists # Outputs description from /proc/scsi/scsi (unless arg passed) # Returns SCSISTR (empty if no dev) testexist () { : testexist SCSISTR= if procscsiscsi && test -z "$1"; then echo "$SCSISTR" | head -n1 echo "$SCSISTR" | tail -n2 | pr -o4 -l1 fi } # Returns the list of existing channels per host chanlist () { local hcil local cil local chan local tmpchan for dev in /sys/class/scsi_device/${host}:* ; do [ -d $dev ] || continue; hcil=${dev##*/} cil=${hcil#*:} chan=${cil%%:*} for tmpchan in $channelsearch ; do if test "$chan" -eq $tmpchan ; then chan= fi done if test -n "$chan" ; then channelsearch="$channelsearch $chan" fi done if test -z "$channelsearch"; then channelsearch="0"; fi } # Returns the list of existing targets per host idlist () { local hcil local target local tmpid local newid idsearch=$(ls /sys/class/scsi_device/ | sed -n "s/${host}:${channel}:\([0-9]*\):[0-9]*/\1/p" | uniq) echo "${channel} - -" > /sys/class/scsi_host/host${host}/scan # Rescan to check if we found new targets newsearch=$(ls /sys/class/scsi_device/ | sed -n "s/${host}:${channel}:\([0-9]*\):[0-9]*/\1/p" | uniq) for id in $newsearch ; do newid=$id for tmpid in $idsearch ; do if test $id -eq $tmpid ; then newid= break fi done if test -n "$newid" ; then id=$newid for dev in /sys/class/scsi_device/${host}:${channel}:${newid}:* ; do [ -d $dev ] || continue; hcil=${dev##*/} lun=${hcil##*:} printf "\r${green}NEW: $norm" testexist if test "$SCSISTR" ; then incrfound "$hcil" fi done fi done } # Returns the list of existing LUNs from device $host $channel $id $lun # and returns list to stdout getluns() { sgdevice if test -z "$SGDEV"; then return 1; fi if test ! -x /usr/bin/sg_luns; then echo 0; return 1; fi LLUN=`sg_luns /dev/$SGDEV 2>/dev/null | sed -n 's/ \(.*\)/\1/p'` # Added -z $LLUN condition because $? gets the RC from sed, not sg_luns if test $? != 0 -o -z "$LLUN"; then echo 0; return 1; fi for lun in $LLUN ; do # Swap LUN number l0=$(printf '%u' 0x$lun) l1=$(( ($l0 >> 48) & 0xffff )) l2=$(( ($l0 >> 32) & 0xffff )) l3=$(( ($l0 >> 16) & 0xffff )) l4=$(( $l0 & 0xffff )) l0=$(( ( ( ($l4 * 0xffff) + $l3 ) * 0xffff + $l2 ) * 0xffff + $l1 )) printf "%u\n" $l0 done return 0 } # Wait for udev to settle (create device nodes etc.) udevadm_settle() { if test -x /sbin/udevadm; then print_and_scroll_back " Calling udevadm settle (can take a while) " /sbin/udevadm settle white_out elif test -x /sbin/udevsettle; then print_and_scroll_back " Calling udevsettle (can take a while) " /sbin/udevsettle white_out else usleep 20000 fi } # Perform scan on a single lun $host $channel $id $lun dolunscan() { local remappedlun0= SCSISTR= devnr="$host $channel $id $lun" echo -e " Scanning for device $devnr ... " printf "${yellow}OLD: $norm" testexist # Device exists: Test whether it's still online # (testonline returns 2 if it's gone and 1 if it has changed) if test "$SCSISTR" ; then testonline RC=$? # Well known lun transition case. Only for Direct-Access devs (type 0) # If block directory exists && and PQUAL != 0, we unmapped lun0 and just have a well-known lun # If block directory doesn't exist && PQUAL == 0, we mapped a real lun0 if test $lun -eq 0 -a $IPTYPE -eq 0 ; then if test $RC = 2 ; then if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then if test -d /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/block ; then remappedlun0=2 # Transition from real lun 0 to well-known else RC=0 # Set this so the system leaves the existing well known lun alone. This is a lun 0 with no block directory fi fi elif test $RC = 0 -a $IPTYPE -eq 0; then if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then if test ! -d /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/block ; then remappedlun0=1 # Transition from well-known to real lun 0 fi fi fi fi fi # Special case: lun 0 just got added (for reportlunscan), # so make sure we correctly treat it as new if test "$lun" = "0" -a "$1" = "1" -a -z "$remappedlun0"; then SCSISTR="" printf "\r\e[A\e[A\e[A" fi : f $remove s $SCSISTR if test "$remove" -a "$SCSISTR" -o "$remappedlun0" = "1"; then if test $RC != 0 -o ! -z "$forceremove" -o -n "$remappedlun0"; then if test "$remappedlun0" != "1" ; then echo -en "\r\e[A\e[A\e[A${red}REM: " echo "$SCSISTR" | head -n1 echo -e "${norm}\e[B\e[B" fi if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then # have to preemptively do this so we can figure out the mpath device # Don't do this if we're deleting a well known lun to replace it if test "$remappedlun0" != "1" ; then incrrmvd "$host:$channel:$id:$lun" fi echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/delete usleep 20000 else echo "scsi remove-single-device $devnr" > /proc/scsi/scsi if test $RC -eq 1 -o $lun -eq 0 ; then # Try readding, should fail if device is gone echo "scsi add-single-device $devnr" > /proc/scsi/scsi fi fi fi if test $RC = 0 -o "$forcerescan" ; then if test -e /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device; then echo 1 > /sys/class/scsi_device/${host}:${channel}:${id}:${lun}/device/rescan fi fi printf "\r\e[A\e[A\e[A${yellow}OLD: $norm" testexist if test -z "$SCSISTR" -a $RC != 1 -a "$remappedlun0" != "1"; then printf "\r${red}DEL: $norm\r\n\n" # In the event we're replacing with a well known node, we need to let it continue, to create the replacement node test "$remappedlun0" != "2" && return 1 fi fi if test -z "$SCSISTR" -o -n "$remappedlun0"; then if test "$remappedlun0" != "2" ; then # Device does not exist, try to add printf "\r${green}NEW: $norm" fi if test -e /sys/class/scsi_host/host${host}/scan; then echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan 2> /dev/null else echo "scsi add-single-device $devnr" > /proc/scsi/scsi fi testexist if test -z "$SCSISTR"; then # Device not present printf "\r\e[A"; # Optimization: if lun==0, stop here (only if in non-remove mode) if test $lun = 0 -a -z "$remove" -a $optscan = 1; then break; fi else if test "$remappedlun0" != "2" ; then incrfound "$host:$channel:$id:$lun" fi fi fi } # Perform report lun scan on $host $channel $id using REPORT_LUNS doreportlun() { lun=0 SCSISTR= devnr="$host $channel $id $lun" echo -en " Scanning for device $devnr ...\r" lun0added= #printf "${yellow}OLD: $norm" # Phase one: If LUN0 does not exist, try to add testexist -q if test -z "$SCSISTR"; then # Device does not exist, try to add #printf "\r${green}NEW: $norm" if test -e /sys/class/scsi_host/host${host}/scan; then echo "$channel $id $lun" > /sys/class/scsi_host/host${host}/scan 2> /dev/null udevadm_settle else echo "scsi add-single-device $devnr" > /proc/scsi/scsi fi testexist -q if test -n "$SCSISTR"; then lun0added=1 #testonline else # Device not present # return # Find alternative LUN to send getluns to for dev in /sys/class/scsi_device/${host}:${channel}:${id}:*; do [ -d "$dev" ] || continue lun=${dev##*:} break done fi fi targetluns=`getluns` REPLUNSTAT=$? lunremove= #echo "getluns reports " $targetluns olddev=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null` oldluns=`echo "$olddev" | awk -F'/' '{print $5}' | awk -F':' '{print $4}'` oldtargets="$targetluns" # OK -- if we don't have a LUN to send a REPORT_LUNS to, we could # fall back to wildcard scanning. Same thing if the device does not # support REPORT_LUNS # TODO: We might be better off to ALWAYS use wildcard scanning if # it works if test "$REPLUNSTAT" = "1"; then if test -e /sys/class/scsi_host/host${host}/scan; then echo "$channel $id -" > /sys/class/scsi_host/host${host}/scan 2> /dev/null udevadm_settle else echo "scsi add-single-device $host $channel $id $SCAN_WILD_CARD" > /proc/scsi/scsi fi targetluns=`find /sys/class/scsi_device/ -name $host:$channel:$id:* 2>/dev/null | awk -F'/' '{print $5}' | awk -F':' '{print $4}' | sort -n` let found+=`echo "$targetluns" | wc -l` let found-=`echo "$olddev" | wc -l` fi if test -z "$targetluns"; then targetluns="$oldtargets"; fi # Check existing luns for dev in $olddev; do [ -d "$dev" ] || continue lun=${dev##*:} newsearch= inlist= # OK, is existing $lun (still) in reported list for tmplun in $targetluns; do if test $tmplun -eq $lun ; then inlist=1 dolunscan $lun0added else newsearch="$newsearch $tmplun" fi done # OK, we have now done a lunscan on $lun and # $newsearch is the old $targetluns without $lun if [ -z "$inlist" ]; then # Stale lun lunremove="$lunremove $lun" fi # $lun removed from $lunsearch (echo for whitespace cleanup) targetluns=`echo $newsearch` done # Add new ones and check stale ones for lun in $targetluns $lunremove; do dolunscan $lun0added done } # Perform search (scan $host) dosearch () { if test -z "$channelsearch" ; then chanlist fi for channel in $channelsearch; do if test -z "$idsearch" ; then idlist fi for id in $idsearch; do if test -z "$lunsearch" ; then doreportlun else for lun in $lunsearch; do dolunscan done fi done done } expandlist () { list=$1 result="" first=${list%%,*} rest=${list#*,} while test ! -z "$first"; do beg=${first%%-*}; if test "$beg" = "$first"; then result="$result $beg"; else end=${first#*-} result="$result `seq $beg $end`" fi test "$rest" = "$first" && rest="" first=${rest%%,*} rest=${rest#*,} done echo $result } searchexisting() { local tmpch; local tmpid local match=0 local targets=`ls -d /sys/class/scsi_device/$host:* 2> /dev/null | egrep -o $host:[0-9]+:[0-9]+ | sort | uniq` # Nothing came back on this host, so we should skip it test -z "$targets" && return local target=; for target in $targets ; do channel=`echo $target | cut -d":" -f2` id=`echo $target | cut -d":" -f 3` if [ -n "$channelsearch" ] ; then for tmpch in $channelsearch ; do test $tmpch -eq $channel && match=1 done else match=1 fi test $match -eq 0 && continue match=0 if [ $filter_ids -eq 1 ] ; then for tmpid in $idsearch ; do if [ $tmpid -eq $id ] ; then match=1 fi done else match=1 fi test $match -eq 1 && doreportlun done } # Go through all of the existing devices and figure out any that have been remapped findremapped() { local hctl=; local devs=`ls /sys/class/scsi_device/` local sddev= local id_serial= local id_serial_old= local sysfs_devpath= mpaths="" local tmpfile="/tmp/rescan-scsi-bus-`date +s`" test -f $tmpfile && rm $tmpfile # Get all of the ID_SERIAL attributes, after finding their sd node for hctl in $devs ; do if [ -d /sys/class/scsi_device/$hctl/device/block ] ; then sddev=`ls /sys/class/scsi_device/$hctl/device/block` id_serial_old=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial_old" ] && id_serial_old="none" echo "$hctl $sddev $id_serial_old" >> $tmpfile fi done # Trigger udev to update the info echo -n "Triggering udev to update device information... " /sbin/udevadm trigger udevadm_settle 2&>1 /dev/null echo "Done" # See what changed and reload the respective multipath device if applicable while read hctl sddev id_serial_old ; do id_serial=`udevadm info -q all -n $sddev | grep "ID_SERIAL=" | cut -d"=" -f2` [ -z "$id_serial" ] && id_serial="none" if [ "$id_serial_old" != "$id_serial" ] ; then if [ "$id_serial" = "1" ] ; then continue # the lun was unmapped and is getting the blank scsi id (1) fi printf "${yellow}REMAPPED: $norm" host=`echo $hctl | cut -d":" -f1` channel=`echo $hctl | cut -d":" -f2` id=`echo $hctl | cut -d":" -f3` lun=`echo $hctl | cut -d":" -f4` procscsiscsi echo "$SCSISTR" incrchgd "$hctl" fi done < $tmpfile rm $tmpfile 2&>1 /dev/null if test -n "$mp_enable" -a -n "$mpaths" ; then echo "Updating multipath device mappings" flushmpaths $MULTIPATH | grep "create:" 2> /dev/null #2&>1 /dev/null fi } incrfound() { local hctl="$1" if test -n "$hctl" ; then let found+=1 FOUNDDEVS="$FOUNDDEVS\t[$hctl]\n" else return fi } incrchgd() { local hctl="$1" if test -n "$hctl" ; then let updated+=1 CHGDEVS="$CHGDEVS\t[$hctl]\n" else return fi if test -n "$mp_enable" ; then local sdev="`findsddev \"$hctl\"`" if test -n "$sdev" ; then findmultipath "$sdev" fi fi } incrrmvd() { local hctl="$1" if test -n "$hctl" ; then let rmvd+=1; RMVDDEVS="$RMVDDEVS\t[$hctl]\n" else return fi if test -n "$mp_enable" ; then local sdev="`findsddev \"$hctl\"`" if test -n "$sdev" ; then findmultipath "$sdev" fi fi } findsddev() { local hctl="$1" local sddev= if test ! -e /sys/class/scsi_device/$hctl/device/block ; then return 1 fi sddev=`ls /sys/class/scsi_device/$hctl/device/block` echo $sddev return 0 } findmultipath() { local dev="$1" local mp= local mp2= # Need a sdev, and executable multipath and dmsetup command here if [ -z "$dev" ] || [ ! -x $DMSETUP ] ; then return 1 fi local maj_min=`cat /sys/block/$dev/dev` for mp in $($DMSETUP ls --target=multipath | cut -f 1) ; do if $($DMSETUP status $mp | grep -q " $maj_min ") ; then for mp2 in $mpaths ; do # mp device is already there, return if [ "$mp2" = "$mp" ] ; then return fi done mpaths="$mpaths $mp" return fi done } reloadmpaths() { local mpath if [ ! -x $MULTIPATH ] ; then echo "no -x multipath" return fi if [ "$1" = "1" ] ; then echo "Reloading all multipath devices" $MULTIPATH -r 2&>1 /dev/null return fi # Reload the multipath devices for mpath in $mpaths ; do echo "Reloading multipath device $mpath" $MULTIPATH -r $mpath 2&>1 /dev/null done } flushmpaths() { local mpath # Mode: flush only failed if test -n "$1" ; then for mpath in $($DMSETUP ls --target=multipath | cut -f 1) ; do num=$($DMSETUP status $mpath | awk 'BEGIN{RS=" ";active=0}/[0-9]+:[0-9]+/{dev=1}/A/{if (dev == 1) active++; dev=0} END{ print active }') if [ $num -eq 0 ] ; then echo -n "Flushing multipath device $mpath... " $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null $MULTIPATH -f $mpath 2&>1 /dev/null $DMSETUP status $mpath 2&>1 /dev/null if test "$?" = "1" ; then echo "Done" else echo "Fail" fi fi done return fi # Flush all the devs specified in $mpaths for mpath in $mpaths ; do echo -n "Flushing multipath device $mpath... " $DMSETUP message $mpath 0 fail_if_no_path 2&>1 /dev/null $MULTIPATH -f $mpath 2&>1 /dev/null $DMSETUP status $mpath 2&>1 /dev/null if test "$?" = "1" ; then echo "Done" else echo "Fail" fi done } # Find resized luns findresized() { local devs=`ls /sys/class/scsi_device/` local size= local new_size= local sysfs_path= local sddev= for hctl in $devs ; do sysfs_path="/sys/class/scsi_device/$hctl/device" if [ -d "$sysfs_path/block" ] ; then sddev=`ls $sysfs_path/block` size=`cat $sysfs_path/block/$sddev/size` echo 1 > $sysfs_path/rescan new_size=`cat $sysfs_path/block/$sddev/size` if [ "$size" != "$new_size" ] && [ "$size" != "0" ] && [ "$new_size" != "0" ] ; then printf "${yellow}RESIZED: $norm" host=`echo $hctl | cut -d":" -f1` channel=`echo $hctl | cut -d":" -f2` id=`echo $hctl | cut -d":" -f3` lun=`echo $hctl | cut -d":" -f4` procscsiscsi echo "$SCSISTR" incrchgd "$hctl" fi fi done if test -n "$mp_enable" -a -n "$mpaths" ; then reloadmpaths fi } FOUNDDEVS="" CHGDEVS="" RMVDDEVS="" # main if test @$1 = @--help -o @$1 = @-h -o @$1 = @-?; then echo "Usage: rescan-scsi-bus.sh [options] [host [host ...]]" echo "Options:" echo " -a scan all targets, not just currently existing [default: disabled]" echo " -c enables scanning of channels 0 1 [default: 0 / all detected ones]" echo " -d enable debug [default: 0]" echo " -f flush failed multipath devices [default: disabled]" echo " -h help: print this usage message then exit" echo " -i issue a FibreChannel LIP reset [default: disabled]" echo " -l activates scanning for LUNs 0--7 [default: 0]" echo " -L NUM activates scanning for LUNs 0--NUM [default: 0]" echo " -r enables removing of devices [default: disabled]" echo " -s look for resized disks and reload associated multipath devices, if applicable" echo " -u look for existing disks that have been remapped" echo " -w scan for target device IDs 0--15 [default: 0--7]" echo "--alltargets: same as -a" echo "--attachpq3: Tell kernel to attach sg to LUN 0 that reports PQ=3" echo "--channels=LIST: Scan only channel(s) in LIST" echo "--color: use coloured prefixes OLD/NEW/DEL" echo "--flush: same as -f" echo "--forceremove: Remove and readd every device (DANGEROUS)" echo "--forcerescan: Rescan existing devices" echo "--help: print this usage message then exit" echo "--hosts=LIST: Scan only host(s) in LIST" echo "--ids=LIST: Scan only target ID(s) in LIST" echo "--issue-lip: same as -i" echo "--largelun: Tell kernel to support LUNs > 7 even on SCSI2 devs" echo "--luns=LIST: Scan only lun(s) in LIST" echo "--nooptscan: don't stop looking for LUNs is 0 is not found" echo "--remove: same as -r" echo "--reportlun2: Tell kernel to try REPORT_LUN even on SCSI2 devices" echo "--resize: same as -s" echo "--sparselun: Tell kernel to support sparse LUN numbering" echo "--sync/nosync: Issue a sync / no sync [default: sync if remove]" echo "--update: same as -u" echo "--wide: same as -w" echo "" echo "Host numbers may thus be specified either directly on cmd line (deprecated)" echo "or with the --hosts=LIST parameter (recommended)." echo "LIST: A[-B][,C[-D]]... is a comma separated list of single values and ranges" echo "(No spaces allowed.)" exit 0 fi if test ! -d /sys/class/scsi_host/ -a ! -d /proc/scsi/; then echo "Error: SCSI subsystem not active" exit 1 fi # Make sure sg is there modprobe sg >/dev/null 2>&1 if test -x /usr/bin/sg_inq; then sg_version=$(sg_inq -V 2>&1 | cut -d " " -f 3) if test -n "$sg_version"; then sg_ver_maj=${sg_version:0:1} sg_version=${sg_version##?.} let sg_version+=$((100*$sg_ver_maj)) fi sg_version=${sg_version##0.} #echo "\"$sg_version\"" if [ -z "$sg_version" -o "$sg_version" -lt 70 ] ; then sg_len_arg="-36" else sg_len_arg="--len=36" fi else echo "WARN: /usr/bin/sg_inq not present -- please install sg3_utils" echo " or rescan-scsi-bus.sh might not fully work." fi # defaults unsetcolor debug=0 lunsearch= opt_idsearch=`seq 0 7` filter_ids=0 opt_channelsearch= remove= updated=0 update=0 resize=0 forceremove= optscan=1 sync=1 existing_targets=1 mp_enable= declare -i scan_flags=0 # Scan options opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in a) existing_targets=;; #Scan ALL targets when specified d) debug=1 ;; f) flush=1 ;; l) lunsearch=`seq 0 7` ;; L) lunsearch=`seq 0 $2`; shift ;; m) mp_enable=1 ;; w) opt_idsearch=`seq 0 15` ;; c) opt_channelsearch="0 1" ;; r) remove=1 ;; s) resize=1 ;; i) lipreset=1 ;; u) update=1 ;; -alltargets) existing_targets=;; -flush) flush=1 ;; -remove) remove=1 ;; -forcerescan) remove=1; forcerescan=1 ;; -forceremove) remove=1; forceremove=1 ;; -hosts=*) arg=${opt#-hosts=}; hosts=`expandlist $arg` ;; -channels=*) arg=${opt#-channels=};opt_channelsearch=`expandlist $arg` ;; -ids=*) arg=${opt#-ids=}; opt_idsearch=`expandlist $arg` ; filter_ids=1;; -luns=*) arg=${opt#-luns=}; lunsearch=`expandlist $arg` ;; -color) setcolor ;; -nooptscan) optscan=0 ;; -issue-lip) lipreset=1 ;; -sync) sync=2 ;; -nosync) sync=0 ;; -multipath) mp_enable=1 ;; -attachpq3) scan_flags=$(($scan_flags|0x1000000)) ;; -reportlun2) scan_flags=$(($scan_flags|0x20000)) ;; -resize) resize=1;; -largelun) scan_flags=$(($scan_flags|0x200)) ;; -sparselun) scan_flags=$((scan_flags|0x40)) ;; -update) update=1;; -wide) opt_idsearch=`seq 0 15` ;; *) echo "Unknown option -$opt !" ;; esac shift opt="$1" done if [ -z "$hosts" ] ; then if test -d /sys/class/scsi_host; then findhosts_26 else findhosts fi fi if [ -d /sys/class/scsi_host -a ! -w /sys/class/scsi_host ]; then echo "You need to run scsi-rescan-bus.sh as root" exit 2 fi if test "$sync" = 1 -a "$remove" = 1; then sync=2; fi if test "$sync" = 2; then echo "Syncing file systems"; sync; fi if test -w /sys/module/scsi_mod/parameters/default_dev_flags -a $scan_flags != 0; then OLD_SCANFLAGS=`cat /sys/module/scsi_mod/parameters/default_dev_flags` NEW_SCANFLAGS=$(($OLD_SCANFLAGS|$scan_flags)) if test "$OLD_SCANFLAGS" != "$NEW_SCANFLAGS"; then echo -n "Temporarily setting kernel scanning flags from " printf "0x%08x to 0x%08x\n" $OLD_SCANFLAGS $NEW_SCANFLAGS echo $NEW_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags else unset OLD_SCANFLAGS fi fi DMSETUP=$(which dmsetup) [ -z "$DMSETUP" ] && flush= && mp_enable= MULTIPATH=$(which multipath) [ -z "$MULTIPATH" ] && flush= && mp_enable= echo -n "Scanning SCSI subsystem for new devices" test -z "$flush" || echo -n ", flush failed multipath devices," test -z "$remove" || echo -n " and remove devices that have disappeared" echo declare -i found=0 declare -i updated=0 declare -i rmvd=0 if [ -n "$flush" ] ; then if [-x $MULTIPATH ] ; then flushmpaths 1 fi fi # Update existing mappings if [ $update -eq 1 ] ; then echo "Searching for remapped LUNs" findremapped # Search for resized LUNs elif [ $resize -eq 1 ] ; then echo "Searching for resized LUNs" findresized # Normal rescan mode else for host in $hosts; do echo -n "Scanning host $host " if test -e /sys/class/fc_host/host$host ; then # It's pointless to do a target scan on FC issue_lip=/sys/class/fc_host/host$host/issue_lip if test -e $issue_lip -a -n "$lipreset" ; then echo 1 > $issue_lip 2> /dev/null; udevadm_settle fi channelsearch= idsearch= else channelsearch=$opt_channelsearch idsearch=$opt_idsearch fi [ -n "$channelsearch" ] && echo -n "channels $channelsearch " echo -n "for " if [ -n "$idsearch" ] ; then echo -n " SCSI target IDs " $idsearch else echo -n " all SCSI target IDs" fi if [ -n "$lunsearch" ] ; then echo ", LUNs " $lunsearch else echo ", all LUNs" fi if [ -n "$existing_targets" ] ; then searchexisting else dosearch fi done if test -n "$OLD_SCANFLAGS"; then echo $OLD_SCANFLAGS > /sys/module/scsi_mod/parameters/default_dev_flags fi fi let rmvd_found=$rmvd+$found if test -n "$mp_enable" -a $rmvd_found -gt 0 ; then echo "Attempting to update multipath devices..." if test $rmvd -gt 0 ; then /sbin/udevadm trigger udevadm_settle echo "Removing multipath mappings for removed devices if all paths are now failed... " flushmpaths 1 fi if test $found -gt 0 ; then /sbin/udevadm trigger udevadm_settle echo "Trying to discover new multipath mappings for newly discovered devices... " $MULTIPATH | grep "create:" 2> /dev/null fi fi echo "$found new or changed device(s) found. " if test ! -z "$FOUNDDEVS" ; then printf "$FOUNDDEVS" fi echo "$updated remapped or resized device(s) found. " if test ! -z "$CHGDEVS" ; then printf "$CHGDEVS" fi echo "$rmvd device(s) removed. " if test ! -z "$RMVDDEVS" ; then printf "$RMVDDEVS" fi # Local Variables: # sh-basic-offset: 2 # End: sg3_utils-1.40/scripts/Makefile.am0000664000175000017500000000160112144707462016100 0ustar douggdougg if OS_LINUX bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif if OS_WIN32_MINGW bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif if OS_WIN32_CYGWIN bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif if OS_FREEBSD bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif if OS_SOLARIS bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif if OS_OSF bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ scsi_satl scsi_start scsi_stop scsi_temperature endif sg3_utils-1.40/scripts/README0000664000175000017500000000446512307310513014723 0ustar douggdougg README for sg3_utils/scripts ============================ Introduction ============ This directory contains bash shell scripts. Most of them call one or more utilities from the sg3_utils package. They assume the sg3_utils package utilities are on the PATH of the user. rescan-scsi-bus.sh is written by Kurt Garloff (see http://www.garloff.de/kurt/linux/ under the "Rescan SCSI bus" heading) with patches from Hannes Reinecke. scsi_logging_level is written by Andreas Herrmann . It sets the logging level of the SCSI subsystem in the Linux 2.6 series kernels. See that file for more information. The other scripts are written by the author. Some do testing while others do bulk tasks (e.g. stopping multiple disks). Details ======= Each script supplies more information, typically by supplying a '-h' or '--help' option. The script source often contains explanatory information. Following is a usage summary with a one line description: rescan-scsi-bus.sh [OPTIONS] - see the output of 'rescan-scsi-bus.sh --help' scsi_logging_level [OPTIONS] - set Linux SCSI subsystem logging level scsi_mandat [-h] [-L] [-q] - check for mandatory SCSI command support scsi_readcap [-b] [-h] [-v] + - fetch capacity/size information for each scsi_ready [-h] [-v] + - check the media ready status on each scsi_satl [-h] [-L] [-q] [-v] - check for SCSI to ATA Translation Layer (SATL) scsi_start [-h] [-v] [-w] + - start media (i.e. spin up) in each scsi_stop [-h] [-v] [-w] + - stop media (i.e. spin down) in each scsi_temperature [-h] [-v] + - check temperature in each These scripts assume that the main sg3_utils utilities are installed and are on the user's PATH. This directory, prior to sg3_utils-1.28, contained the sas_disk_blink script. Since it depends on the sdparm utility it has been moved to the sdparm package in its scripts directory. 59-scsi-sg3_utils.rules is a Linux specific file for udev. These rules use 'sg_inq --export' to help udev create identifying device nodes, for example /dev/disk/by-id/wwn-0x5001501234567890-part1. Douglas Gilbert 8th March 2014 sg3_utils-1.40/scripts/Makefile.in0000664000175000017500000003621712401205666016117 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = scripts DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am README ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ @OS_FREEBSD_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_FREEBSD_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature @OS_LINUX_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_LINUX_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature @OS_OSF_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_OSF_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature @OS_SOLARIS_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_SOLARIS_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature @OS_WIN32_CYGWIN_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_WIN32_CYGWIN_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature @OS_WIN32_MINGW_TRUE@bin_SCRIPTS = scsi_logging_level scsi_mandat scsi_readcap scsi_ready \ @OS_WIN32_MINGW_TRUE@ scsi_satl scsi_start scsi_stop scsi_temperature all: all-am .SUFFIXES: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu scripts/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu scripts/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic clean-libtool \ cscopelist-am ctags-am distclean distclean-generic \ distclean-libtool distdir dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic \ mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-binSCRIPTS # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/scripts/scsi_mandat0000775000175000017500000000675112231276745016274 0ustar douggdougg#!/bin/bash # scsi_mandat # # Script to test compliance with SCSI mandatory commands. # The vintage is SPC-3 and SPC-4 (see www.t10.org). # # Coverage: # Command Standard/Draft (is mandatory in) # ------------------------------------------------------- # INQUIRY (standard) SCSI-2, SPC, SPC-2, SPC-3, SPC-4 # INQUIRY (VPD pages 0, 0x83) SPC-2, SPC-3, SPC-4 # REPORT LUNS SPC-3, SPC-4 # TEST UNIT READY SCSI-2, SPC, SPC-2, SPC-3, SPC-4 # REQUEST SENSE SCSI-2, SBC, SBC-2,3, MMC-4,5, SSC-2,3 # SEND DIAGNOSTIC SBC, SBC-2,3, SSC-2,3 # # This script uses utilities frim sg3_utils package (version # 1.21 or later) # # Douglas Gilbert 20131016 log=0 quiet=0 verbose="" file_err=0 inv_opcode=0 illeg_req=0 not_ready=0 medium=0 other_err=0 recovered=0 sanity=0 syntax=0 timeout=0 unit_attention=0 aborted_command=0 total_err=0 usage() { echo "Usage: scsi_mandat [-h] [-L] [-q] [-v] " echo " where: -h print usage message" echo " -L, --log append stderr to 'scsi_mandat.err'" echo " -q suppress some output" echo " -v increase verbosity of output" echo "" echo "Check for mandatory SCSI command support" } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in h|-help) usage ; exit 0 ;; L|-log) let log=$log+1 ;; q|-quiet) let quiet=$quiet+1 ;; v|-verbose) verbose="-v" ;; vv) verbose="-vv" ;; vvv) verbose="-vvv" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for command in "sg_inq" "sg_luns" "sg_turs" "sg_requests" "sg_vpd" \ "sg_vpd -i" "sg_senddiag -t" do if [ $quiet -eq 0 ] then echo "$command" $verbose $1 fi if [ $verbose ] then if [ $log -eq 0 ] then $command $verbose $1 else $command $verbose $1 >> scsi_mandat.err 2>> scsi_mandat.err fi else if [ $log -eq 0 ] then $command $1 > /dev/null 2>> /dev/null else $command $1 > /dev/null 2>> scsi_mandat.err fi fi res=$? case "$res" in 0) ;; 1) echo " syntax error" ; let syntax=$syntax+1 ;; 2) echo " not ready" ; let not_ready=$not_ready+1 ;; 3) echo " medium error" ; let medium=$medium+1 ;; 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;; 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;; 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;; 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;; 15) echo " file error with $1 " ; let file_err=$file_err+1 ;; 20) echo " no sense" ; let other_err=$other_err+1 ;; 21) echo " recovered error" ; let recovered_err=$recovered_err+1 ;; 33) echo " timeout" ; let timeout=$timeout+1 ;; 97) echo " response fails sanity" ; let sanity=$sanity+1 ;; 98) echo " other SCSI error" ; let other_err=$other_err+1 ;; 99) echo " other error" ; let other_err=$other_err+1 ;; *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;; esac done echo "" let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout let total_allow_err=$not_ready+$unit_attention echo "total number of bad errors: $total_bad_err " if [ $total_allow_err -gt 0 ] then echo "total number of allowable errors: $total_allow_err " fi exit $total_bad_err sg3_utils-1.40/scripts/scsi_temperature0000775000175000017500000000165012144707462017354 0ustar douggdougg#!/bin/bash ################################################################### # # Check the temperature of the given SCSI device(s). # # This script assumes the sg3_utils package is installed. # ################################################################## verbose="" usage() { echo "Usage: scsi_temperature [-h] [-v] +" echo " where:" echo " -h, --help print usage message" echo " -v, --verbose more verbose output" echo "" echo "Use SCSI LOG SENSE command to fetch temperature of each " } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in h|-help) usage ; exit 0 ;; v|-verbose) verbose="-v" ;; vv) verbose="-vv" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for i do echo "sg_logs -t $verbose $i" sg_logs -t $verbose $i done sg3_utils-1.40/scripts/58-scsi-sg3_symlink.rules0000664000175000017500000000375512430315266020562 0ustar douggdougg# SCSI-ID symlinks for sg3_utils ACTION=="remove", GOTO="sg3_utils_symlink_end" SUBSYSTEM!="block", GOTO="sg3_utils_symlink_end" # Skip symlink generation for multipath ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="sg3_utils_symlink_end" # Select which identifier to use per default # 0: vpd page 0x80 identifier ENV{SCSI_IDENT_SERIAL}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}" ENV{SCSI_IDENT_SERIAL}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-S$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_SERIAL}-part%n" # 1: NAA identifier (prefix 3) ENV{SCSI_IDENT_LUN_NAA}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA}" ENV{SCSI_IDENT_LUN_NAA}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-3$env{SCSI_IDENT_LUN_NAA}-part%n" # 2: EUI-64 identifer (prefix 2) ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-2$env{SCSI_IDENT_LUN_EUI64}" ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-2$env{SCSI_IDENT_LUN_EUI64}-part%n" # 3: SCSI name identifier (prefix 8) ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-8$env{SCSI_IDENT_LUN_NAME}" ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-8$env{SCSI_IDENT_LUN_NAME}-part%n" # 4: T10 Vendor identifer (prefix 1) ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}" ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-1$env{SCSI_IDENT_LUN_T10}-part%n" # 5: Vendor-specific identifier (prefix 0) ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{DEVTYPE}=="disk", SYMLINK+="disk/by-id/scsi-0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}" ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{DEVTYPE}=="partition", SYMLINK+="disk/by-id/scsi-0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}-part%n" LABEL="sg3_utils_symlink_end" sg3_utils-1.40/scripts/scsi_ready0000775000175000017500000000214112144707462016117 0ustar douggdougg#!/bin/bash ################################################ # # Send a TEST UNIT READY SCSI command to each given device. # # This script assumes the sg3_utils package is installed and uses # the sg_turs utility.. # ############################################### verbose="" brief="" usage() { echo "Usage: scsi_ready [-b] [-h] [-v] +" echo " where:" echo " -b, --brief print 'ready' or 'device not ready' only" echo " -h, --help print usage message" echo " -v, --verbose more verbose output" echo "" echo "Send SCSI TEST UNIT READY to each " } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in b|-brief) brief="1" ;; h|-help) usage ; exit 0 ;; v|-verbose) verbose="-v" ;; vv) verbose="-vv" ;; vvv) verbose="-vvv" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for i do if [ ! $brief ] ; then echo "sg_turs $verbose $i" fi echo -n " " if sg_turs $verbose $i ; then echo "ready" fi done sg3_utils-1.40/scripts/scsi_stop0000775000175000017500000000270212144707462016003 0ustar douggdougg#!/bin/bash ################################################ # # Spin down the given SCS disk(s). # # SCSI disks (or disks that understand SCSI commands) # are assumed. By default, the immediate bit is set so the # command should return immediately. The disk however will # take 10 seconds or more to spin down. The '-w' option # causes each stop to wait until the disk reports that it # has stopped. # # This script assumes the sg3_utils package is installed. # ############################################### verbose="" immediate="-i" usage() { echo "Usage: scsi_stop [-h] [-v] [-w] +" echo " where:" echo " -h, --help print usage message" echo " -v, --verbose more verbose output" echo " -w, --wait wait for each stop to complete" echo "" echo "Send SCSI START STOP UNIT command to stop each " } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in h|-help) usage ; exit 0 ;; v|-verbose) verbose="-v" ;; w|-wait) immediate="" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for i do # Use '-r' (read-only) otherwise using a block device node # (e.g. 'sg_start 0 /dev/sdb') can result in a change of state # event causing the disk to spin up again immediately. echo "sg_start -r $immediate 0 $verbose $i" sg_start -r $immediate 0 $verbose $i done sg3_utils-1.40/scripts/scsi_readcap0000775000175000017500000000245712144707462016424 0ustar douggdougg#!/bin/bash ################################################################### # # Fetch READ CAPACITY information for the given SCSI device(s). # # This script assumes the sg3_utils package is installed. # ################################################################## verbose="" brief="" long_opt="" usage() { echo "Usage: scsi_readcap [-b] [-h] [-l] [-v] +" echo " where:" echo " -b, --brief output brief capacity data" echo " -h, --help print usage message" echo " -l, --long send longer SCSI READ CAPACITY (16) cdb" echo " -v, --verbose more verbose output" echo "" echo "Use SCSI READ CAPACITY command to fetch the size of each " } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in b|-brief) brief="-b" ;; h|-help) usage ; exit 0 ;; l|-long) long_opt="--16" ;; v|-verbose) verbose="-v" ;; vv) verbose="-vv" ;; vvv) verbose="-vvv" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for i do if [ $brief ] ; then sg_readcap $brief $long_opt $verbose $i 2> /dev/null else echo "sg_readcap $brief $long_opt $verbose $i" sg_readcap $brief $long_opt $verbose $i fi done sg3_utils-1.40/scripts/scsi_start0000775000175000017500000000240512144707462016153 0ustar douggdougg#!/bin/bash ################################################ # # Spin up the given SCSI disk(s). # # SCSI disks (or disks that understand SCSI commands) # are assumed. By default, the immediate bit is set so the # command should return immediately. The disk however will # take 10 seconds or more to spin up. The '-w' option # causes each start to wait until the disk reports that it # has started. # # This script assumes the sg3_utils package is installed. # ############################################### verbose="" immediate="-i" usage() { echo "Usage: scsi_start [-h] [-v] [-w] +" echo " where:" echo " -h, --help print usage message" echo " -v, --verbose more verbose output" echo " -w, --wait wait for each start to complete" echo "" echo "Send SCSI START STOP UNIT command to start each " } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in h|-help) usage ; exit 0 ;; v|-verbose) verbose="-v" ;; w|-wait) immediate="" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for i do echo "sg_start $immediate 1 $verbose $i" sg_start $immediate 1 $verbose $i done sg3_utils-1.40/scripts/scsi_satl0000775000175000017500000000741612144707462015770 0ustar douggdougg#!/bin/bash # scsi_satl # # Script to test compliance of SCSI commands on a SCSI to ATA # Translation (SAT) Layer (SATL). This script was compiled using # sat-r09.pdf found at www.t10.org . # The scripts still seems to be valid for sat2r09.pdf . # The vintage is SPC-3 and SPC-4 (see www.t10.org). # # Coverage: # Command SATL notes # ------------------------------------------------------- # INQUIRY (standard) # INQUIRY (VPD: 0) # INQUIRY (VPD: 0x83) Device identification VPD page # INQUIRY (VPD: 0x89) ATA Information VPD page # REPORT LUNS SPC-3, SPC-4 (hardly mentioned in sat-r08c) # TEST UNIT READY # REQUEST SENSE # SEND DIAGNOSTIC default self test # MODE SENSE(10) draft unclear which mode pages, so ask for all # ATA PASS THROUGH(16) send IDENTIFY DEVICE command. Assume non-packet # device, if packet device add "-p" option # # This script uses utilities from sg3_utils package (version # 1.22 or later) # # Douglas Gilbert 20090930 log=0 quiet=0 verbose="" file_err=0 inv_opcode=0 illeg_req=0 not_ready=0 medium=0 other_err=0 recovered=0 sanity=0 syntax=0 timeout=0 unit_attention=0 aborted_command=0 total_err=0 usage() { echo "Usage: scsi_satl [-h] [-L] [-q] [-v] " echo " where: -h, --help print usage message" echo " -L, --log append stderr to 'scsi_satl.err'" echo " -q, --quiet suppress some output" echo " -v, --verbose more verbose output" echo "" echo "Check for SCSI to ATA Translation Layer (SATL) support" } opt="$1" while test ! -z "$opt" -a -z "${opt##-*}"; do opt=${opt#-} case "$opt" in h|-help) usage ; exit 1 ;; L|-log) let log=$log+1 ;; q|-quiet) let quiet=$quiet+1 ;; v|-verbose) verbose="-v" ;; *) echo "Unknown option: -$opt " ; exit 1 ;; esac shift opt="$1" done if [ $# -lt 1 ] then usage exit 1 fi for command in "sg_inq" "sg_vpd" "sg_vpd -p di" "sg_vpd -p ai" "sg_luns" \ "sg_turs" "sg_requests -s" "sg_senddiag -t" "sg_modes -a" \ "sg_sat_identify" do if [ $quiet -eq 0 ] then echo "$command" $1 fi if [ $log -eq 0 ] then if [ $verbose ] then $command $verbose $1 > /dev/null else $command $1 > /dev/null 2>> /dev/null fi else $command $verbose $1 > /dev/null 2>> scsi_satl.err fi res=$? case "$res" in 0) ;; 1) echo " syntax error" ; let syntax=$syntax+1 ;; 2) echo " not ready" ; let not_ready=$not_ready+1 ;; 3) echo " medium error" ; let medium=$medium+1 ;; 5) echo " illegal request, general" ; let illeg_req=$illeg_req+1 ;; 6) echo " unit attention" ; let unit_attention=$unit_attention+1 ;; 9) echo " illegal request, invalid opcode" ; let inv_opcode=$inv_opcode+1 ;; 11) echo " aborted command" ; let aborted_command=$aborted_command+1 ;; 15) echo " file error with $1 " ; let file_err=$file_err+1 ;; 20) echo " no sense" ; let other_err=$other_err+1 ;; 21) echo " recovered error" ; let recovered_err=$recovered_err+1 ;; 33) echo " timeout" ; let timeout=$timeout+1 ;; 97) echo " response fails sanity" ; let sanity=$sanity+1 ;; 98) echo " other SCSI error" ; let other_err=$other_err+1 ;; 99) echo " other error" ; let other_err=$other_err+1 ;; *) echo " unknown exit status for sg_inq: $res" ; let other_err=$other_err+1 ;; esac done echo "" let total_bad_err=$file_err+$inv_opcode+$illeg_req+$medium+$aborted_command let total_bad_err+=$other_err+$recovered+$sanity+$syntax+$timeout let total_allow_err=$not_ready+$unit_attention echo "total number of bad errors: $total_bad_err " if [ $total_allow_err -gt 0 ] then echo "total number of allowable errors: $total_allow_err " fi exit $total_bad_err sg3_utils-1.40/scripts/55-scsi-sg3_id.rules0000664000175000017500000000464412341217414017460 0ustar douggdougg# SCSI-ID mappings for sg3_utils ACTION=="remove", GOTO="sg3_utils_id_end" SUBSYSTEM!="block", GOTO="sg3_utils_id_end" # Import values for partitions ENV{DEVTYPE}=="partition", IMPORT{parent}="SCSI_*", ENV{ID_SCSI}="1" # SCSI INQUIRY values KERNEL=="sd*[!0-9]|sr*", IMPORT{program}="/usr/bin/sg_inq --export $tempnode", ENV{ID_SCSI}="1" # scsi_id compat mappings ENV{SCSI_VENDOR}=="?*", ENV{ID_VENDOR}="$env{SCSI_VENDOR}" ENV{SCSI_VENDOR_ENC}=="?*", ENV{ID_VENDOR_ENC}="$env{SCSI_VENDOR_ENC}" ENV{SCSI_MODEL}=="?*", ENV{ID_MODEL}="$env{SCSI_MODEL}" ENV{SCSI_MODEL_ENC}=="?*", ENV{ID_MODEL_ENC}="$env{SCSI_MODEL_ENC}" ENV{SCSI_REVISION}=="?*", ENV{ID_REVISION}="$env{SCSI_REVISION}" ENV{SCSI_TYPE}=="?*", ENV{ID_TYPE}="$env{SCSI_TYPE}" # SCSI EVPD page 0x80 values KERNEL=="sd*[!0-9]|sr*", ENV{ID_SCSI}=="1", IMPORT{program}="/usr/bin/sg_inq --export --page=sn $tempnode" # SCSI EVPD page 0x83 values KERNEL=="sd*[!0-9]|sr*", ENV{ID_SCSI}=="1", IMPORT{program}="/usr/bin/sg_inq --export --page=di $tempnode" # ID_WWN compat mapping ENV{SCSI_IDENT_LUN_NAA}=="?*", ENV{ID_WWN}!="?*", ENV{ID_WWN}="0x$env{SCSI_IDENT_LUN_NAA}" ENV{SCSI_IDENT_LUN_NAA}=="?*", ENV{ID_WWN_WITH_EXTENSION}!="?*", ENV{ID_WWN_WITH_EXTENSION}="0x$env{SCSI_IDENT_LUN_NAA}" # ata_id compability ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_ATA}=="?*", ENV{ID_BUS}="ata", ENV{ID_ATA}="1", ENV{ID_SERIAL}="$env{SCSI_IDENT_LUN_ATA}" ENV{ID_SERIAL_SHORT}!="?*", ENV{SCSI_VENDOR}=="ATA", ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_VENDOR}" # Compat ID_SERIAL setting ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAA}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="3$env{SCSI_IDENT_LUN_NAA}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAA}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_EUI64}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="2$env{SCSI_IDENT_LUN_EUI64}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_EUI64}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_NAME}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="8$env{SCSI_IDENT_LUN_NAME}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_NAME}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_T10}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="1$env{SCSI_IDENT_LUN_T10}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_T10}" ENV{ID_SERIAL}!="?*", ENV{SCSI_IDENT_LUN_VENDOR}=="?*", ENV{ID_BUS}="scsi", ENV{ID_SERIAL}="0$env{SCSI_VENDOR}_$env{SCSI_MODEL}_$env{SCSI_IDENT_LUN_VENDOR}", ENV{ID_SERIAL_SHORT}="$env{SCSI_IDENT_LUN_VENDOR}" LABEL="sg3_utils_id_end" sg3_utils-1.40/scripts/scsi_logging_level0000775000175000017500000001735512407706337017647 0ustar douggdougg#! /bin/bash ############################################################################### # Conveniently create and set scsi logging level, show SCSI_LOG fields in human # readable form. # # (C) Copyright IBM Corp. 2006 # # Modified by D. Gilbert to replace the use of sysctl [20080218] ############################################################################### REVISION="1.0" SCRIPTNAME="scsi_logging_level" declare -i LOG_ERROR=0 declare -i LOG_TIMEOUT=0 declare -i LOG_SCAN=0 declare -i LOG_MLQUEUE=0 declare -i LOG_MLCOMPLETE=0 declare -i LOG_LLQUEUE=0 declare -i LOG_LLCOMPLETE=0 declare -i LOG_HLQUEUE=0 declare -i LOG_HLCOMPLETE=0 declare -i LOG_IOCTL=0 declare -i LEVEL=0 SET=0 GET=0 CREATE=0 OPTS=`getopt -o hvcgsa:E:T:S:I:M:L:H: --long \ help,version,create,get,set,all:,error:,timeout:,scan:,ioctl:,\ midlevel:,mlqueue:,mlcomplete:,lowlevel:,llqueue:,llcomplete:,\ highlevel:,hlqueue:,hlcomplete: -n \'$SCRIPTNAME\' -- "$@"` eval set -- "$OPTS" # print version info printversion() { cat <>3)) LOG_TIMEOUT=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_SCAN=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_MLQUEUE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_MLCOMPLETE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_LLQUEUE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_LLCOMPLETE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)) LOG_HLQUEUE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)); LOG_HLCOMPLETE=$(($LEVEL & 7)); LEVEL=$(($LEVEL>>3)); LOG_IOCTL=$(($LEVEL & 7)) echo "SCSI_LOG_ERROR=$LOG_ERROR" echo "SCSI_LOG_TIMEOUT=$LOG_TIMEOUT" echo "SCSI_LOG_SCAN=$LOG_SCAN" echo "SCSI_LOG_MLQUEUE=$LOG_MLQUEUE" echo "SCSI_LOG_MLCOMPLETE=$LOG_MLCOMPLETE" echo "SCSI_LOG_LLQUEUE=$LOG_LLQUEUE" echo "SCSI_LOG_LLCOMPLETE=$LOG_LLCOMPLETE" echo "SCSI_LOG_HLQUEUE=$LOG_HLQUEUE" echo "SCSI_LOG_HLCOMPLETE=$LOG_HLCOMPLETE" echo "SCSI_LOG_IOCTL=$LOG_IOCTL" } set_logging_level() { echo "New scsi logging level:" # sysctl -q -w dev.scsi.logging_level=$LEVEL echo $LEVEL > /proc/sys/dev/scsi/logging_level if [ $? != 0 ] then echo "$SCRIPTNAME: could not write scsi logging level $LEVEL" \ "(kernel probably without SCSI_LOGGING support)" exit 1 fi } create_logging_level() { LEVEL=$(($LOG_IOCTL & 7)); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_HLCOMPLETE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_HLQUEUE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_LLCOMPLETE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_LLQUEUE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_MLCOMPLETE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_MLQUEUE & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_SCAN & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_TIMEOUT & 7))); LEVEL=$(($LEVEL<<3)) LEVEL=$(($LEVEL|($LOG_ERROR & 7))) } check_cmdline $* if [ $SET = "1" ] then create_logging_level set_logging_level show_logging_level elif [ $GET = "1" ] then get_logging_level show_logging_level elif [ $CREATE = "1" ] then create_logging_level show_logging_level else invalid_cmdline missing option \'-g\', \'-s\' or \'-c\' fi sg3_utils-1.40/README.solaris0000664000175000017500000001272212076116252014711 0ustar douggdouggPlease Note: >>> Up to and including sg3_utils-1.33 the Solaris code was built >>> and tested on an OpenSolaris VM run with VirtualBox on Ubuntu >>> 11.10 . Now with Ubuntu 12.04 those VMs crash immediately when >>> started with VirtualBox. Further, Oracle (who owns SUN and thus >>> Solaris) no longer supports OpenSolaris and its package >>> repository has been withdrawn. The author can find no generic VMs >>> for Oracle Solaris 11 that run on VirtualBox or VMWare. The author >>> is also displeased with the withdrawal of the Open Software >>> OS and is disinclined to build a Solaris 11 system just to >>> virtualize it. >>> So as of sg3_utils-1.34 the Solaris port is provided "as-is" without >>> testing on a Solaris platform. Douglas Gilbert 13th October 2012 Introduction ============ The Solaris port of sg3_utils contains those utilities that are _not_ specific to Linux. The dd variants from the sg3_utils package (e.g. sg_dd) rely on too many Linux idiosyncrasies to be easily ported. A new package called 'ddpt' contains a utility with similar functionality to sg_dd and is available for Solaris. Supported Utilities =================== Here is a list of utilities that have been ported: sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident sg_inq [dropped ATA IDENTIFY DEVICE capability] sg_logs sg_luns sg_modes sg_persist sg_opcodes sg_prevent sg_raw sg_rdac sg_read_block_limts sg_read_buffer sg_read_long sg_readcap sg_reassign sg_referrals sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same Most utility names are indicative of the main SCSI command that they execute. Some utilities are slightly higher level, for example sg_ses fetches SCSI Enclosure Services (SES) status pages and can send control pages. Each utility has a man page (placed in section 8). An overview of sg3_utils can be found at: http://sg.danny.cz/sg/sg3_utils.html . A copy of the "sg3_utils.html" file is in the "doc" subdirectory. The executables and library can be built from the source code in the tarball and installed with the familiar "./configure ; make ; make install" sequence. If this fails try running the "./autogen.sh" script prior to that sequence. There are generic instruction on configure and friend in the INSTALL file. Some man pages have examples which use Linux device names which hopefully will not confuse the Solaris users. Device naming ============= In Solaris, SCSI device names below the '/dev' directory have a form like: c5t4d3s2 where the number following "c" is the controller (HBA) number, the number following "t" is the target number (from the SCSI parallel interface days) and the number following "d" is the LUN. Following the "s" is the slice number which is related to a partition and by convention "s2" is the whole disk. OpenSolaris also has a c5t4d3p2 form where the number following the "p" is the partition number apart from "p0" which is the whole disk. So a whole disk may be referred to as either: - c5t4d3 - c5t4d3s2 - c5t4d3p0 And these device names are duplicated in the /dev/dsk and /dev/rdsk directories. The former is the block device name and the latter is for "raw" (or char device) access which is what sg3_utils needs. So in OpenSolaris something of the form: sg_inq /dev/rdsk/c5t4d3p0 should work. If it doesn't add a '-vvv' option. If that is attempted on the /dev/dsk/c5t4d3p0 variant an inappropriate ioctl for device error will result. The device names within the /dev directory are typically symbolic links to much longer topological names in the /device directory. In Solaris cd/dvd/bd players seem to be treated as disks and so are found in the /dev/rdsk directory. Tape drives appear in the /dev/rmt directory. There is also a sgen (SCSI generic) driver which by default does not attach to any device. See the /kernel/drv/sgen.conf file to control what is attached. Any attached device will have a device name of the form /dev/scsi/c5t4d3 . Listing available SCSI devices in Solaris seems to be a challenge. "Use the 'format' command" advice works but seems a very dangerous way to list devices. [It does prompt again before doing any damage.] 'devfsadm -Cv' cleans out the clutter in the /dev/rdsk directory, only leaving what is "live". The "cfgadm -v" command looks promising. Details ======= The ported utilities listed above, all use SCSI command functions declared in sg_cmds_basic.h and sg_cmds_extra.h . Those SCSI command functions are implemented in the corresponding ".c" files. The ".c" files pass SCSI commands to the host operating system via an interface declared in sg_pt.h . There are currently five implementations of that interface depending on the host operating system: - sg_pt_linux.c - sg_pt_freebsd.c - sg_pt_osf1.c [Tru64] - sg_pt_solaris.c - sg_pt_win32.c The sg_pt_solaris.c file uses the "uscsi" SCSI pass through mechanism. There seems to be no corresponding ATA pass through and recent SATA disks do not seem to have a SAT layer in front of them (within Solaris). If SAT is present (perhaps externally or within a HBA) then that would allow SATA disks to accept SCSI commands including the SCSI ATA PASS THROUGH commands. Douglas Gilbert 14th January 2013 sg3_utils-1.40/CREDITS0000664000175000017500000001217212430315266013375 0ustar douggdouggThe author of sg3_utils would like to thank the following people who have made contributions: Andries Brouwer rewrite of isosize (original written by Joerg Schilling). isosize is now found in the util-linux package and in the archive directory of this package. Brian Bunker contributed sg_read_block_limits and the target reset addition to sg_reset [20090615] Christophe Varoqui original sg_rtpg [20041229] Clayton Weaver contributed safe_strerror(). Dan Horak website support for this package and others. Lot of fixes, recently man pages [20140128] Dave Johnson improved disk defect list handling [20051218] Dave Williams help with sgp_dd especially and "> 0x7fffffff" with sg*_dd [20060303] Eric Schwartz who wrote these man pages: sg_readcap, sg_reset, sg_scan, sg_start, sg_test_rwbuf, sg_turs and sginfo Eric Seppanen borrowed ideas from alternate implementation of sg_compare_and_write [20130823] Eric Youngdale author of scsi_info on which sginfo is based. Frank Jansen : additions to sg_scan; contributed code for '--alloc-length=' option in sg_persist [20090402] Grant Grundler co-author of blk512-linux that has become sg_format [20050201] Greg Inozemtsev extensions to sg_xcopy [20130207+20130816] Hannes Reinecke contributed sg_rdac, (and some corresponding VPD entries to sg_vpd_vendor), sg_stpg and sg_safte [20071013+20130110] sg_referrals [20100906] sg_inq --export option [20120220+20130109] sg_xcopy+sg_copy_results [20120322] rescan-scsi-bus.sh patches to Kurt Garloff's v1.57 [20130715] 55-scsi-sg3_id.rules + 58-scsi-sg3_symlink.rules [20140527] sg_sat_read_gplog [20141107] Hayashi Naoyuki port to Tru64 [20060127] Heiko Eissfeldt sg based example programs for the original sg driver Ilan Steinberg sg_xcopy: contributed --on_src and --on_dst options [20130505] Ingo van Lil contributed sg_raw [20070331] James Bottomley co-author of blk512-linux that has become sg_format [20050201] Joe Krahn help with int64_t cleanup [20071219] Kai Makisara help with tape minor numbers in lk 2.6 plus earlier advice [20081008] Kurt Garloff original sg_start and sg_test_rwbuf. Additions to sginfo and sg_map. Author of rescan-scsi-bus.sh with latest update to v1.57 [20130331] Lars Marowsky-Brée contributed Unit Path Report VPD page decoding in sg_inq (vendor specific: EMC) and sg_emc_trespass utility Luben Tuikov help with documentation and other suggestions [20061014] contribution sg_read_buffer and sg_write_buffer [20061103] Marius Konitzer suggested and tested oflag=sparse for sg_dd Martin Schwenke added the raw switch "-r" to sg_inq Nate Dailey < Nate dot Dailey at stratus dot com > extended sg_map for sparse disk node names (e.g. /dev/sdaaa) [20050511] Pat LaVarre pointed out danger of negative bpt values in sg_dd (and friends); also problems when reading /dev/null Peter Allworth original dd clone design used by sg3_utils's dd variants (e.g. sg_dd). Roland Dreier extension and correction to sg_xcopy [20120205] Ronnie Sahlberg has written libiscsi and a set of external patches to add direct iSCSI support to this package. See README.iscsi [20110518] Saeed Bishara contributed sg_write_long Sean Stewart various improvements to rescan-scsi-bush.sh script [20130827] Shahar Salzman contributed sg_compare_and_write [20121205] Thomas Kolbe Solaris port help and testing [20070503] Tim Hunt increased number of (sd and sg) devices that sginfo could detect. Tom Steudten sginfo addition: add '-Fhead' option to sort defect list by head. Trent Piepho print out some "sense key specific" data and "-6" switch for sg_modes Douglas Gilbert 10th November 2014 sg3_utils-1.40/ChangeLog0000664000175000017500000017437712430315266014147 0ustar douggdouggEach utility has its own version number, date of last change and some description at the top of its ".c" file. All utilities in the main directory have their own "man" pages. There is also a sg3_utils man page. Changelog for sg3_utils-1.40 [20141110] [svn: r620] - sg_write_verify: new utility for WRITE AND VERIFY - sg_ses_microcode: new utility - sg_sat_read_gplog: new utility - sg_senddiag: add --maxlen= option - sg_copy_results: correct response length calculations - sg_format: make '-FFF' bypass mode sense/select - add --mode=MP to supply alternate mode page, default remains read-write error recovery mpage - output unit serial number and LU name prior to - sg_inq: expand Block limits VPD page output - fix --cmddt output if not supported by device - more sanity checks on vendor supplied fields - sg_vpd: add --all option - more TPC VPD page decoding - add zoned block device characteristics page - more sanity checks on vendor supplied fields - sg_ses: fix problem with --index=sse (and ssc) - mask status element before using as control - defeat previous item with --mask (ignore) option - SAS connector status element: add overcurrent bit - handle element descriptor names that count a trailing NULL - add --warn option mainly for broken joins - add optional descriptions to -ee output - sync with ses3r07 - sg_sanitize: add --desc and --zero options - output unit serial number and LU name prior to - sg_rep_zones: corrections, sync with zbc-r01c - sg_persist: split help into two pages, '-hh' for 2nd - sg_logs: refine tape drive output - sg_raw: with -vvv decode T10 CDB name - do not output/print data-in if error - sg_opcodes: add --compact field - sg_senddiag: add --page=PG option - sg_reset: add words for EAGAIN from reset ioctl - sg_sat_*: mention t_type and multiple_count fields - win32: sg_scan: handle larger configurations - sg_lib: trim trailing spaces in dStrHex() and friends - sg_lib_data: sync asc/ascq codes with T10 20140924 - clean up service action string functions - sg_ll_unmap_v2(): fix group number - sg_ll_inquiry(), sg_ll_mode_sense*(), sg_ll_log_sense(): use resid to clear unfilled data-in buffer - sg_unaligned.h: add header for building parameters - examples/sg_tst_async: new Linux sg test utility Changelog for sg3_utils-1.39 [20140612] [svn: r588] - sg_rep_zones: new utility for ZBC REPORT ZONES - sg_reset_wp: new utility, ZBC RESET WRITE POINTER - sg_ses: add --eiioe=auto|force option - fix AES dpage element indexing problems - add --readonly option - sg_write_buffer: add --bpw=CS option to call write buffer multiple times for big blobs - sg_format: add --ip_def option to fully provision - sg_opcodes: add --mask option - sg_logs: add --in=FN option for log select params - add --filter=PARC (parameter code) - add --no_inq for suppress initial INQUIRY call - add --readonly option - sg_persist: add --readonly option, environment variable SG_PERSIST_IN_RDONLY sets ro on prin cmds - sg_inq: sync version descriptors dated 20105176 - suppress dev-id VPD messages so they only appear when --verbose is given - add new SCSI_IDENT_*_ATA pair to --export output - sg_luns: add decoding for conglomerate LUNS - add --lu_cong option to simulate the LU_CONG bit - sg_vpd: add --vendor=VP option, re-order vendor specific pages, split lto into lto5 and lto6 - add Supported block lengths and protection types page (sbc4r01) - add Block device characteristics extension page (sbc4r02) - sg_copy_results, sg_get_lba_status, sg_luns, sg_read_buffer, sg_readcap, sg_referrals, sg_rtpg, sg_sat_set_features, sg_sat_identify: add --readonly option - sginfo: strip trailing spaces from INQUIRY text - sg_rbuf: add --echo option (to use echo buffer) - sg_lib: add sanitize command service action names - add 'sense' categories for reservation conflict, data protect and protection information violations - add sg_get_category_sense_str() to API - change struct sg_simple_inquiry_resp::rmb to byte_1 - add initial zbc service actions - dStrHex(Err): fix output truncation error - linux, sg: support SCSI_PT_FLAGS_QUEUE_AT_TAIL and SCSI_PT_FLAGS_QUEUE_AT_HEAD (block layer queueing) - sg_lib_data: sync asc/ascq codes with T10 20140516 - sync operation code with T10 20140515 - add id string for SPC-5 - scripts/59-scsi-sg3_utils.rules: removed - functionality split into two scripts: 55-scsi-sg3_id.rules + 58-scsi-sg3_symlink.rules - examples/sg_persist_tst.sh: add --exclusive option - win32: sg_scan, sg_ses and sg_log fixes - examples/sgq_dd: re-add old utility as example Changelog for sg3_utils-1.38 [20140401] [svn: r563] - sg_ses: add --dev-slot-num= and --sas-addr= - fix --data=- problem with large buffers - new --data=@FN to read hex data from file FN - error and warning message cleanup - add --maxlen= option - sg_inq: add --block=0|1 option to control opens - add --inhex=FN to read response in ASCII hex from a file; --inhex=FN --raw reads response in binary - make -HHH (-HHHH for '-p ai') output suitable for another sg_inq invocation to use --inhex to decode - add LU_CONG to standard inquiry response output - decode ASCII information VPD pages - add HAW_ZBC in block dev char. VPD page (sbc4r01) - sync version descriptors dated 20131126 - allow --page=-1 to force std INQUIRY decoding - fix overflow in encode_whitespaces - improve unit serial number display (VPD page 0x80) - sg_vpd: add LU_CONG to standard inquiry response output - add --inhex=FN to read response in ASCII hex from a file; --inhex=FN --raw reads response in binary - decode Third Party Copy (tpc) page - add HAW_ZBC in block dev char. VPD page (sbc4r01) - add LTO and DDS vendor pages - allow --page=num to restrict --enumerate output - sg_persist: add PROUT: Replace Lost Reservation (spc4r36) - add --transport-id= for SOP: 'sop,' - sg_readcap: for --16 show physical block size if different from logical block size - sg_xcopy: environment variables: XCOPY_TO_SRC and XCOPY_TO_DST indicate where xcopy command is sent - change default to send xcopy to dst (was src) - improve CL handling of short options (e.g. '-vv') - sg_luns: guard against garbage response - sg_decode_sense: with --nospace ignore spaces on command line, so multiple arguments are concatenated - sg_write_same: repeat if unit attention - sg_rtpg: fix indexing bug with --extended option - sg_logs: placeholder for pending defects lpage - sg_unmap: fix another problem with --grpnum= option - sg_lib.h: add PDT_ZBC define (spc4r36p) - sg_lib_data: sync asc/ascq codes with T10 dated 20140320 - add pdt string for ZBC (spc4r36p) - sg_lib: extensions to sg_get_num() and sg_get_llnum() - sg_cmds_extra: fix sa bug in sg_ll_3party_copy_out() - scripts/rescan-scsi-bus.sh: check if FC driver exports issue_lip before using it - man page added (Linux only) - scripts/59-scsi-sg3_utils.rules: linux specific udev rules - examples: add sg_tst_excl3 for testing O_EXCL - improve sg_tst_excl and sg_tst_excl2 - add sg_tst_context for testing file handle contexts - upgrade automake to version 1.13.3 - add suse directory and 'spec' file to facilitate builds Changelog for sg3_utils-1.37 [20131014] [svn: r522] - sg_compare_and_write: fix wrprotect setting - add --quiet option to suppress miscompare report - merge features from another implementation - sg_inq: fix referrals VPD page - dev_id VPD: T10 vendor id designator clean up - sg_logs: improve for tape drives, general cleanup - sg_persist: fix core dump on -Q option - sg_unmap: fix core dump on -g option - sg_vpd: dev_id VPD: T10 vendor id designator clean up - cleanup up dev_id NAA-3: locally assigned - sg_ses: add --nickname and --nickid options - eiioe added to additional element status page (ses3r6) - multiple --filter options to prune output - sg_verify: improve miscompare handling - rename --btychk=ndo option to --ndo=ndo (hide former) - add --quiet option - sg_xcopy: allow sg and bsg devices - fix for bpt going negative - limit each XCOPY(LID1) command to 65535 blocks - fix for seek in multi-segment copies - sg_sanitize: skip 15 second safety delay with --fail - sg_libs: extended copy opcode renamed (spc4r34) - sg_ll_receive_copy_results(): expand for all sa_s - add sg_get_sense_key() - add sg_ll_3party_copy_out() - add dStrHexErr(): ascii hex to stderr - add dStrHexStr(): ascii hex to string - add SG_LIB_CAT_MISCOMPARE to categories - clean header files - sg_pt_freebsd: sanity check on sense_resid; fix leaks - scripts/rescan-scsi-bus.sh KG's v1.57 + HR patch - improve wlun handling, detect updated and resized devices, better multipath support - Makefile.am cleanup - examples: add sg_tst_excl and sg_tst_excl2 Changelog for sg3_utils-1.36 [20130531] [svn: r497] - sg_vpd: Protocol-specific port information VPD page for SAS SSP, persistent connection (spl3r2), power disable (spl3r3) - block device characteristics: add FUAB bit - sg_xcopy: handle more descriptor types; handle zero maximum segment length; allow list IDs to be disabled; improve skip/seek handling; allow xcopy on destination - sg_reset: and --no-esc option to stop reset escalation - clean up cli, add long option names - sg_luns: add --test=ALUN option for decoding LUNs - decoded luns output in decimal or hex (if -HH given) - add '--linux' option to show Linux LUN after T10 representation, can map one to the other - sg_inq: add --vendor option to show standard inquiry's vendor specific fields in ASCII - take resid into account with response output - sg_sync: add --16 (for 16 byte command) and --timeout= - sg_logs: add data compression page (ssc4) - sg_sat_set_features: increase --lba from 1 to 4 bytes - sg_write_same: add --ndob option (sbc3r35d) - sg_map: mark as deprecated - sginfo: mark as deprecated, especially -l (list) - sg_lib: improve snprintf handling - sg_lib_data: sync asc/ascq codes with T10 20130117 - sg_cmds (lib): if noisy given, give more UA info - make code more C++ friendly Changelog for sg3_utils-1.35 [20130117] [svn: r476] - sg_compare_and_write: new utility - sg_inq+sg_vpd: block device characteristics VPD page: add product_type, WABEREQ, WACEREQ and VBULS fields - sg_inq: more --export option changes for udev - sg_vpd: add more rdac vendor specific vpd pages - sg_verify: add --ebytchk option for sbc3r34 changes - sg_stpg: --offline option: fix 'Invalid state 0xe' - sg_ses: Door Lock element changed to Door element and abbreviation changed from 'dl' to 'do' (ses3r05) - archive/rescan-scsi-bus.sh: upgrade to version 1.53hr - move rescan-scsi-bus.sh to scripts directory - sync to sbc3r34 - sg_lib: sg_ll_verify10+16 expand BYTCHK to 2 bit field - sg_pt_win32, sg_scan(win32): changes for cygwin 1.7.17 - clean up man page summary lines Changelog for sg3_utils-1.34 [20121013] [svn: r461] - sg_xcopy: new dd like utility for extended copy command - sg_copy_results: new utility for receive copy results - sg_verify: add 16 byte cdb, bytchk (data-out buffer) and group number support - sync to spc4r36 and sbc3r32 - sg_inq: add --export so sg_inq can replace udev's scsi_id - decode old EMC Symmetrix abuse of VPD page 0x83 - sg_vpd: decode old EMC Symmetrix abuse of VPD page 0x83 - sg_ses: increase max dpage response size to 64 KB - allow ident,locate on enclosure controller - more sanity for additional element status descriptor - sg_sanitize: add --ause, --fail and --test= - sg_luns: add long extended flat space addressing format - sg_logs: add ATA pass-through results lpage (SAT-2) - sg_rtpg: add --extended option - sg_senddiag: list rebuild assist diag page name - sg_pt_linux: expand DID_ (host_byte) codes - cope with a transport error plus sense data - prefer major() over MAJOR() macro - sg_lib: fix sg_get_command_name() service actions - report sdat_ovfl bit (if set) in sense data - decode extended_copy and receive_copy service actions - decode read_buffer and write_buffer modes - decode ATA PT fixed format sense (SAT-2) - sg_cmds_extra: add sg_ll_report_tgt_prt_grp2() - ./configure options: - change --enable-no-linux-bsg to --disable-linuxbsg - add --disable-scsistrings to reduce utility sizes Changelog for sg3_utils-1.33 [20120118] [svn: r435] - sg_ses: major rework of indexes (again), now two level - sg_write_buffer: new --specific option for mode specific field; new mode 13 (spc4r32) - sg_vpd: add hp3par volume info vendor VPD page - fix 'scsi ports' [0x88] page problem - add 'sinq' pseudo page for standard inquiry response - add power consumption page - sg_format: add --poll= option for request sense polling - improve handling of disks > 2 TB and DIF (protection) - sg_logs: LB provision lpage extra (sbc3r28) - sg_modes: application tag mpage subcode 0xf0->0x2 - sg_write_same: no prot fields when wrprotect=0 - sg_get_lba_status: reflect change in sbc3r25 to Parameter Data Length response field (offset reduced from 8 to 4) - sg_inq, sg_vpd: sync with spc4r33 - win32: change DataBufferOffset type per MSDN; caused problem with 64 bit machines (with buffered interface) - sg_luns: tweak documentation for vendor specific reports - add man pages for scsi_loging_level, scsi_mandat, scsi_satl and scsi_temperature Changelog for sg3_utils-1.32 [20110730] [svn: r410] - sg_sanitize: new utility for command added in sb3r27 - sg_sat_identify: add '--ident' to output WWN - sg_ses: major rework of descriptor output - add --index, --descriptor, --join, --clear, --get, and --set options - sg_raw: exit status corrections - sg_decode_sense: add --nospace and --hex options - sg_logs: fix bug with large --maxlen - zero response length when resid implies it is invalid - add scope field to lb provisioning lpage (sb3r27) - sg_inq: sync version descriptors with spc4r31 - sg_lib_data: sync asc/ascq codes with spc4r31 - sg_vpd: add LBPRZ field in LB provisioning VPD page - sg_format: allow format of pdt 7 (some MO drives) - sg_cmds_basic: sg_cmds_process_resp() handle status good with a sense key other than no_sense (e.g. completed) - add README.iscsi Changelog for sg3_utils-1.31 [20110216] [svn: r386] - sg_decode_sense: new utility to decode sense data - sg_vpd: LB provisioning + Block limits pages (sbc3r26) - sync asc/ascq and version descriptors with spc4r28 - sg_get_config, sg_rmsn, sg_verify: add --readonly option - sg_lib: implement forwarded sense data descriptor - decode user data segment referral sense data descriptor - sg_lib, sg_turs, sg_format: more precision for progress indication (two places after decimal point) - sg_lib(win32): add runtime selection of SPT direct or indirect interface - sg_read_buffer+sg_write_buffer: set SPT direct - add examples/forwarded_sense.txt + examples/ref_sense.txt Changelog for sg3_utils-1.30 [20101111] [svn: r363] - sg_referrals: new utility for REPORT REFERRALS - sbc3r25 renames 'thin' provisioning' to 'logical block provisioning': changes in sg_format, sg_inq, sg_logs, sg_modes, sg_readcap, sg_vpd - sg_inq: update version descriptor list to spc4r27 - extended inquiry vpd page add extended self test completion minutes field - sg_lib: sync asc/ascq list to spc4r27 - dStrHex(): trim excess trailing spaces - sg_read_long: add --readonly option (open() is rw) - sg_raw: add --readonly option (open() is rw) - allow bidirectional commands - sg_vpd: rdac vendor page [0xc8] parse corrections - extended inquiry vpd page add extended self test completion minutes field - sg_ses: expand --data (in) buffer to 2048 bytes - sg_opcodes: add extended parameter data for TMFs (spc4r26) - sg_dd: clean count calculation, document nocache flag - treat bsg devices as implicit sg_io - add more conversions - sg_write_same: if READ CAPACITY(16) fails try 10 byte variant - anticipate approval of proposal to allow UNMAP and ANCHOR bits to be set on WRITE SAME(10) with '--10' option - sg3_utils man page: sections added for OS device names Changelog for sg3_utils-1.29 [20100406] [svn: r334] - sg_rtpg: new logical block dependent state and bit (spc4r23) - sg_start: add '--readonly' option for ATA disks - sg_lib: update asc/ascq list to spc4r23 - sg_inq: update version descriptor list to spc4r23 - sg_vpd: block device characteristics page: fix form factor - update Extended Inquiry VPD page to spc4r23 - update Block Limits VPD page to sbc3r22 - update Thin Provisioning VPD page to sbc3r22 - Automation device serial number and Data transfer device element VPD pages (ssc4r01) - add Referrals VPD page (sbc3r22) - sg_logs: add thin provisioning and solid state media log pages - addition of IBM LTO specific log pages - sg_modes: new page names from ssc4r01 - sg_ses: sync with ses3r02 (SAS-2.1 connector types) - sg_unmap: add '--anchor' option (sbc3r22) - sg_write_same: add '--anchor' option (sbc3r22) - sg_pt interface: add set_scsi_pt_flags() to permit passing through SCSI_PT_FLAGS_QUEUE_AT_TAIL and AT_HEAD flags - add examples/sg_queue_tst+bsg_queue_tst for SG_FLAG_Q_AT_TAIL - add AM_MAINTAINER_MODE to configure.ac to lessen build issues - add BSD_LICENSE file to this and lib directories, refer to it from source and header files. Some source has GPL license Changelog for sg3_utils-1.28 [20091002] [svn: r315] - sg_unmap: new utility for thin provisioning - add examples/sg_unmap_example.txt - sg_get_lba_status: new utility for thin provisioning - sg_read_block_limits: new utility for tape drives - sg_logs: add cache memory statistics log (sub)page - sg_vpd, sg_inq: extend Block limits VPD page (sbc3r19) - sg_vpd: add Thin provisioning VPD page (sbc3r20) and TapeAlert supported flags VPD page - sg_inq: note VPD page support better in sg_vpd - sg_persist: add transport specific transportID format - allow transportIDs to be read from named file - sg_opcodes: allow --opcode= option to take OP and SA values (comma seperated) - tweak print format, remove test code - sg_requests: remove test code in progress calculation - sg_reset: add target reset option - sg_luns: reduce default maxlen to 8192 (for FreeBSD) - sg_raw: extend max cdb length from 16 to 256 bytes - align heap allocs to page boundaries - sg_lib: sg_set_binary_mode() needs config.h included - add progress indication sense data descriptor (0xa) - change SG3_UTILS_* constants to SG_LIB_* - decode service actions within persistent reserve in/out - sync with spc4r21 - sg_cmds_extra: add sg_ll_unmap() and sg_ll_get_lba_status() - sg_pt_linux: fix check condition but empty sense buffer; occurred when sg v3 node used and /usr/include/linux/bsg.h visible - major() macro grief, if present include and use MAJOR() instead - scripts/sas_disk_blink: moved from this package to sdparm - utils/hxascdmp: in Windows set binary mode on read files - examples/sg_persist_tst.sh: add PRIN read full status command - sg_raw,sg_write_buffer,sg_write_long,sg_write_same: in Windows set binary mode on read files - sg_pt_win32: default to non-direct variant of SPT interface - use './configure --enable-win32-spt-direct' to override - non-direct data length set to 16 KB, extended if required - debian: incorporate patch from debian sid Changelog for sg3_utils-1.27 [20090411] [svn: r250] - sg_write_same: new utility: 10, 16 and 32 byte cdb variants - sg_inq: sync version descriptors with spc4r18 - add power condition VPD page - expand block limits VPD page (sbc3r18) - sg_vpd: add power condition VPD page - expand block limits VPD page (sbc3r18) - sg_map26: fix for lk 2.6.26 when CONFIG_SYSFS_DEPRECATED_V2 is not defined - output cdb when verbose option given - correct tape minors >= 32 - sg_dd: flock flag (does LOCK_EX|LOCK_NB) - switch open on input for sg device nodes: first open read-write and if that fails try opening read-only - experiment with of2=OFILE2; add conv=sparse - use posix_fadvise() to defeat caching of normal+block files when new 'nocache' flag given - sg_dd copied to own package called ddpt - sg_dd, sgm_dd, sgp_dd: accept 'count=-1' for calculate count, accept '-V' for version string - sg_get_config: add OSSC feature [mmc6r02] - sg_modes: add ATA power condition mode page - sg_logs: protocol specific (SAS) lpage sync to sas2r15 - power condition transitions lpage (added in spc4r18) - extra parameters for start-stop cycle counter lpage - sg_format: add '--fmtpinfo=' and '--pie=' options (sbc3r18) - sg_readcap: more protection + thin provisioning (sbc3r18) - add a '--16' option for 16 byte cdb version - sg_persist: code clean up - allow '--transport-id=' argument to use space as separator - add '--alloc-length=' argument - sg_scan: (win32) new format, scsi adapter scan optional - sginfo: fix crash when 1024 sg device nodes (or more) - sg_ses: allow '--data=' argument to use space as separator - sg_senddiag: allow '--raw=' argument to use space as separator - sg_reassign: allow '--address=' argument to use space as separator - sg_wr_mode: allow '--contents=' and '--mask=' arguments to use space as separator - sg3_utils.spec: correction to configure call - sg_pt: add scsi_pt_open_device_flags() call - add scsi_pt_version() and clear_scsi_pt_obj() calls - clear os_err at start of do_scsi_pt() - add linux bsg support via runtime detection - sg_cmds: add sg_cmds_open_device_flags() - sg_cmds_extra: sg_ll_format_unit: remove rto_req argument, the expanded fmtpinfo argument subsumes it. - clearer split between Linux and Windows only code and doc - automake tools: change to what Ubuntu 8.10 provides - Ubuntu 8.10 libtool problems -> Debian 4.0 Changelog for sg3_utils-1.26 [20080625] [svn: r183] - sg_sat_phy_event: new utility; copied from examples directory and enhanced, rename original to sg__sat_phy_event - sg_ses: sync with ses2r19b, many nomenclature changes - sg_get_config: sync with mmc6r01 - allow Microcode upgrade and DVD read feature descriptors to be 4 bytes long - add '--raw' option - sg_verify: add --vrprotect= option - sg_vpd: add nominal form factor to block dev. char. VPD page - add --maxlen= option to set allocation length in cdb - sg_inq: add --maxlen= option that does same as --len= - move version descriptors (spc4r15) to sg_inq_data.c file - sg_inq+sg_vpd: logic for "NAA-3 Locally assigned" identifier - update extended inquiry VPD page - sg_modes: add --maxlen= option to specify allocation length - sg_start: add '--noflush' and '--mod=PC_MOD' options (sbc3r14) - sg_request: add a '--progress' option (similar to sg_turs) - add --maxlen= option to set allocation length in cdb - sg_luns: add --maxlen= option to specify allocation length - sg_dd: improve MMC handling of 'illegal mode for this track' read errors (with ILI and info field) - sg_dd, sgm_dd, sgp_dd, sginfo, sg_rbuf, sg_read: replace "%lld" and friends with PRI macros - sg_opcodes: tmf name change in spc4r15 (async event) - sg_turs: add more to man page about '--progress' indication - sg_write_long: add examples section to man page - '--raw' option: modify utilities that can send binary output to call sg_set_binary_mode(). For MingGW port CR problem. - sg_lib: update asc/ascq and command name strings to spc4r15 - split sg_lib into sg_lib_data.[hc] and sg_lib.[hc] - split sg_cmds_extra into sg_cmds_extra and sg_cmds_mmc - add osd2r03 service actions (all different from osd-r10) - add sg_get_trans_proto_str() - add sg_get_sense_filemark_eom_ili() function (MMC uses ILI) - add sense key specific unit attention condition queue overflow decoding (added in spc4r13) - add sg_set_text_mode() and sg_set_binary_mode() functions for non-Unix OSes - sg_cmds_mmc: add sg_ll_set_streaming() function - sg_cmds_extra: add vrprotect argument to sg_ll_verify10() - add sg_ll_get_performance() and sg_ll_set_cd_speed() - change 'long long' to int64_t and 'unsigned long long' to uint64_t to stress that 64 bit integer wanted, not larger - audit of dangerous 'u64 = uch[24] << 24' code, replace most 'unsigned long's - multiple documentation corrections provided by Dan Horak - win32/MinGW: define SG3_UTILS_MINGW when detected - remove archive/pre_configure subdirectory - move sg_io_linux.c into the lib subdirectory - utils/hxascdmp: add hxascdmp(1) man page - switch primary build to ubuntu environment, rename library to libsgutils2 to avoid clash Changelog for sg3_utils-1.25 [20071016] [svn: r115] - sg_stpg: new utility to Set Target Port Groups - sg_safte: new utility to query SAF-TE processor (SES like) - sg_sat_set_features: new utility (actually copied from examples directory); renamed examples version to: sg__sat_set_features - sg_read_buffer: restore (had fallen out of build scripts) - sg_dd: add oflag=sparse to step over bs*bpt number of zeros; - with oflag=sparse, write last bs*bpt segment at end or after error so file length of OFILE is appropriate - when coe>1 then SCSI READ LONG logic remembers extended block length of first encountered error - sg_dd, sgm_dd, sgp_dd: allow iflag=null and oflag=null both of which do nothing (placeholders) - sg_ses: sync with ses2r17 then r18 - sg_vpd, sg_inq: add block device characteristics VPD page - sg_inq: add '--vpd' option (or '-e') for backward compatibility - sg_vpd: decode protocol specific lu information page for SAS - add more RDAC vendor VPD pages - sg_logs: update background scan results log page, sbc3r11 - add generation code to protocol specific page for SAS SSP - add media changer diagnostic data log page - sg_raw: fix error message when do_scsi_pt() fails - sg_lib: sync asc/ascq codes with spc4r11 - add sg_get_num_nomult() - add TPROTO_* protocol identifier constants to sg_lib.h - sg_cmds_extra: add sg_ll_set_tgt_prt_grp() - place source in subversion repository - split code into src/ lib/ and include/ directories - sync debian directory with their 1.24 version (sid unstable) - convert build logic to use autotools (i.e. './configure ; make') - rename this file from CHANGELOG to ChangeLog - note: only code in lib/ and src/ directories built by autotools; some other subdirectories still use hand-crafted Makefiles Changelog for sg3_utils-1.24 [20070507] [svn: r77] - sg_raw: new utility to send arbirary SCSI commands - sg_luns: increase number of luns that can be fetched - fix length of raw and hex output - add '--quiet' option to output only ASCII hex representation of each lun - sg_rtpg: update for changes in spc4r09 - sg_persist: update documentation, spc-4 references - fix exit status values - sg_inq: update version descriptors per spc4r09 - fix '--id' and '--extended' - extend block limits VPD page (sbc3r09) - sg_vpd: extend block limits VPD page (sbc3r09) - append relative target port identifier to SAS target port address with '-iq' option - sg_logs: add decoding for stats+performance log pages - fix showing of page names for pdt > 0 - implement '-HH' for single and all pages, fix '-r' - when '--maxlen=' given, only do single fetch - add Tape Alert (ssc), Media and Element statistics (smc) pages - add '--brief' option - sg_ses: sync with ses2r16 - fix bay number for SAS - sg_format: add '--dcrt' and '--security' options - sgm_dd: add 'smmap' oflag for shared_mmap_io testing - add 'dio' oflag - sg_dd, sgp_dd: add 'dio' iflag and oflag - sg_modes: change SAS mode page names per sas2r09 - check validity of block descriptors length - sg_pt: change opaque context object from 'void *' to 'struct sg_pt_base *' - sg_opcodes: anticipate extra tmfs from 07-159r0 - sg_sat_set_features: add more usage information - add man page - sg_sat_phy_event: add to examples directory - sg_lib: sync asc/ascq codes with spc4r10 - Solaris port: using uscsi interface - various .html files removed from doc directory Changelog for sg3_utils-1.23 [20070131] [svn: 75] - sg_read_buffer: new utility - sg_write_buffer: new utility - sg_opcodes, sg_senddiag, sg_logs, sg_modes, sg_start, sg_inq, sg_turs, sg_readcap, sg_rbuf: add getopt_long() based cli; old and new cli selectable, new getopt_long cli is default - scripts: new subdirectory containing some bash scripts - add scripts/README file - sg_reassign: add '--hex' option for grown and primary lists - sg_rtpg: add '--raw' option - sg_lib.h, sg_cmds_basic.h + sg_cmds_extra.h: add C++ 'extern "C" ' wrappers - cleanup C code so it will compile as C++ - sg_lib: sync with spc4r08 - include , use PRId64 instead of %lld form - fix sg_get_sense_str() when empty sense buffer - win32 port: add Makefile.mingw + related support for MinGW - sg_cmds_extra: add sg_ll_read_buffer() and sg_ll_write_buffer() - sg_dd, sgp_dd, sgm_dd, sg_read: use lseek64() instead of llseek.c - sgm_dd: accept coe= for interworking with sg_dd - sg_rdac: fix on non-linux ports - sg_ses: fix spurious warning in additional element status page - '-rr' option outputs a diagnostic page in binary to stdout - sg_opcodes: add command timeout descriptor support (spc4r08) - change linux specific pass through to generic pass through - sg_logs: add 'name=value' decoding for SAS specific lpage - examples+utils subdirectories: remove symlinks - synchronize man pages with usage messages - sg3_utils.spec: rework Changelog for sg3_utils-1.22 [20061016] [svn: 72] - sgp_dd: accept verbose= as well as deb= to ease interworking with sg_dd and sgm_dd - sg_sat_set_features: added to examples directory - sg_lib: sync asc/ascq text with spc4r06 - move SG_LIB_CAT_NO_SENSE and SG_LIB_CAT_RECOVERED to 20 and 21 respectively; add SG_LIB_CAT_ABORTED_COMMAND at 11 (its sense key value) - sg_vpd: tweak '--page=sp --quiet' output - change '-HHH' so same as '-rr' (prepares ATA Information (ai) response for hdparm) - sg_requests: add '-s' option to set exit status from parameter data - sg_modes: exit quickly from '-e' if device not ready - sg_logs: sync sas log pages with sas2r05a - expand background scan results log page - add '-m=' to limit response length - drop '-scum' and '-sthr' options and add '-select' - sg_write_long: add '--16' option to send 16 byte cdb - add '--wr_uncor' and '--pblock' options - sg_senddiag: cleanup and add sdiag_sas_p1_stop.txt to examples directory - sg_format: add '--cmplst=' option (default: 1) - add '--pfu=' option - expand man page to discuss P/D/C/GLISTs - sg_reassign: add '--primary' option to fetch primary defect list (PLIST) length - sg_readcap: add '-H' option to output response in hex and '-r' to output response in binary to stdout - add logical blocks per physical block (sbc3r07) - sginfo: add PLIST and GLIST designation to defect lists - sg_cmds: split this support file into sg_cmds_basic.[hc] and sg_cmds_extra.[hc] - add sg_ll_ata_pt() (SATL ATA pass) to sg_cmds_extra.[hc] - sg_rdac: fix includes for FreeBSD - sg_dd: add 'coe_limit=' option to exit after consecutive 'coe' type read errors - sgm_dd: print out throughput information when signal arrives if time=1 (like sg_dd does already) - sg_inq: change '-HHH' so same as '-rr'. Now sg_inq, sg_vpd and sdparm output for hdparm with '-HHH' -add '-l=' option - sg_read_long: add '--pblock' option for physical blocks - sg_luns: add '--hex' and '--raw' options - sg_requests: add '--hex' and '--raw' options - sg_scan: windows version added (was previously linux only) - 2 man pages: sg_scan.8l and sg_scan.8w that are installed as sg_scan.8 - archive directory: removed all but rescan-scsi-bus.sh - README points to previous version in that directory - sg_sat_identify: add to main directory - rename earlier version to examples/sg__sat_identify.c - sg_ident: rework as spc4r07 changed command names and expanded functionality Changelog for sg3_utils-1.21 [20060706] [svn: 70] - sg_vpd: new utility for decoding VPD pages. sg_inq's cli is cluttered; also borrows from sdparm's VPD handling - sg_rdac: new utility for vendor specific work - sg_lib: add sg_vpd_dev_id_iter() to iterate over di VPD page - add sg_ata_get_chars() to fetch chars from ATA words - sync additional sense code strings with spc4r05a - add SG_LIB_CAT_NOT_READY category when sense_key is NOT READY - add SG_LIB_FILE_ERROR category for open problems - add SG_LIB_SYNTAX_ERROR category for command line problems - broaden SG_LIB_CAT_MEDIA_CHANGED to SG_LIB_CAT_UNIT_ATTENTION - add SG_LIB_CAT_MALFORMED for bad responses - BEWARE: these changes cause confusion if an executable from this version is run with a libsgutils library from 1.20 or earlier - sg_cmds: add SG_LIB_CAT_NOT_READY return to most "ll" functions - alter many utilities to report SG_LIB_CAT_NOT_READY - sg_dd: add retries= option for sg_io - sg_logs: add '-T' option to output protocol specific port log page - add support for log subpages (new in spc4r05) - more sanity checks in Start Stop Cycle Counter page - sg_cmds: add sg_ll_read_long16() - add page_code and subpage_code to sg_ll_log_select() - add subpage_code to sg_ll_log_sense() - sg_read_long: do READ LONG(16) when '--16' given - sg_read: accept and ignore 'of=' arguments - sg_dd: expand medium/hardware error "coe' processing to include the "blank check" sense key (for optical devices) - sg_ses: expand display element (per 05-011r2) - sg_format: clear 'cmplst' bit (for MO disks) - add '--six' ('-6') option for mode sense/select(6) - sg_format + sg_test_rwbuf: fix for when char is unsigned - sg_inq: VPD page 0x89: output ATA IDENTIFY DEVICE strings - for IDENTIFY (PACKET) DEVICE response use sg_ata_get_chars() - sg3_utils.html : new name, was previously u_index.html. Copy placed in doc subdirectory - tools.html : SCSI and storage tools reference, copy placed in doc subdirectory - sg3_utils.8 : add a new man page containing general information especially common exit status values - sg_sat_identify: added to examples directory (SAT passthrough test) - extend to pass through IDENTIFY PACKET DEVICE with '-p' option - sg_sat_chk_power: added to examples directory - sg_sat_smart_rd_data: added to examples directory - sg_chk_asc: added to utils directory to check asc_ascq codes - debian: stop placing archive directory under examples - add build_debian.sh script Changelog for sg3_utils-1.20 [20060418] [svn: 68] - sg_logs: decode phy event descriptors in SAS port specific log page (sas2r03) - new parameter control byte format (spc4r03), subpages to come - update Makefile (linux) to install sg_io_linux.h + sg_linux_inc.h - sg_map26: fix for block device mapping in lk 2.6.16-rc1 and beyond - cope with sysfs removal of 'generic' symlink post lk 2.6.16, anticipate removal of 'tape' symlink - sg_dd, sgm_dd, sgp_dd: fix problem around 0x7fffffff blocks - sg_dd: fix read_long processing error (when 'coe=2' or 3) - expand 'coe=' to take 0...3 (invokes read long with 2 or 3) - allow for SG_GET_RESERVED_SIZE yielding 0, lk 2.6.16 feature - sgp_dd: add 'iflag=' and 'oflag=' arguments; signals (like sg_dd) - sgm_dd: add 'iflag=' and 'oflag=' arguments; signals (like sg_dd) - sg_get_config: double->dual renaming (mmc5r03) - sg_read: add 'dpo=' and 'fua=' options - allow 'count' < 0 (or 'bpt=0') for issuing zero block READs - allow for SG_GET_RESERVED_SIZE yielding 0, lk 2.6.16 feature - add 'no_dxfer=0|1' option - sg_modes: fix exit value when MODE SENSE fails - add '-e' to examine presence of page codes from 0x0 to 0x3e - sg_requests: add '--num=' and '--time' options for timing multiple invocations - sg_inq: fix vpd 0x83 designator code 8 name: "scsi name string" - sg_scan: if lk 2.6, use sysfs to find active sg device nodes - sg_map: if lk 2.6, use sysfs to find active sg device nodes - sg_ses: expand display element (per 05-011r1) - sg_start: add an '-i' option which is equivalent to '--imm=1' - sg_senddiag: update man page showing use of two scripts in examples directory (sdiag_sas_p0_cjtpat.txt and _p1_) - sg_lib: fix sg_get_sense_descriptors_str() case 9 (ATA Return) Changelog for sg3_utils-1.19 [20060127] [svn: 66] - sg_start: accept '--' options (e.g. 'sg_start --stop') - add '--fl=' option for jump to format layer (mmc5) - sg_logs: background scan log page, resync with sbc3r03 - add '-scum' and '-sthr' for setting defaults - add device statistics log page (ssc + adc) - fix "last n" deferred errors/error events incrementing - partial addition of log subpages (spc4r03) - sg_get_config: sync features with mmc5 rev 02b - sg_wr_mode: mask out dpofua bit in mode select header - sg_inq: try harder with '-A' to identify ATA device - broaden meaning of '-d' option to decode ... - decode software interface id VPD page ('-p=84 -d') - decode device capabilities (ssc) VPD page ('-p=b0 -d') - sginfo: correct defect list handling ('-d' and '-G') - sg_verify: improve error processing (e.g. medium errors) - sg_ses: scsi target_initiator port additional element status (ses2r14) - many: arguments that currently accept '0x' or '0X' to indicate a hex number may alternatively take a trailing 'h' or 'H' to indicate hex - sg_lib: update asc/ascq strings (spc4r03) - sg_lib+sg_cmds: make independent of linux via sg_pt.h function based interface. - linux pass through code placed in sg_pt_linux.c - rename sg_include.h to sg_linux_inc.h - linux specific code in sg_lib.[hc] moved to sg_io_linux.[hc] - port to FreeBSD: using sg_pt_freebsd.c - port to Tru64: using sg_pt_osf1.c - sg_cmds: add sg_ll_get_config(), sg_ll_format_unit(), sg_ll_reassign_blocks(), sg_ll_persistent_reserve_in+out(), sg_ll_read_long10(), sg_ll_verify10(), sg_ll_write_long10() - sg_persist: add "allow commands" to report capabilities - sg_persist_tst: (examples) takes device node as argument - sg_luns: add "security protocol" wlun Changelog for sg3_utils-1.18 [20051118] [svn:63] - sg_map26: new utility to map sg devices in lk 2.6 - sg_luns: luns > 16,384 (sam-4 rev 4) - sg_ses: bump fan speed field to 11 bits - SAS connector names (ses2r13) - sg_inq: add '-rr' option for "hdparm --Istdin" - sg_get_config: tracking mmc-5 - sg_write_long: add support for COR_DIS bit - sg_cmds: add sg_ll_test_unit_ready_progress() - sg_turs: '-p' option shows progress - sg_dd: add 'iflag=' and 'oflag=' options - remove output of mode page info when verbose > 0 - add control of DPO bit via iflag/oflag - sg_lib: add sg_get_pdt_str() - update asc/ascq strings - sg_modes + sginfo: add SAS(2) SSP shared mode subpage - doc: rename "html" directory to "doc" - Makefile: add 'libtool --finish' to install Changelog for sg3_utils-1.17 [20050922] [svn: 60] - sg_inq: add '-a' option for ATA information VPD page - add '-b' option for Block limits VPD page (SBC) - add '-A' option for probing ATA or ATAPI device - increase raw ('-r') and verbose ('-v') output for ATA(PI) devices to 512 bytes (was 256 bytes) - output hex ('-H') and verbose response for ATA(PI) devices in 16 bit words (corrected for endianness) - output bytes if '-HH' option given - sync with spc4 rev 02 - sg_lib: add dWordHex() and sg_is_big_endian() - sync asc/ascq with spc4 rev 02 - sg_cmds: defensive prefill for inquiry commands - sg_opcodes: sync with spc4 rev 02 (add tmf I_T nexus reset) - sginfo: add EBACKERR in Informational exception mode page - add Background control mode page (SBC-3) - sgm_dd: add 'verbose=' option Changelog for sg3_utils-1.16 [20050810] [svn: 58] - sg_ident: new utility to report+set device identifier - sg_map: increase MAX_SG_DEVS from 256 to 2048 - debian: new directory to support deb package builds - sg_get_config: add '--current' option, same as '--rt=1' - update for DVD+RW Dual Layer - sg_inq: add notes in source about use of SCSI INQUIRY - decode Management network addresses VPD page ('-m') - decode Mode page policy VPD page ('-M') - sginfo: increase device mapping capability (> 78 disks) - add '-r' option to scan /dev/raw* device nodes [Tim Hunt] - sg_dd: change bpt default value to 32 when bs >= 2048 bytes - sg_ses: mention SAF-TE in man page - sg_readcap: add '-b' option for brief output (2 hex numbers) - sg_cmds: add sg_ll_start_stop_unit(), sg_ll_prevent_allow(), sg_ll_report_dev_id() and sg_ll_set_dev_id() - sg_lib: add extra argument to sense print functions to enable the suppression of the raw output of the sense buffer - resid > 0 warnings now includes number actually fetched - sg_start: add '-load' and '-eject' options - default to start action when no other indication given - change -imm=0|1 option default to 0 (was 1) - gcc 4.0: cleanup warnings (apart from sgp_dd: revisit later) Changelog for sg3_utils-1.15 [20050605] [svn: 56] - sg_cmds: sg_get_mode_page_controls(): improve error processing, add double fetch - sg_turs, sg_rbuf, sg_requests, sg_test_rwbuf, sg_format, sg_dd and sgm_dd: add O_NONBLOCK to open() - sgm_dd: switch to use SG_IO ioctl (that leaves only sgp_dd using the asynchronous sg write()/read() sequence) - sg_ses: sync with rev 12 changes - sg_map: extend to cope with sparse disk device names with up to 3 letters (e.g. /dev/sdaaa) [Nate Dailey] - sg_modes: add '-f' option to flexibly decode broken mode sense responses. - zero prefill response; stop decoding response after 3 unit attention mode pages seen (i.e. malformed) - add '-L' option for LLBAA bit in msense 10 cdb - sg_reset: update man page - sg_inq: VPD page 0x83: output eui addresses in hex as well - Makefile: fix bug in rules for sgp_dd (when 'make dep' used) - sg_format: expand explanations in its man page - sg_inq, sg_logs, sg_modes, sg_opcodes, sg_rbuf, sg_readcap, sg_scan, sg_senddiag, sg_start and sg_turs: allow command line to take concaternated options - sg_start: add -start and -stop to parallel "1" and "0" - sg_senddiag: set pf bit with '-l' option Changelog for sg3_utils-1.14 [20050506] [svn: 54] - sg_rmsn: new utility to read media serial number - sg_rtpg: add T_SUP bit report - sg_ses: ses-2 rev 11 changes (mainly to additional element status) - add 'bay number' to SAS additional element status - sg_modes: recognise attached enclosure and medium changer - sg_inq: spell out non-zero peripheral qualifiers - note VS bit preceding MultiP(ort) when latter set - VPD page 0x83: output naa addresses in hex as well - sginfo: recognise attached enclosure and medium changer - increase device mapping capability (to 78 disks) [Tim Hunt] - sg_senddiag: add option to send raw diagnostic page - sg_get_config: update some BD information - sg_reasign: add '-g' option to give grown defect list length - sg_dd: note default bpt value (128) may be too high for cd/dvds - sg_lib: sync with SPC-3 rev 22a [opcodes + asc/q] - add DID_IMM_RETRY and DID_REQUEUE [linux specific "host" bytes] - sg_cmds: add send+receive diagnostic, read defect data commands - add duration output on some commands when verbose > 2 - spec: change to produce libsgutils (and -devel variant) as well as sg3_utils binary rpms - sdparm: new utility like hdparm but for SCSI disks (or other devices) - moved to its own package called: sdparm Changelog for sg3_utils-1.13 [20050313] [svn: 52] - sg_format: new utility to format disks (perhaps change block size) - sg_ses: rename "device element" to "additional element" [SES-2 rev 10] - add SAS expander and connector elements; add download microcode and subenclosure nickname diagnostic pages - fix additional element descriptor for SAS - off by 1 error when no type descriptor text in config page - sg_logs: log page for background media scan results - sginfo: add "-flba64" option for outputting 64 bit lba defect lists - sg_get_config: additions for BD from MMC-5 rev 1b - sg_lib: add SG_LIB_CAT_ILLEGAL_REQ sense category - add sg_get_sense_progress_fld() - SPC-3 rev21d updates: report + set timestamp - sg_get_num() + sg_get_llnum(): switch to multipliers that are compatible with SI and with IEC 60027-2. Used modern GNU's dd command as guide. - report field replaceable unit code in fixed format - sg_dd: add logic to use read_long on unrecovered read errors when 'coe' set, read just prior to error if 'coe' clear - both 'odir' and 'blk_sgio" are honoured on block devices - add 'verbose' switch, output some mode page info when verbose - print out elapsed time/throughput when signal received - add new web page discussing sg_dd, copy in html subdirectory - sg_read: add 'blk_sgio' and 'odir' options - sg_wr_mode: clear mode data length in mode select(10) - sg_test_rwbuf: add long options, allow test to run multiple times - sg_cmds: add sg_get_mode_page_types() [get current, changeable, etc] - llseek.c: add Makefile rule without "-std=c99", breaks on some archs Changelog for sg3_utils-1.12 [20050121] [svn: 50] - sg_wr_mode: new utility to modify (i.e. write to) mode pages - sg_reassign: new utility: issues Reassign Blocks command - sg_rtpg: new utility: issues Report Target Port Groups command [Christophe Varoqui] - ATA IDENTIFY command misspelt as "IDENTITY" in several places - sginfo: tweak SAS mode pages to match sas 1.1 rev 07 - add NV_DIS bit to disk caching mode page - sg_map: open /dev/nst* rather than /dev/st* (to stop spurious rewinds) - sg_lib: ATA return sense descriptor - add sg_get_sense_info_fld() to fetch info field from sense data - fix bug in sg_scsi_sense_desc_find() - add sense key specific decoding for fixed format sense data - sg_modes: extend '-p' option to allow '-p=,' - add '-A' option to output all mode pages and subpages - extend '-l' option to show subpages, selected command set pages - sg_inq: fix LUN WWN output in unit path report VPD page (emc) [Hergen Lange] - sg_get_config: some additions for DVD-R dual layer - sg_modes: show write protect (WP) and DpoFua flags for disks - sg_cmds: add llbaa argument to sg_ll_mode_sense10() Changelog for sg3_utils-1.11 [20041126] [svn: 48] - sg_sync: new utility: invokes the synchronize cache command - sg_prevent: new utility: invokes the prevent allow medium removal command - sg_get_config: new utility: get configuration command for dvds and cds - sg_request: fix, allocation length wasn't set - sg_start: remove '-s', as start_stop_unit implicitly syncs caches - sg_ses: add SAS expander element type - sg_inq: add sanity check to unit serial number (VPD page 0x80) - output ANSI version string (e.g. "SPC-2", previously was number) - add '-s' option to decode SCSI Ports VPD page - sg_logs: decoding of format status and non-volatile cache log pages (0x8 and 0x17 in sbc-2) - sg_dd: handle compile error when O_DIRECT not defined - sginfo: tighten sanity checks around Unit serial number VPD page Changelog for sg3_utils-1.10 [20041030] [svn: 46] - sg_readcap, sg_dd, sgm_dd, sgp_dd: fix sg_ll_readcap_10+16 (sg_cmds.c) - sg_luns: new utility to report luns - sg_logs: with '-t' (show temperature) ignore extra parameters in temperature log page (still show them with '-p=d') - sg_ses: clean argument sanity checks - sg_cmds: add more common command wrappers Changelog for sg3_utils-1.09 [20041022] [svn: 44] - sg_ses: new utility to get status and set control on SES devices - sg_verify: new utility to verify block devices - sg_emc_trespass: new utility for EMC specific trespass mode page - sg_request: new utility that sends a REQUEST SENSE command - sg_logs: '-r' to reset to manufacturer's defaults - decode last n error events and last n deferred errors pages - add names of ADC log pages - sg_inq: update to SPC-3 rev 21 - decode Extended INQUIRY data VPD page [0x86] {'-x'} - decode Unit Path Report VPD page [0xc0] (EMC) {'-P'} - sginfo: decode SAS protocol specific lu mode page - sg_err: convert to sg_lib + update to SPC-3 rev 21 - change GPL to FreeBSD license - flag vendor specific asc/ascq ranges - libsgutils: library made from sg_lib.c and sg_cmds.c - rpm "spec" file additionally builds a "-devel" rpm with static libsgutils.a and sg_lib.h and sg_cmds.h - utils/hxascdmp.c: add FreeBSD license - sg_persist: additions to man page - add sg_persist_tst.sh example script to examples directory - sg_turs: add '-v' and '-V' options - sg_senddiag: add '-v' option Changelog for sg3_utils-1.08 [20040831] [svn: 42] - sg_inq: fix noisy message when EVPD and raw modes set - for VPD page 0, list supported page names if known {'-e'} - add '-d' option to list version descriptors - sg_opcodes: numerically sort list of opcodes unless '-u' given - add '-a' to sort alphabetically list of opcode names - add '-t' to report supported task management functions - sg_persist: add 'register and move" PROUT service action - add transportId support, document in sg_persist.8 and example - sg_modes: handle subpage code for known pages (e.g. control extension) - clean up sense buffer handling (allow for descriptor format) - SPC-3 draft revision 20a updates - sg_write_long: new utility to exercise WRITE LONG command - sg_read_long: new utility to exercise READ LONG command - sg_err.c: fix compile errors when SG_KERNEL_INCLUDES defined in lk 2.6 - sg_includes.h typedef of u64 for BLKGETSIZE64 ioctl in lk 2.4 - add safe_strerror(), sg_scsi_normalize_sense(), sg_normalize_sense() and sg_scsi_sense_desc_find() functions - add more sense data descriptor format decoding - move multiple implementations of dStrHex() into sg_err.c - sg_logs: exit if SCSI INQUIRY fails (e.g. when applied to ATA disk) - sginfo: bug fixes and SPC-3 revision 20a updates - add '-E' option to access Control Extension mode (sub)page - sg_start: change '-d' switch to '-v' (verbose) switch for consistency - document extra power condition states in man page - sg_readcap: output rto_en and prot_en bits from long read capacity data - add COVERAGE file to list SCSI command coverage Changelog for sg3_utils-1.07 [20040708] [svn: 40] - sginfo: clean up inquiry vendor,product,revision strings - '-Fhead': sort defect list by head Tom Steudten - rework sg_err for better command name coverage: service actions, variable length and peripheral device type - update asc,ascq codes to SPC-3 revision 19 - move scsi_devfs_scan to archive directory - add sg_opcodes utility to list supported operation codes - add sg_persist utility to support persistent reservations - add '-i' option to sg_inq to decode device identification VPD page (0x83) - sg_inq tries an ATA IDENTIFY if SCSI INQUIRY fails - sg_dd, sgm_dd and sgp_dd calculate block device sizes (if count not given) - drop SG_GET_VERSION_NUM ioctl guard in most utilities Changelog for sg3_utils-1.06 [20040426] [svn: 37] - sg_logs: some HBAs don't like odd transfer lengths so increment - do INQUIRY and output product strings - add ASCII rendering of the Protocol specific SAS page - add '-v' verbose option to output cdb - sg_scan: optionally take device file names (e.g. /dev/hdc and /dev/sda) - only request 36 byte INQUIRY responses - sg_err: add sg_decode_sense() function - sg_inq: update output (ref: SPC-3 t10/1416-d rev 17, 28 January 2004) - remove '-p' option to print out PCI address of host - add '-v' verbose option to output cdb - sginfo: allow '-u' to take hex arguments (prefixed by '0x'), when subpage value is 255 show multiple subpages - accept /dev/hd? ATAPI devices directly in lk 2.6 - add '-t [,]' argument; like '-u' but decodes page if it recognizes it - drop '-L' argument - add cd/dvd, tape, SES, more disk and more SPC-3 decoded mode pages - add transport protocol decoded mode pages for SPI-4, FCP and SAS - sg_modes: print all subpages when '-subp=ff' is selected - do INQUIRY and output product strings - add '-v' verbose option to output cdb - Makefile: add -W compile flag and fix exposed warnings - .spec file: change to build on Mandrake without errors Changelog for sg3_utils-1.05 [20031112] [svn: 35] - sginfo: major rework; add IE page, clean up control, cache + disconnect pages (as per SPC-3 and SBC-2). - when storing, update saved page (change from previous version) - use 10 byte mode sense and select by default (override with '-6') - mode subpage support - sg_dd, sgm_dd + sgp_dd: - 64 bit capable (read capacity; count, skip and seek values). - numerical arguments accept hex (prefixed by '0x' or '0X') - require bpt > 0 - fix problem when reading /dev/null - sg_dd: Treat SIGUSR1 properly: print stats and continue; - sgp_dd: reduce READ CAPACITY response size to 8 bytes - sg_read: require bpt > 0 - sg_test_rwbuf: switch from sg_header to sg_io_hdr interface N.B. After these changes no sg3_utils utilities (in the main directory) use the sg_header interface - sg_scan: switch from sg_header to sg_io_hdr interface - sg_senddiag: increase extended foreground timeout to 60 minutes - sg_inq: add names of peripheral device types - sg_readcap: show total size in bytes, MB, GB - sg_logs: read log pages twice (first time to get response length), for fragile HBAs; decode Seagate 0x37 + 0x3e pages; display pcbs - sg_modes: fix core dump when corrupted response, don't print extra pages - sg_map: increase sg device scanning from 128 to 256 - change man page references from lk 2.5 to lk 2.6 - examples/sg_iovec_tst: added testing sg_iovec (sg_io_hdr iovec's) [retrospective addition to this log: "#define __user" added into sg_include.h so user space programs aren't broken if they choose to include kernel header.] - utils/hxascdmp: add utility for displaying ASCII hex Changelog for sg3_utils-1.04 [20030513] [svn: 33] - all remaining utilities in the main directory have man pages [thanks to Eric Schwartz for 7 man pages] - add CREDITS file - sg_simple1, sg_simple2, sg_simple3, sg_simple4, sg_simple16 and scsi_inquiry: moved to the examples directory - sg_debug: moved to the archive directory - sg_modes: add '-subp=' for sub page code, suggests 6/10 byte alternative if bad opcode sense received, flip -cpf flag to -pf, add page names for most peripheral types - sg_turs: default '-n=' argument to 1, only when '-n=1' print error message in full - sg_logs: print temperature "" for 255, '-t' switch for temperature (from either temperature or IE log page) - sg_dd: add '-odir=0|1' switch for O_DIRECT on block devices - sg_start: add '-imm', '-loej' and 'pc=' switches plus man page - sg_readcap: add '-pmi' and 'lba=' switches - open files O_NONBLOCK in sg_inq, sg_modes and sg_logs so they can be used on cd/dvd drivers when there is no disk present Changelog for sg3_utils-1.03 [20030402] [svn: 30] - sg_senddiag: added, allows self tests and listing of diag pages - sg_start: changed to use SG_IO so works on block devices - sg_err: print out some "sense key specific" data [Trent Piepho] - sg_modes: add "-6" switch for force 6 byte MODE SENSE [Trent Piepho] - sg_modes: more information on page codes and controls - sg_inq, sg_modes, sg_logs, sg_senddiag: add man pages - sg_dd: add "append=0|1" switch for glueing together large files - note in README about utilities offered by scsirastools package Changelog for sg3_utils-1.02 [20030101] [svn: 28] - sg_inq: check if cmddt or evpd bits ignored - sg_inq: warn -o= not used for standard INQUIRY - sg_turs: add -t option to time Test Unit Ready commands - sg_errs: (used by most utilities) warn if sense buffer empty - sg_modes: make safe with block SG_IO (bypass SG_GET_SCSI_ID ioctl) - sg_logs: make safe with block SG_IO, self-test page work - sg_dd: add "blksg_io=" switch to experiment with block SG_IO - sg_read: now use SG_IO ioctl rather than sg write/read - sginfo: fix writing parameters, check for block devices that answer sg's ioctls, recognize "scd" device names - sg_map: stop close error report on tape devices - sg_readcap: make safe with block SG_IO - sg_start: make safe with block SG_IO - sg_test_rwbuf: make safe with block SG_IO Changelog for sg3_utils-1.01 [20020814] [svn: 27] ---------------------------- - add raw switch ("-r") to sg_inq [Martin Schwenke] Changelog for sg3_utils-1.00 [20020728] [svn: 26] ---------------------------- - update sg_err [to SPC-3 T10/1416-D Rev 07 3 May 2002] - "sg_inq -cl" now outputs opcode names - add "continue on error" option to sg_dd - add _LARGEFILE64_SOURCE _FILE_OFFSET_BITS=64 defines to Makefile - drop 'gen' argument from sg_dd and friends, allow any file types except scsi tape device file names - treat of=/dev/null as special (skip write). Accept of=. as alias for of=/dev/null - decode various log pages in sg_logs - add 'dio' argument to sgm_dd for testing "zero copy" copies Changelog for sg3_utils-0.99 [20020317] ---------------------------- - add 'fua' and 'sync' arguments to sg_dd, sgp_dd and sgm_dd - improve sg_inq, add "-cl" and "-36" arguments - add sg_modes + sg_logs for MODE SENSE and LOG SENSE queries - add rescan-scsi-bus.sh [Kurt Garloff] to archive directory Changelog for sg3_utils-0.98 [20020216] ---------------------------- - move sg_reset back from archive to main directory + build - sprintf() to snprintf() changes - add "time=" argument to sg_dd, sgp_dd and sgm_dd to time transfer - add man pages for sgm_dd and sg_read, update sg_dd and sgp_dd man pages - add "cdbsz=" argument to sg_dd, sgp_dd, sgm_dd + sg_read - add "gen=0|1" argument to sg_dd Changelog for sg3_utils-0.97 [20011223] ---------------------------- - move isosize to archive since introduced into util-linux-2.10s Changelog for sg3_utils-0.96 [20011221] ---------------------------- - add '-p' switch to sg_inq to provide PCI slot_name - add '-n' switch to scsi_inquiry for non-blocking open - new sgm_dd (dd variant) using mmap-ed IO - sg_rbuf now has a '-m' argument to select mmap-ed IO - sg_rbuf now has a '-t' switch to do timing + throughput calculation - add sg_simple4 to demonstrate mmap-ed IO on an INQUIRY response - add sg_simple16 to do a READ_16 (16 byte SCSI READ command) - mmap-ed IO requires sg version 3.1.22 or later - add sg_read to read multiple times starting at same offset Changelog for sg3_utils-0.95 [20010915] ---------------------------- - make sg_dd, sgp_dd and archive/sgq_dd warn if dio selected but /proc/scsi/sg/allow_dio is '0' - sg_map can now do any INQUIRY (when '-i' argument given) - expand example in scsi_inquiry Changelog for sg3_utils-0.94 [20010419] ---------------------------- - add sg_start, documented in README.sg_start [Kurt Garloff] - add osst suport in sg_map [Kurt Garloff] - improvements to sginfo [Kurt Garloff] Changelog for sg3_utils-0.93 [20010415] ---------------------------- - more include file fine tuning - some "dio" work sg_rbuf - extend sgp_dd so "continue on error" works on normal files - introduce sg_include.h to encapsulate sg include problems - add scsi_devfs_scan - add sg_bus_xfer to archive directory - more error info in sginfo Changelog for sg3_utils-0.92 [20010116] ---------------------------- - change sg_err.c output from stdout to stderr - change sg_debug to call system("cat /proc/scsi/sg/debug"); - fix in+out totals in sg_dd and sgp_dd when partial transfers - lower include dependencies in sg_err.h - add sgq_dd + Makefile to archive directory Changelog for sg3_utils-0.91 [20001221] ---------------------------- - signalling handling added to sg_dd (and documented in sg_dd.8) - add man page for sg_rbuf (and a small change to its code) - add "-d" switch to isosize and cope with > 2 GB (and man page) Changelog for sg3_utils-0.90 ---------------------------- - switch from dated versioning. Previous version was sg3_utils001012. Arbitrarily start at package version 0.90 . Start Changelog. - incorporate Kurt Garloff's patches from Suse scsi.spm source rpm compilation: - add Kurt Garloff's sg_test_rwbuf utility to read and write to disk buffer - clean up Makefile to include a "make install" (and also add a "make uninstall"). - add "-uno" switch to sginfo - make raw and sg devices equally acceptable to sg_dd and sgp_dd. [Raw devices still not as fast as sg devices doing disk to disk copies in sgp_dd but this may be improved soon. Still faster than using dd!] - change lseek() in sg_dd and sgp_dd to _llseek() [using code borrowed from fdisk] so big disks can be properly offset with 'skip' and 'seek' arguments. [This change is significant for raw devices and normal files since sg devices already use 31 bit block addressing.] - rename sg_s3_inq to sg_inq. This utility allows the INQUIRY response to be decoded as per SCSI 3 and 4. Also can probe VPD and CmdDt pages. - change multiplier suffixes on sg_dd, sgp_dd and sg_turs so lower case "k, m, g" are powers of 2 while "K, M, G" are powers of 10. This idea borrowed from lmdd (lmbench suite) - retire a few more less used utilities into the archive directory. - add man pages for sg_dd, sgp_dd and sg_map sg3_utils-1.40/missing0000775000175000017500000001533012335161436013755 0ustar douggdougg#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # 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. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: sg3_utils-1.40/BSD_LICENSE0000664000175000017500000000275212200001501014030 0ustar douggdougg/* * Copyright (c) 1999-2013 Douglas Gilbert. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ sg3_utils-1.40/debian/0000755000175000017500000000000012431015530013562 5ustar douggdouggsg3_utils-1.40/debian/sg3-utils.install0000664000175000017500000000003710640352677017026 0ustar douggdouggusr/bin/* usr/share/man/man8/* sg3_utils-1.40/debian/docs0000664000175000017500000000010211356735137014451 0ustar douggdouggREADME README.sg_start AUTHORS COVERAGE CREDITS INSTALL ChangeLog sg3_utils-1.40/debian/rules0000775000175000017500000000405012144707462014660 0ustar douggdougg#!/usr/bin/make -f # Sample debian/rules that uses debhelper. # GNU copyright 1997 by Joey Hess. # # This version is for a hypothetical package that builds an # architecture-dependant package, as well as an architecture-independent # package. # Uncomment this to turn on verbose mode. # export DH_VERBOSE=1 DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS 2>/dev/null) configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --bindir=/usr/bin --prefix=/usr --mandir=\$${prefix}/share/man touch configure-stamp build: configure-stamp build-stamp build-stamp: dh_testdir # Add here commands to compile the package. PREFIX=/usr MANDIR=/usr/share/man $(MAKE) -e touch build-stamp clean: dh_testdir dh_testroot # Add here commands to clean up after the build process. -$(MAKE) distclean rm -f build-stamp configure-stamp debian/substvars dh_clean install: DH_OPTIONS= install: build dh_testdir dh_testroot dh_clean dh_installdirs # Add here commands to install the package into debian/tmp $(MAKE) -e install DESTDIR=$(CURDIR)/debian/tmp PREFIX=/usr dh_install --autodest --sourcedir=debian/tmp dh_installman # Build architecture-independent files here. # Pass -i to all debhelper commands in this target to reduce clutter. binary-indep: build install # nothing to do here # Build architecture-dependent files here. binary-arch: build install dh_testdir -a dh_testroot -a dh_installdocs -a dh_installexamples -a dh_installmenu -a dh_installchangelogs ChangeLog -a dh_strip -a dh_link -a dh_compress -a -X archive -X .c -X .h dh_fixperms -a dh_makeshlibs -V -v dh_installdeb -a ifeq ($(DEB_HOST_ARCH_OS),kfreebsd) echo kfreebsd:Depends=libcam-dev >>debian/libsgutils2-dev.substvars endif dh_shlibdeps -ldebian/tmp/usr/lib -L libsgutils2 dh_gencontrol -a dh_md5sums -a dh_builddeb -a binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure sg3_utils-1.40/debian/changelog0000664000175000017500000001611312430315266015450 0ustar douggdouggsg3-utils (1.40-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Mon, 10 Nov 2014 23:00:00 -0500 sg3-utils (1.39-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Thu, 12 Jun 2014 09:00:00 -0400 sg3-utils (1.38-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Tue, 01 Apr 2014 15:00:00 -0400 sg3-utils (1.37-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Mon, 14 Oct 2013 15:00:00 -0400 sg3-utils (1.36-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Fri, 31 May 2013 10:00:00 -0400 sg3-utils (1.35-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Thu, 17 Jan 2013 19:00:00 -0500 sg3-utils (1.34-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Sat, 13 Oct 2012 19:00:00 -0400 sg3-utils (1.33-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 18 Jan 2012 14:00:00 -0500 sg3-utils (1.32-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 22 Jun 2011 16:00:00 -0400 sg3-utils (1.31-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 16 Feb 2011 16:00:00 -0500 sg3-utils (1.30-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Fri, 05 Nov 2010 10:30:00 -0400 sg3-utils (1.29-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Wed, 31 Mar 2010 23:00:00 -0400 sg3-utils (1.28-0.1) unstable; urgency=low * New upstream version -- Douglas Gilbert Fri, 02 Oct 2009 00:20:00 -0400 sg3-utils (1.27-0.1) unstable; urgency=low [ Martin Pitt ] * Non-maintainer upload; this package blocks DeviceKit, and maintainer is apparently not active any more. Also clean up and modernize the package somewhat while we are at it. * New upstream release (required for current devicekit-disks). (Closes: #532546). Upstream original tarball repacked to not contain debian/ directory. * Rename libsgutils1{,-dev} to libsgutils2-2{,-dev}, upstream bumped SONAME. Also call the library libgsutils2-2 to match SONAME. Add Conflicts/Replaces for "libsgutils2" to provide a clean upgrade from the packages as provided by Upstream and Ubuntu. * debian/rules: Update build rules for upstream Makefile → autotools switch. * debian/rules: Fix cleaning a clean source package. * Demote Recommends to Suggests; the library doesn't actually call the binaries in sg3-utils. (Closes: #532547) * Drop debian/*.dirs, unnecessary with dh_install. * Drop sg3-utils.preinst, not necessary to deal with kernel 2.4 any more. * Drop libsgutils2-0.install, libsgutils2-0-dev.install, these packages don't exist. * Drop libsgutils2.post{inst,rm}: Basically empty, debhelper will create its own. * libsgutils2-dev.install: Drop *.lo. * debian/compat: 4 -> 7. Bump debhelper build-depends accordingly. * debian/control: Bump Standards-Version to 3.8.2. * debian/control: Modernize package description for Linux 2.6. (Closes: #506578) * debian/rules: Drop -k argument from dh_clean (thanks lintian). [ Frank Lichtenheld ] * debian/control, debian/rules: Add dependency of libsgutils-dev on libcam-dev on kfreebsd-*. (Closes: #519460) -- Martin Pitt Mon, 22 Jun 2009 12:04:20 +0200 sg3-utils (1.24-2) unstable; urgency=low * Cleaned up package description (Closes: #445920). * Don't make libtool think rpath is necessary (Closes: #451153) * Capitalized Linux in extended description (Closes: #457526). * Completed sentence in libsgutils1 long description (Closes: #421391). * Added patch from Aurelian Jarno to build on kfreebsd-* (Closes: #455430). * Symlinks in examples directory cleaned up (Closes: #372610). -- Eric Schwartz (Skif) Sun, 30 Dec 2007 11:52:58 -0700 sg3-utils (1.24-1) unstable; urgency=low * New upstream release * Conflicts with upstream libsgutils package libsgutils-1-0 (closes: #391077) -- Eric Schwartz (Skif) Tue, 5 Jun 2007 17:04:21 -0600 sg3-utils (1.21-2.1) unstable; urgency=medium * Non-maintainer upload. * Fix FTBFS due to old syscall usage (Closes: #395512). -- Luk Claes Sun, 5 Nov 2006 17:23:29 +0100 sg3-utils (1.21-2) unstable; urgency=low * Added Depends on libsgutils1 to libsgutils1-dev (closes: #387798) -- Eric Schwartz (Skif) Fri, 22 Sep 2006 00:20:28 -0600 sg3-utils (1.21-1) unstable; urgency=low * New upstream release -- Eric Schwartz (Skif) Wed, 13 Sep 2006 21:54:30 -0600 sg3-utils (1.20-1) unstable; urgency=low * New upstream release -- Eric Schwartz (Skif) Wed, 26 Apr 2006 22:31:15 -0600 sg3-utils (1.17-3) unstable; urgency=low * Cleaned up sg_read(8) manpage (Closes: #294521) -- Eric Schwartz (Skif) Mon, 13 Feb 2006 17:59:46 -0700 sg3-utils (1.17-2) unstable; urgency=low * Add libtool to build-depends -- Eric Schwartz (Skif) Tue, 4 Oct 2005 19:40:00 -0600 sg3-utils (1.17-1) unstable; urgency=low * New upstream version -- Eric Schwartz (Skif) Sat, 1 Oct 2005 13:26:16 -0600 sg3-utils (1.08-2) unstable; urgency=low * Fix packaging bug that accidentally left off binaries. Sigh. (closes: #271906) -- Eric Schwartz (Skif) Wed, 15 Sep 2004 22:40:06 -0600 sg3-utils (1.08-1) unstable; urgency=low * New upstream version * Unified package description with list of tools actually installed (closes: #271093) -- Eric Schwartz (Skif) Sun, 12 Sep 2004 21:22:42 -0600 sg3-utils (1.05-1) unstable; urgency=low * New upstream release * updated description to match tools in package (closes: #221143) -- Eric Schwartz Tue, 18 Nov 2003 22:22:29 -0700 sg3-utils (1.03-1) unstable; urgency=low * New upstream release (closes: #181999) -- Eric Schwartz Tue, 29 Apr 2003 20:18:30 -0600 sg3-utils (0.95-4) unstable; urgency=low * Only warns if installed on a kernel version < 2.4 (closes: #136434) -- Eric Schwartz Tue, 28 May 2002 22:55:29 -0600 sg3-utils (0.95-3) unstable; urgency=low * Extended description to include descriptions of all tools included in the package. (closes: #121968) -- Eric Schwartz Sun, 13 Jan 2002 17:09:27 -0700 sg3-utils (0.95-2) unstable; urgency=low * Packaging manpages (closes: #122692) * Conflicts with cdwrite (closes: #123779) -- Eric Schwartz Wed, 2 Jan 2002 01:05:08 -0700 sg3-utils (0.95-1) unstable; urgency=low * Initial Release. * Adjusted Makefile to include $DESTDIR -- Eric Schwartz Wed, 14 Nov 2001 17:05:56 -0700 sg3_utils-1.40/debian/libsgutils2-dev.install0000664000175000017500000000006711231667560020213 0ustar douggdouggusr/include/scsi usr/lib/*.so usr/lib/*.la usr/lib/*.a sg3_utils-1.40/debian/README.debian40000664000175000017500000000131011262403037015750 0ustar douggdouggFor whatever reason Debian build scripts (e.g. debhelper and dbclean) seem to have changed in such a way to be Debian 4.0 ("etch") unfriendly. So when the ./build_debian.sh script is called on a Debian 4.0 system, it fails saying the debhelper is too old. That can be fixed by editing the 'control' file, changing this line: Build-Depends: debhelper (>> 7), libtool, libcam-dev [kfreebsd-i386 kfreebsd-amd64] to: Build-Depends: debhelper, libtool, libcam-dev [kfreebsd-i386 kfreebsd-amd64] The script then dies in dbclean and the hack to get around that is to edit the 'compat' file. It contains "7" which needs to be changed to "4". Evidently "4" is deprecated and "5" is preferable and should work. sg3_utils-1.40/debian/copyright0000664000175000017500000000257511231667560015545 0ustar douggdouggThis package was debianized by Eric Schwartz on Wed, 14 Nov 2001 17:05:56 -0700. It was downloaded from Upstream Authors: Douglas Gilbert , Bruce Allen , Peter Allworth , James Bottomley , Lars Marowsky-Bree , Kurt Garloff , Grant Grundler , Christophe Varoqui , Michael Weller , Eric Youngdale , Copyright: This software is copyright(c) 1994-2009 by the authors You are free to distribute this software under the terms of the GNU General Public License. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL file. Many parts of this package are covered by the BSD license. These include central error processing code and common command code found in the lib subdirectory. Most newer utilities also use the BSD license. The author's intention is that this code can be used freely by others. On Debian systems and those derived from Debian, the complete text of the BSD License can be found in /usr/share/common-licenses/BSD. sg3_utils-1.40/debian/control0000664000175000017500000000313111232105010015154 0ustar douggdouggSource: sg3-utils Section: admin Priority: optional Maintainer: Eric Schwartz (Skif) Build-Depends: debhelper (>> 7), libtool, libcam-dev [kfreebsd-i386 kfreebsd-amd64] Standards-Version: 3.8.2 Package: sg3-utils Architecture: any Depends: ${shlibs:Depends} Conflicts: sg-utils, cdwrite Replaces: sg-utils Description: utilities for devices using the SCSI command set. Most OSes have SCSI pass-through interfaces that enable user space programs to send SCSI commands to a device and fetch the response. With SCSI to ATA Translation (SAT) many ATA disks now can process SCSI commands. Typically each utility in this package implements one SCSI command. See the draft standards at www.t10.org for SCSI command definitions plus SAT. ATA commands are defined in the draft standards at www.t13.org . For a mapping between supported SCSI and ATA commands and utility names in this package see the COVERAGE file. Package: libsgutils2-2 Section: libs Depends: ${shlibs:Depends} Architecture: any Conflicts: libsgutils2 Replaces: libsgutils2 Suggests: sg3-utils Description: utilities for devices using the SCSI command set (shared libraries) Shared library used by the utilities in the sg3-utils package. Package: libsgutils2-dev Section: libdevel Architecture: any Depends: libsgutils2-2 (= ${binary:Version}), ${shlibs:Depends}, ${kfreebsd:Depends} Conflicts: libsgutils1-dev Suggests: sg3-utils Description: utilities for devices using the SCSI command set (developer files) Developer files (i.e. headers and a static library) which are associated with the utilities in the sg3-utils package. sg3_utils-1.40/debian/libsgutils2-2.install0000664000175000017500000000001711231667560017571 0ustar douggdouggusr/lib/*.so.* sg3_utils-1.40/debian/compat0000664000175000017500000000000211504563063014773 0ustar douggdougg7 sg3_utils-1.40/debian/sg3-utils.examples0000664000175000017500000000002310671137042017160 0ustar douggdouggexamples/* archive sg3_utils-1.40/TODO0000664000175000017500000000026511170007606013041 0ustar douggdouggSome suggestions and shortcomings: - Win32 version of sg_scan doesn't work well in Vista. Rework scanning logic. Done 20090410 - support the SCSI UNMAP command [20090410] sg3_utils-1.40/COPYING0000664000175000017500000000272511765746727013437 0ustar douggdougg Upstream Authors: Douglas Gilbert , Bruce Allen , Peter Allworth , James Bottomley , Lars Marowsky-Bree , Kurt Garloff , Grant Grundler , Christophe Varoqui , Michael Weller , Eric Youngdale Copyright: This software is copyright(c) 1994-2012 by the authors Most of the code in this package is covered by a BSD license. On Debian systems, the complete text of the BSD License can be found in `/usr/share/common-licenses/BSD'. All the code in the library (usually called libsgutils) is covered by a BSD license. Some of the older utilities are covered by the GPL. More precisely: You are free to distribute this software under the terms of the GNU General Public License either version 2, or (at your option) any later version. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL-2 file. The later GPL-3 is found in /usr/share/common-licenses/GPL-3 file but no code in this package refers to that license. Douglas Gilbert 10th April 2012 sg3_utils-1.40/README.win320000664000175000017500000002304612412306433014174 0ustar douggdouggIntroduction ============ The win32 port of sg3_utils contains those utilities that are _not_ specific to Linux. One utility for listing available devices, sg_scan, has a Windows-specific version for this port. The dd variants from the sg3_utils package (e.g. sg_dd) rely on too many Linux idiosyncrasies to be easily ported. A new package called 'ddpt' contains a utility with similar functionality to sg_dd and is available for Windows. The Windows port uses the Microsoft SCSI Pass Through (SPT) interface. It has two variants: "SPT" where data is double buffered; and "SPTD" where data pointers to the user space are passed to the OS. Only Windows 2000 and later (i.e. not 95, 98 or ME) support SPT. Two build environments are catered for: cygwin (see www.cygwin.com) and MinGW ("Minimalist GNU for Windows", see www.mingw.org). Both are based in the gcc compiler (although other C compilers should have little problem with the source code). Cygwin is a more sophisticated, commercial product that results in executables that depend on cygwin1.dll . No licensing is required since sg3_utils is open source (with either BSD or GPL licenses) but users will need to fetch that dll. On the other hand MinGW (and its companion MSYS shell) builds freestanding console executables. The Unix library support is not as advanced with MinGW which has led to some timing functions being compiled out when sg3_utils is built for MinGW. In later versions of Windows these utilities may need to be "run as Administrator" for disks and other devices to be seen. If not those devices will simply not be found as calls to query them fail with access permission problems. Supported Utilities =================== Here is a list of utilities that have been ported: sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident sg_inq [dropped ATA IDENTIFY DEVICE capability] sg_logs sg_luns sg_modes sg_persist sg_opcodes sg_prevent sg_raw sg_rdac sg_read_block_limits sg_read_buffer sg_read_long sg_readcap sg_reassign sg_referrals sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_scan [this is Windows specific] sg_senddiag sg_ses sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same Most utility names are indicative of the main SCSI command that they execute. Some utilities are slightly higher level, for example sg_ses fetches SCSI Enclosure Services (SES) status pages and can send control pages. Each utility has a man page (placed in section 8). There is summary of the mapping between utility names and the SCSI commands they execute in the COVERAGE file. An overview of sg3_utils can be found at: http://sg.danny.cz/sg/sg3_utils.html . A copy of the "sg3_utils.html" file is in the "doc" subdirectory. Some man pages have examples which use Linux device names which hopefully will not confuse Windows users. Two pass-through variants ========================= The sg_pt_win32.c file uses the Windows SCSI Pass Through interface. That is often shortened to SPT or SPTI. There are two DeviceIoControl() ioctl variants provided: IOCTL_SCSI_PASS_THROUGH and IOCTL_SCSI_PASS_THROUGH_DIRECT. The former involves double handling of data (and perhaps an upper limit on the data length associated with one SCSI command; MS documentation mentions 16 KB). The "direct" variant passes a pointer from the user space and to be faster looks and more versatile. However the "direct" variant has potentially (unquantified) alignment requirements and may not be (well) implemented by the hardware driver. In practice some users have reported errors (e.g. 1117: a non-descript IO error) when the direct variant is used. Hence the non-direct variant is the default. The default size limit on the data buffer is set at 16 KB but if the user asks for more the data buffer will be extended. The OS or the hardware drivers may reject the extended data buffer but we tried. The package can be built using the direct variant with: ./configure --enable-win32-spt-direct rather than: ./configure prior to the 'make' call. In sg3_utils version 1.31 run-time selection of the direct or indirect interface was added with the scsi_pt_win32_direct(int state_direct) function declared in sg_pt.h. The default is indirect unless './configure --enable-win32-spt-direct' was used in the build. If 'state_direct' is 1 then the direct interface is used and if it is 0 the indirect interface is used. Both sg_read_buffer and sg_write_buffer can transfer buffers larger than 16 KB. So in sg3_utils version 1.31, they use this new function to set direct interface mode. This is regardless of whether or not "--enable-win32-spt-direct" is given to ./configure . Details ======= Most of the ported utilities listed above use SCSI command functions declared in sg_cmds_*.h headers . Those SCSI command functions are implemented in the corresponding ".c" files. The ".c" files pass SCSI commands to the host operating system via an interface declared in sg_pt.h . There are currently five implementations of that interface depending on the host operating system: - sg_pt_linux.c - sg_pt_freebsd.c - sg_pt_osf1.c [Tru64] - sg_pt_solaris.c - sg_pt_win32.c The ASPI32 interface which requires a dll from Adaptec is not supported. The sg_scan utility is a special version for Windows and it attempts to show the various available storage device names, one per line. Here is an example of sg_scan's output: # sg_scan PD0 [C] FUJITSU MHY2160BH 0000 PD1 [DF] WD 2500BEV External 1.05 WD-WXE90 CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 Here is an example with added bus type: # sg_scan -b PD0 [C] FUJITSU MHY2160BH 0000 PD1 [DF] WD 2500BEV External 1.05 WD-WXE90 CDROM0 [E] MATSHITA DVD/CDRW UJDA775 CB03 Here is an example with added SCSI adapter scan: # sg_scan -b -s PD0 [C] ST380011A 8.01 PD1 SEAGATE ST373455SS 2189 PD2 ATA ST3160812AS D PD3 SEAGATE ST336754SS 0003 CDROM0 [F] HL-DT-ST DVDRAM GSA-4163B A103 TAPE0 SONY SDT-7000 0192 SCSI0:0,0,0 claimed=1 pdt=0h dubious ST380011 A 8.01 SCSI1:0,0,0 claimed=1 pdt=5h HL-DT-ST DVDRAM GSA-4163B A103 SCSI2:0,6,0 claimed=1 pdt=1h SONY SDT-7000 0192 SCSI5:0,17,0 claimed=1 pdt=0h SEAGATE ST373455SS 2189 SCSI5:0,19,0 claimed=1 pdt=0h ATA ST3160812AS D SCSI5:0,21,0 claimed=1 pdt=0h SEAGATE ST336754SS 0003 SCSI5:0,112,0 claimed=0 pdt=10h LSI PSEUDO DEVICE 2.34 The storage devices scanned are PhysicalDrive (shortened form PD used), CDROM (which includes DVD and BD drives) and TAPE. There is also an optional SCSI adapter scan with device names of the form SCSI::: . These only come into play for devices that are not claimed by one of the storage class drivers. The "LSI PSEUDO DEVICE" device above is an example of an unclaimed device. The SCSI adapter scan does not show USB and IEEE 1394 connected devices. Volume names (e.g. "C:") that match a storage device (or perhaps a partition within that device) are shown in brackets. Notice there can be zero, one or more volume names for each storage device. Up to four volume names are listed in brackets, if there are more a "+" is added after the fourth. Several utilities have conditional compilation sections based on the SG_LIB_MINGW define. For those who want to try native C compilers on Windows setting the SG_LIB_MINGW define may help. Build environments ================== This package uses autotools infrastructure with the now common "./configure ; make ; make install" sequence needed to build and install from the source found in the tarball. Two Windows environments for building Unix code are supported: cygwin and MinGW. If the "./configure" sequence fails try using the ./autogen.sh prior to that sequence. The executables produced are console applications that can be executed in either a cygwin, MSYS or "cmd" shell. Various build options are available by giving command line options to "./configure", see the INSTALL file for generic information about the build infrastructure. MinGW can be used to cross built on some Redhat (Linux) platforms. After loading the cross build packages, the ./configure call in the normal autotools sequence should be replaced by either mingw32-configure or mingw64-configure. These scripts will set up the environment for the cross build and then call ./configure (so this invocation should be made in the top level of the untarred source). Options given to either script (e.g. --enable-win32-spt-direct) will be passed through to ./configure . Binary and Text files ===================== A problem has been reported with binary output being written in a MinGW environment (or executables build by MinGW). Windows has a concept of text and binary files which is not found in Unix. Recent versions of MinGW default to opening files in text mode. This can lead to binary output (such as when the '--raw' option is given) having 0xa (i.e. LF) translated to 0xd,0xa (i.e. CR,LF). sg3_utils version 1.26 attempts to fix this problem by changing what it knows to be binary output files to "binary mode" with the setmode() Windows command. Douglas Gilbert 24th September 2014 sg3_utils-1.40/config.h.in0000664000175000017500000000536312227043041014375 0ustar douggdougg/* config.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the `getopt_long' function. */ #undef HAVE_GETOPT_LONG /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_BSG_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_KDEV_T_H /* Define to 1 if you have the header file. */ #undef HAVE_LINUX_TYPES_H /* Define to 1 if you have the `lseek64' function. */ #undef HAVE_LSEEK64 /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `posix_fadvise' function. */ #undef HAVE_POSIX_FADVISE /* Define to 1 if you have the `posix_memalign' function. */ #undef HAVE_POSIX_MEMALIGN /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the `sysconf' function. */ #undef HAVE_SYSCONF /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* ignore linux bsg */ #undef IGNORE_LINUX_BSG /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* sg3_utils Build Host */ #undef SG_LIB_BUILD_HOST /* sg3_utils on FreeBSD */ #undef SG_LIB_FREEBSD /* assume sg3_utils on linux */ #undef SG_LIB_LINUX /* also MinGW environment */ #undef SG_LIB_MINGW /* sg3_utils on Tru64 UNIX */ #undef SG_LIB_OSF1 /* sg3_utils on Solaris */ #undef SG_LIB_SOLARIS /* sg3_utils on Win32 */ #undef SG_LIB_WIN32 /* full SCSI sense strings */ #undef SG_SCSI_STRINGS /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION /* enable Win32 SPT Direct */ #undef WIN32_SPT_DIRECT sg3_utils-1.40/AUTHORS0000664000175000017500000000016210646015765013431 0ustar douggdouggDouglas Gilbert See the CREDITS file for the names of those who have contributed. sg3_utils-1.40/compile0000775000175000017500000001624512335161436013742 0ustar douggdougg#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # 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. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: sg3_utils-1.40/utils/0000755000175000017500000000000012431015530013500 5ustar douggdouggsg3_utils-1.40/utils/Makefile0000664000175000017500000000243712404735305015161 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/share/man CC = gcc LD = gcc EXECS = hxascdmp EXTRA_EXECS = hxascdmp sg_chk_asc tst_sg_lib MAN_PGS = hxascdmp.1 MAN_PREF = man1 CFLAGS = -g -O2 -W -Wall -iquote ../include # CFLAGS = -g -O2 -W -iquote ../include -pedantic -std=c99 LDFLAGS = all: $(EXECS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXTRA_EXECS) core .depend hxascdmp: hxascdmp.o $(LD) -o $@ $(LDFLAGS) $^ # building sg_chk_asc depends on a prior successful make in ../lib sg_chk_asc: sg_chk_asc.o ../lib/sg_lib.o ../lib/sg_lib_data.o $(LD) -o $@ $(LDFLAGS) $^ tst_sg_lib: tst_sg_lib.o ../lib/sg_lib.o ../lib/sg_lib_data.o $(LD) -o $@ $(LDFLAGS) $^ install: $(EXECS) install -d $(INSTDIR) for name in $^; \ do install -s -o root -g root -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -o root -g root -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done ifeq (.depend,$(wildcard .depend)) include .depend endif sg3_utils-1.40/utils/README0000664000175000017500000000264111715321645014400 0ustar douggdouggThis directory contains these utilities: - hxascdmp: takes a binary stream and converts it to hexadecimal ASCII which is sent to stdout. The incoming binary stream can either be from a file or, in the absence of a file name, from stdin. Similar to the Unix "od" command. By default, it decodes 16 bytes per line with an ASCII interpretation to the right of each line. See its hxascdmp(1) man page. - sg_chk_asc: utility decodes the SCSI additional sense code table found at http://www.t10.org/lists/asc-num.txt and checks it against the table found in sg_lib_data.c in the lib/ subdirectory. It is designed to keep the table in sg_lib_data.c in "sync" with the table at the t10.org web site. By default, the Makefile only builds the hxascdmp utility. The 'Makefile' file (i.e. with no suffix) builds for Linux; the 'Makefile.freebsd' file builds for FreeBSD (e.g. 'make -f Makefile.freebsd'); the 'Makefile.solaris' file builds for Solaris; the 'Makefile.mingw' builds in the Windows MinGW environment (e.g. msys shell); and 'Makefile.cygwin' builds in the Windows Cygwin environment. To build sg_chk_asc the sg_lib.o and sg_lib_data.o files must be present (i.e. compiled) in the lib/ subdirectory. One way to meet that requirement is to execute './configure' in the main directory then 'cd lib ; make '. Then return to this directory and do 'make sg_chk_asc'. Douglas Gilbert 30th March 2010 sg3_utils-1.40/utils/hxascdmp.c0000664000175000017500000002133412277337476015510 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #define DEF_BYTES_PER_LINE 16 static int bytes_per_line = DEF_BYTES_PER_LINE; static const char * version_str = "1.14 20140213"; #define CHARS_PER_HEX_BYTE 3 #define BINARY_START_COL 6 #define MAX_LINE_LENGTH 257 #ifdef SG_LIB_MINGW /* Non Unix OSes distinguish between text and binary files. Set text mode on fd. Does nothing in Unix. Returns negative number on failure. */ int sg_set_text_mode(int fd) { return setmode(fd, O_TEXT); } /* Set binary mode on fd. Does nothing in Unix. Returns negative number on failure. */ int sg_set_binary_mode(int fd) { return setmode(fd, O_BINARY); } #else /* For Unix the following functions are dummies. */ int sg_set_text_mode(int fd) { return fd; /* fd should be >= 0 */ } int sg_set_binary_mode(int fd) { return fd; } #endif /* Returns the number of times 'ch' is found in string 's' given the * string's length. */ static int num_chs_in_str(const char * s, int slen, int ch) { int res = 0; while (--slen >= 0) { if (ch == s[slen]) ++res; } return res; } static void dStrHex(const char* str, int len, long start, int noAddr) { const char* p = str; unsigned char c; char buff[MAX_LINE_LENGTH]; long a = start; int bpstart, cpstart; int j, k, line_length, nl, cpos, bpos, midline_space; if (noAddr) { bpstart = 0; cpstart = ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; } else { bpstart = BINARY_START_COL; cpstart = BINARY_START_COL + ((CHARS_PER_HEX_BYTE * bytes_per_line) + 1) + 5; } cpos = cpstart; bpos = bpstart; midline_space = ((bytes_per_line + 1) / 2); if (len <= 0) return; line_length = BINARY_START_COL + (bytes_per_line * (1 + CHARS_PER_HEX_BYTE)) + 7; if (line_length >= MAX_LINE_LENGTH) { fprintf(stderr, "bytes_per_line causes maximum line length of %d " "to be exceeded\n", MAX_LINE_LENGTH); return; } memset(buff, ' ', line_length); buff[line_length] = '\0'; if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } for(j = 0; j < len; j++) { nl = (0 == (j % bytes_per_line)); if ((j > 0) && nl) { printf("%s\n", buff); bpos = bpstart; cpos = cpstart; a += bytes_per_line; memset(buff,' ', line_length); if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } } c = *p++; bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) bpos++; sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; if ((c < ' ') || (c >= 0x7f)) c='.'; buff[cpos++] = c; } if (cpos > cpstart) printf("%s\n", buff); } static void dStrHexOnly(const char* str, int len, long start, int noAddr) { const char* p = str; unsigned char c; char buff[MAX_LINE_LENGTH]; long a = start; int bpstart, bpos, nl; int midline_space = ((bytes_per_line + 1) / 2); int j, k, line_length; if (len <= 0) return; bpstart = (noAddr ? 0 : BINARY_START_COL); bpos = bpstart; line_length = (noAddr ? 0 : BINARY_START_COL) + (bytes_per_line * CHARS_PER_HEX_BYTE) + 4; if (line_length >= MAX_LINE_LENGTH) { fprintf(stderr, "bytes_per_line causes maximum line length of %d " "to be exceeded\n", MAX_LINE_LENGTH); return; } memset(buff, ' ', line_length); buff[line_length] = '\0'; if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } for(j = 0; j < len; j++) { nl = (0 == (j % bytes_per_line)); if ((j > 0) && nl) { printf("%s\n", buff); bpos = bpstart; a += bytes_per_line; memset(buff,' ', line_length); if (0 == noAddr) { k = sprintf(buff + 1, "%.2lx", a); buff[k + 1] = ' '; } } c = *p++; bpos += (nl && noAddr) ? 0 : CHARS_PER_HEX_BYTE; if ((bytes_per_line > 4) && ((j % bytes_per_line) == midline_space)) bpos++; sprintf(&buff[bpos], "%.2x", (int)(unsigned char)c); buff[bpos + 2] = ' '; } if (bpos > bpstart) printf("%s\n", buff); } static void usage() { fprintf(stderr, "Usage: hxascdmp [-b=] [-h] [-H] [-N] [-V] [-?] " "[+]\n"); fprintf(stderr, " where:\n"); fprintf(stderr, " -b= bytes per line to display " "(def: 16)\n"); fprintf(stderr, " -h print this usage message\n"); fprintf(stderr, " -H print hex only (i.e. no ASCII " "to right)\n"); fprintf(stderr, " -N no address, start in first column\n"); fprintf(stderr, " -V print version string then exits\n"); fprintf(stderr, " -? print this usage message\n"); fprintf(stderr, " + reads file(s) and outputs each " "as hex ASCII\n"); fprintf(stderr, " if no then reads stdin\n\n"); fprintf(stderr, "Sends hex ASCII dump of stdin/file to stdout\n"); } int main(int argc, const char ** argv) { char buff[8192]; int num = 8192; long start = 0; int res, k, u, len, n; int inFile = STDIN_FILENO; int doHelp = 0; int doHex = 0; int noAddr = 0; int doVersion = 0; int hasFilename = 0; int ret = 0; const char * cp; for (k = 1; k < argc; k++) { cp = argv[k]; len = strlen(cp); if (0 == strncmp("-b=", cp, 3)) { res = sscanf(cp + 3, "%d", &u); if ((1 != res) || (u < 1)) { fprintf(stderr, "Bad value after '-b=' option\n"); usage(); return 1; } bytes_per_line = u; } else if ((len > 1) && ('-' == cp[0]) && ('-' != cp[1])) { res = 0; n = num_chs_in_str(cp + 1, len - 1, 'h'); doHelp += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'H'); doHex += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'N'); noAddr += n; res += n; n = num_chs_in_str(cp + 1, len - 1, 'V'); doVersion += n; res += n; n = num_chs_in_str(cp + 1, len - 1, '?'); doHelp += n; res += n; if (0 == res) { fprintf(stderr, "No option recognized in str: %s\n", cp); usage(); return 1; } } else if (0 == strcmp("-?", argv[k])) ++doHelp; else if (*argv[k] == '-') { fprintf(stderr, "unknown switch: %s\n", argv[k]); usage(); return 1; } else { hasFilename = 1; break; } } if (doVersion) { printf("%s\n", version_str); return 0; } if (doHelp) { usage(); return 0; } /* Make sure num to fetch is integral multiple of bytes_per_line */ if (0 != (num % bytes_per_line)) num = (num / bytes_per_line) * bytes_per_line; if (hasFilename) { for ( ; k < argc; k++) { inFile = open(argv[k], O_RDONLY); if (inFile < 0) { fprintf(stderr, "Couldn't open file: %s\n", argv[k]); ret = 1; } else { sg_set_binary_mode(inFile); start = 0; if (! doHex) printf("ASCII hex dump of file: %s\n", argv[k]); while ((res = read(inFile, buff, num)) > 0) { if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } close(inFile); } } else { sg_set_binary_mode(inFile); while ((res = read(inFile, buff, num)) > 0) { if (doHex) dStrHexOnly(buff, res, start, noAddr); else dStrHex(buff, res, start, noAddr); start += (long)res; } } return ret; } sg3_utils-1.40/utils/tst_sg_lib.c0000664000175000017500000002100712357543201016007 0ustar douggdougg/* * Copyright (c) 2013-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include "sg_lib.h" /* A utility program to test sg_libs string handling, specifically * related to snprintf(). * */ static char * version_str = "1.01 20140427"; #define MAX_LINE_LEN 1024 static struct option long_options[] = { {"dtsrhex", 0, 0, 'd'}, {"help", 0, 0, 'h'}, {"printf", 0, 0, 'p'}, {"sense", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; const unsigned char desc_sense_data1[] = { /* unrec_err, excessive_writes, sdat_ovfl, additional_len=? */ 0x72, 0x1, 0x3, 0x2, 0x80, 0x0, 0x0, 12+12+8+4+8+4+28, /* Information: 0x11223344556677bb */ 0x0, 0xa, 0x80, 0x0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0xbb, /* command specific: 0x3344556677bbccff */ 0x1, 0xa, 0x0, 0x0, 0x33, 0x44, 0x55, 0x66, 0x77, 0xbb, 0xcc, 0xff, /* sense key specific: SKSV=1, actual_count=257 (hex: 0x101) */ 0x2, 0x6, 0x0, 0x0, 0x80, 0x1, 0x1, 0x0, /* field replaceable code=0x45 */ 0x3, 0x2, 0x0, 0x45, /* another progress report indicator */ 0xa, 0x6, 0x2, 0x1, 0x2, 0x0, 0x32, 0x01, /* incorrect length indicator (ILI) */ 0x5, 0x2, 0x0, 0x20, /* user data degment referral */ 0xb, 26, 0x1, 0x0, 0,0,0,1, 0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8, 0x1,0x2,0x3,0x4,0x55,0x6,0x7,0x8, 2,0,0x12,0x34, }; const unsigned char desc_sense_data2[] = { /* ill_req, inv fld in para list, additional_len=? */ 0x72, 0x5, 0x26, 0x0, 0x0, 0x0, 0x0, 8+4, /* sense key specific: SKSV=1, C/D*=0, bitp=7 bytep=34 */ 0x2, 0x6, 0x0, 0x0, 0x8f, 0x0, 0x34, 0x0, /* field replaceable code=0x45 */ 0x3, 0x2, 0x0, 0x45, }; static void usage() { fprintf(stderr, "Usage: " "tst_sg_lib [--dstrhex] [--help] [--printf] [--sense] " "[--verbose]\n" " [--version]\n" " where: --dstrhex|-d test dStrHex* variants\n" " --help|-h print out usage message\n" " --printf|-p test library printf variants\n" " --sense|-s test sense data handling\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Test various parts of sg_lib, see options\n" ); } /* Want safe, 'n += snprintf(b + n ...)' like function. If cp_max_len is 1 * then assume cp is pointing to a null char and do nothing. Returns number * number of chars placed in cp excluding the trailing null char. So for * cp_max_len > 0 the return value is always < cp_max_len; for cp_max_len * <= 0 the return value is 0 (and no chars are written to cp). */ static int my_snprintf(char * cp, int cp_max_len, const char * fmt, ...) { va_list args; int n; if (cp_max_len < 2) return 0; va_start(args, fmt); n = vsnprintf(cp, cp_max_len, fmt, args); va_end(args); return (n < cp_max_len) ? n : (cp_max_len - 1); } int main(int argc, char * argv[]) { int k, c, n, len; int do_dstrhex = 0; int do_printf = 0; int do_sense = 0; int did_something = 0; int verbose = 0; int ret = 0; char b[2048]; char bb[128]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "dhpsvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': ++do_dstrhex; break; case 'h': case '?': usage(); return 0; case 'p': ++do_printf; break; case 's': ++do_sense; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised switch code 0x%x ??\n", c); usage(); return 1; } } if (optind < argc) { if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return 1; } } if (do_sense ) { ++did_something; sg_print_sense("desc_sense_data test1", desc_sense_data1, (int)sizeof(desc_sense_data1), 1); printf("\n"); #if 1 sg_get_sense_str("sg_get_sense_str(ds_data1)", desc_sense_data1, sizeof(desc_sense_data1), 1, sizeof(b), b); printf("sg_get_sense_str: strlen(b)->%zd\n", strlen(b)); printf("%s", b); printf("\n"); #endif sg_print_sense("desc_sense_data test2", desc_sense_data2, (int)sizeof(desc_sense_data2), 1); printf("\n"); } if (do_printf) { ++did_something; printf("Testing my_snprintf():\n"); b[0] = '\0'; len = sizeof(b); n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = -1; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 0; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 1; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 2; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 3; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 4; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 5; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 6; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); b[0] = '\0'; len = 7; n = my_snprintf(b, len, "%s", "test"); printf("my_snprintf(,%d,,\"test\") -> %d; strlen(b) -> %zd\n", len, n, strlen(b)); if (strlen(b) > 0) printf("Resulting string: %s\n", b); } if (do_dstrhex) { char b[] = {0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58}; ++did_something; for (k = 0; k < 18; ++k) { printf("k=%d:\n", k); dStrHex(b, k, 0); dStrHex(b, k, 1); dStrHex(b, k, -1); dStrHexStr(b, k, "dStrHexStr:^", 0, sizeof(bb), bb); printf("%s", bb); printf("\n"); } } if (0 == did_something) printf("Looks like no tests done, check usage with '-h'\n"); return ret; } sg3_utils-1.40/utils/Makefile.solaris0000664000175000017500000000166211030022612016613 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = gcc LD = gcc EXECS = hxascdmp # EXECS = hxascdmp sg_chk_asc MAN_PGS = MAN_PREF = man8 CFLAGS = -g -O2 -W # CFLAGS = -g -O2 -W -pedantic -std=c99 LDFLAGS = all: $(EXECS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) core .depend hxascdmp: hxascdmp.o $(LD) -o $@ $(LDFLAGS) $@.o sg_chk_asc: sg_chk_asc.o ../sg_lib.o $(LD) -o $@ $(LDFLAGS) $@.o ../sg_lib.o install: $(EXECS) install -d $(INSTDIR) for name in $(EXECS); \ do install -s -f $(INSTDIR) $$name; \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -m 644 -f $(MANDIR)/$(MAN_PREF) $$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done sg3_utils-1.40/utils/sg_chk_asc.c0000664000175000017500000001300112061626602015734 0ustar douggdougg/* * Copyright (c) 2006-2012 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include "sg_lib.h" /* A utility program for the Linux OS SCSI subsystem. * * This program takes a asc_ascq.txt file from www.t10.org and * checks it against the additional sense codes held in the * sg_lib.c file. * The online version of the asc_ascq codes can be found at: * http://www.t10.org/lists/asc-num.txt */ static char * version_str = "1.04 20120920"; #define MAX_LINE_LEN 1024 static struct option long_options[] = { {"help", 0, 0, 'h'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_chk_asc [--help] [--verbose] [--version] \n" " where: --help|-h print out usage message\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Checks asc/ascq codes in against the sg3_utils " "library.\nThe additional sense code (asc_ascq) can be found at\n" "www.t10.org/lists/asc-num.txt .\n" ); } int main(int argc, char * argv[]) { int k, j, res, c, num, len, asc, ascq; FILE * fp; int verbose = 0; char file_name[256]; char line[MAX_LINE_LEN]; char b[MAX_LINE_LEN]; char bb[MAX_LINE_LEN]; char * cp; int ret = 1; memset(file_name, 0, sizeof file_name); memset(line, 0, sizeof file_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "hvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised switch code 0x%x ??\n", c); usage(); return 1; } } if (optind < argc) { if ('\0' == file_name[0]) { strncpy(file_name, argv[optind], sizeof(file_name) - 1); file_name[sizeof(file_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return 1; } } if (0 == file_name[0]) { fprintf(stderr, "missing file name!\n"); usage(); return 1; } fp = fopen(file_name, "r"); if (NULL == fp) { fprintf(stderr, "open error: %s: %s\n", file_name, safe_strerror(errno)); return 1; } for (k = 0; (cp = fgets(line, sizeof(line) - 1, fp)); ++k) { len = strlen(line); if (len < 1) continue; if (! isdigit(line[0])) continue; num = sscanf(line, "%xh/%xh", &asc, &ascq); if (1 == num) ascq = -1; if (num < 1) { if (verbose) fprintf(stderr, "Badly formed line number %d (num=%d)\n", k + 1, num); continue; } if (len < 26) continue; #if 0 strncpy(b , line, sizeof(b) - 1); b[sizeof(b) - 1] = '\0'; num = strlen(b); if (0xd == b[num - 2]) { b[num - 2] = '\0'; b[num - 1] = '\0'; } printf("\"%s\",\n", b); #endif strncpy(b , line + 25, sizeof(b) - 1); b[sizeof(b) - 1] = '\0'; num = strlen(b); if (0xd == b[num - 2]) { b[num - 2] = '\0'; b[num - 1] = '\0'; } num = strlen(b); for (j = 0; j < num; ++j) b[j] = toupper(b[j]); bb[0] = '\0'; if (ascq >= 0) { cp = sg_get_asc_ascq_str(asc, ascq, sizeof(bb) - 1, bb); if (NULL == cp) { fprintf(stderr, "no entry for %x,%x : %s\n", asc, ascq, b); continue; } num = strlen(cp); // fprintf(stderr, "file: asc=%x acsq=%x strlen=%d %s\n", asc, ascq, num, // cp); // if (num < 20) // continue; if ((num > 6) && ((0 == memcmp("ASC", cp, 3)) || (0 == memcmp("vendor", cp, 6)))) { fprintf(stderr, "%x,%x differ, ref: %s, sg_lib_data: " "\n", asc, ascq, b); continue; } if (num > 20) { cp += 18; num -= 18; for (j = 0; j < num; ++j) cp[j] = toupper(cp[j]); } if (0 != strcmp(b, cp)) fprintf(stderr, "%x,%x differ, ref: %s, sg_lib_data: " "%s\n", asc, ascq, b, cp); } } if (NULL == cp) { if (feof(fp)) { if (verbose > 2) fprintf(stderr, "EOF detected\n"); } else fprintf(stderr, "fgets: %s\n", safe_strerror(errno)); } else fprintf(stderr, "%s\n", line); res = fclose(fp); if (EOF == res) { fprintf(stderr, "close error: %s\n", safe_strerror(errno)); return 1; } return ret; } sg3_utils-1.40/utils/hxascdmp.10000664000175000017500000000674412277337476015436 0ustar douggdougg.TH HXASCDMP "1" "February 2014" "sg3_utils\-1.38" SG3_UTILS .SH NAME hxascdmp \- hexadecimal ASCII dump .SH SYNOPSIS .B hxascdmp [\fI\-b=BPL\fR] [\fI\-h\fR] [\fI\-H\fR] [\fI\-N\fR] [\fI\-V\fR] [\fIFILE+\fR] .SH DESCRIPTION .\" Add any additional description here .PP This utility reads one or more \fIFILE\fR names and dumps them in hexadecimal and ASCII to stdout. If no \fIFILE\fR is given then stdin is read instead; reading continues (or stalls) until an EOF is received. .PP The default format is to start each line with the hexadecimal address (offset from the start of file) followed by 16 hexadecimal bytes separated by a single space (apart from the 8th and 9th bytes which are separated by two spaces). If the \fI\-H\fR is not given, there is then a string of 16 ASCII characters corresponding to the hexadecimal bytes earlier in the line; only bytes in the range 0x20 to 0x7e are printed in ASCII, other bytes values are printed as '.' . If the \fI\-H\fR is not given, each \fIFILE\fR name that appears on the command line is printed on a separate line prior to that file's hexadecimal ASCII dump. .PP If the \fI\-N\fR option is given then no address is printed out and each line starts with the next hexadecimal byte. .PP This utility is pretty close to the 'hexdump -C' variant of BSD's .B hexdump(1) command. .SH OPTIONS .TP \fB\-b\fR=\fIBPL\fR where \fIBPL\fR specifies the number of bytes per line. The default value is 16. 16 bytes per line is just enough to allow the address, 16 bytes in hexadecimal followed by 16 bytes as ASCII to fit on a standard 80 column wide terminal. .TP \fB\-h\fR output the usage message then exit. .TP \fB\-H\fR output hexadecimal only (i.e. don't place an ASCII representation at the end of each line). .TP \fB\-N\fR no address; so each line starts with the next hexadecimal byte. .TP \fB\-V\fR, \fB\-\-version\fR print the version string and then exit. .SH NOTES In Windows the given file (or files) are set to binary mode. .SH EXIT STATUS The exit status of hxascdmp is 0 when it is successful. If any of the given \fIFILE\fR names cannot be opened then the exit status is 1. .SH EXAMPLES First we manufacture a short file with a mix of data in it: mostly ASCII with some control characters and 0xaa (which the echo command only accepts in octal (0252): .PP $ echo -e "three blind mice,\t\r\0252" > 3bm.txt .PP Now we use this utility to see exactly what is in the file. To avoid problems with line wrapping, the bytes per line option is set to 8: .PP $ hxascdmp -b=8 3bm.txt .br ASCII hex dump of file: 3bm.txt .br 00 74 68 72 65 65 20 62 6c three bl .br 08 69 6e 64 20 6d 69 63 65 ind mice .br 10 2c 09 0d aa 0a ,.... .PP Using the same file, use this utility to output only hexadecimal formatted 16 bytes per line. .PP $ hxascdmp -H 3bm.txt .br hex dump of file: 3bm.txt .br 00 74 68 72 65 65 20 62 6c 69 6e 64 20 6d 69 63 65 .br 10 2c 09 0d aa 0a .PP For comparison the hexdump utility gives similar output: .PP $ hexdump -C 3bm.txt .br 00000000 74 68 72 65 65 20 62 6c 69 6e 64 20 6d 69 63 65 |three blind mice| .br 00000010 2c 09 0d aa 0a |,....| .br 00000015 .SH AUTHORS Written by Douglas Gilbert. .SH "REPORTING BUGS" Report bugs to . .SH COPYRIGHT Copyright \(co 2004\-2014 Douglas Gilbert .br This software is distributed under a FreeBSD license. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .SH "SEE ALSO" .B hexdump(1) sg3_utils-1.40/utils/Makefile.cygwin0000664000175000017500000000112611355017121016443 0ustar douggdougg# Assumes Makefile is used in a cygwin shell SHELL = /bin/sh CC = gcc LD = gcc EXECS = hxascdmp EXE_S = hxascdmp.exe # OS_FLAGS = -DSG_LIB_WIN32 -DSPTD OS_FLAGS = -DSG_LIB_WIN32 LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS) # CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) # CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) LDFLAGS = all: $(EXECS) clean: rm *.o $(EXE_S) .c.o: $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $< hxascdmp: hxascdmp.o $(LD) -o $@ $(LDFLAGS) $@.o sg3_utils-1.40/utils/Makefile.freebsd0000664000175000017500000000175511030022612016554 0ustar douggdouggSHELL = /bin/sh PREFIX=/usr/local INSTDIR=$(DESTDIR)/$(PREFIX)/bin MANDIR=$(DESTDIR)/$(PREFIX)/man CC = gcc LD = gcc EXECS = hxascdmp # EXECS = hxascdmp sg_chk_asc MAN_PGS = MAN_PREF = man8 CFLAGS = -g -O2 -W # CFLAGS = -g -O2 -W -pedantic -std=c99 LDFLAGS = all: $(EXECS) depend dep: for i in *.c; do $(CC) $(INCLUDES) $(CFLAGS) -M $$i; \ done > .depend clean: /bin/rm -f *.o $(EXECS) core .depend hxascdmp: hxascdmp.o $(LD) -o $@ $(LDFLAGS) $@.o sg_chk_asc: sg_chk_asc.o ../sg_lib.o ../sg_lib_data.o $(LD) -o $@ $(LDFLAGS) $@.o ../sg_lib.o install: $(EXECS) install -d $(INSTDIR) for name in $(EXECS); \ do install -s -m 755 $$name $(INSTDIR); \ done install -d $(MANDIR)/$(MAN_PREF) for mp in $(MAN_PGS); \ do install -m 644 $$mp $(MANDIR)/$(MAN_PREF); \ gzip -9f $(MANDIR)/$(MAN_PREF)/$$mp; \ done uninstall: dists="$(EXECS)"; \ for name in $$dists; do \ rm -f $(INSTDIR)/$$name; \ done for mp in $(MAN_PGS); do \ rm -f $(MANDIR)/$(MAN_PREF)/$$mp.gz; \ done sg3_utils-1.40/utils/Makefile.mingw0000664000175000017500000000122311173615520016267 0ustar douggdougg# Assumes makefile is used in a MSYS shell with a MinGW compiler available. SHELL = /bin/sh CC = gcc LD = gcc EXECS = hxascdmp EXE_S = hxascdmp.exe # OS_FLAGS = -DSG_LIB_WIN32 -DSG_LIB_MINGW -DSPTD OS_FLAGS = -DSG_LIB_WIN32 -DSG_LIB_MINGW LARGE_FILE_FLAGS = -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 EXTRA_FLAGS = $(OS_FLAGS) $(LARGE_FILE_FLAGS) # CFLAGS = -O2 -Wall -W $(EXTRA_FLAGS) CFLAGS = -g -O2 -Wall -W $(EXTRA_FLAGS) # CFLAGS = -g -O2 -Wall -W -pedantic -std=c99 $(EXTRA_FLAGS) LDFLAGS = all: $(EXECS) clean: rm *.o $(EXE_S) .c.o: $(CC) $(INCLUDES) $(CFLAGS) $(S_CFLAGS) -c -o $@ $< hxascdmp: hxascdmp.o $(LD) -o $@ $(LDFLAGS) $@.o sg3_utils-1.40/ltmain.sh0000775000175000017500000105204412335161436014205 0ustar douggdougg # libtool (GNU libtool) 2.4.2 # Written by Gordon Matzigkeit , 1996 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, # 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This is free software; see the source for copying conditions. There is NO # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # GNU Libtool 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 of the License, or # (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, # or obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Usage: $progname [OPTION]... [MODE-ARG]... # # Provide generalized library-building support services. # # --config show all configuration variables # --debug enable verbose shell tracing # -n, --dry-run display commands without modifying any files # --features display basic configuration information and exit # --mode=MODE use operation mode MODE # --preserve-dup-deps don't remove duplicate dependency libraries # --quiet, --silent don't print informational messages # --no-quiet, --no-silent # print informational messages (default) # --no-warn don't display warning messages # --tag=TAG use configuration variables from tag TAG # -v, --verbose print more informational messages than default # --no-verbose don't print the extra informational messages # --version print version information # -h, --help, --help-all print short, long, or detailed help message # # MODE must be one of the following: # # clean remove files from the build directory # compile compile a source file into a libtool object # execute automatically set library path, then run a program # finish complete the installation of libtool libraries # install install libraries or executables # link create a library or an executable # uninstall remove libraries from an installed directory # # MODE-ARGS vary depending on the MODE. When passed as first option, # `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. # Try `$progname --help --mode=MODE' for a more detailed description of MODE. # # When reporting a bug, please describe a test case to reproduce it and # include the following information: # # host-triplet: $host # shell: $SHELL # compiler: $LTCC # compiler flags: $LTCFLAGS # linker: $LD (gnu? $with_gnu_ld) # $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.7ubuntu1 # automake: $automake_version # autoconf: $autoconf_version # # Report bugs to . # GNU libtool home page: . # General help using GNU software: . PROGRAM=libtool PACKAGE=libtool VERSION="2.4.2 Debian-2.4.2-1.7ubuntu1" TIMESTAMP="" package_revision=1.3337 # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } # NLS nuisances: We save the old values to restore during execute mode. lt_user_locale= lt_safe_locale= for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${$lt_var+set}\" = set; then save_$lt_var=\$$lt_var $lt_var=C export $lt_var lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" fi" done LC_ALL=C LANGUAGE=C export LANGUAGE LC_ALL $lt_unset CDPATH # Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh # is ksh but when the shell is invoked as "sh" and the current value of # the _XPG environment variable is not equal to 1 (one), the special # positional parameter $0, within a function call, is the name of the # function. progpath="$0" : ${CP="cp -f"} test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} : ${MAKE="make"} : ${MKDIR="mkdir"} : ${MV="mv -f"} : ${RM="rm -f"} : ${SHELL="${CONFIG_SHELL-/bin/sh}"} : ${Xsed="$SED -e 1s/^X//"} # Global variables: EXIT_SUCCESS=0 EXIT_FAILURE=1 EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. exit_status=$EXIT_SUCCESS # Make sure IFS has a sensible default lt_nl=' ' IFS=" $lt_nl" dirname="s,/[^/]*$,," basename="s,^.*/,," # func_dirname file append nondir_replacement # Compute the dirname of FILE. If nonempty, add APPEND to the result, # otherwise set result to NONDIR_REPLACEMENT. func_dirname () { func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi } # func_dirname may be replaced by extended shell implementation # func_basename file func_basename () { func_basename_result=`$ECHO "${1}" | $SED "$basename"` } # func_basename may be replaced by extended shell implementation # func_dirname_and_basename file append nondir_replacement # perform func_basename and func_dirname in a single function # call: # dirname: Compute the dirname of FILE. If nonempty, # add APPEND to the result, otherwise set result # to NONDIR_REPLACEMENT. # value returned in "$func_dirname_result" # basename: Compute filename of FILE. # value retuned in "$func_basename_result" # Implementation must be kept synchronized with func_dirname # and func_basename. For efficiency, we do not delegate to # those functions but instead duplicate the functionality here. func_dirname_and_basename () { # Extract subdirectory from the argument. func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` if test "X$func_dirname_result" = "X${1}"; then func_dirname_result="${3}" else func_dirname_result="$func_dirname_result${2}" fi func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` } # func_dirname_and_basename may be replaced by extended shell implementation # func_stripname prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # func_strip_suffix prefix name func_stripname () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname may be replaced by extended shell implementation # These SED scripts presuppose an absolute path with a trailing slash. pathcar='s,^/\([^/]*\).*$,\1,' pathcdr='s,^/[^/]*,,' removedotparts=':dotsl s@/\./@/@g t dotsl s,/\.$,/,' collapseslashes='s@/\{1,\}@/@g' finalslash='s,/*$,/,' # func_normal_abspath PATH # Remove doubled-up and trailing slashes, "." path components, # and cancel out any ".." path components in PATH after making # it an absolute path. # value returned in "$func_normal_abspath_result" func_normal_abspath () { # Start from root dir and reassemble the path. func_normal_abspath_result= func_normal_abspath_tpath=$1 func_normal_abspath_altnamespace= case $func_normal_abspath_tpath in "") # Empty path, that just means $cwd. func_stripname '' '/' "`pwd`" func_normal_abspath_result=$func_stripname_result return ;; # The next three entries are used to spot a run of precisely # two leading slashes without using negated character classes; # we take advantage of case's first-match behaviour. ///*) # Unusual form of absolute path, do nothing. ;; //*) # Not necessarily an ordinary path; POSIX reserves leading '//' # and for example Cygwin uses it to access remote file shares # over CIFS/SMB, so we conserve a leading double slash if found. func_normal_abspath_altnamespace=/ ;; /*) # Absolute path, do nothing. ;; *) # Relative path, prepend $cwd. func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath ;; esac # Cancel out all the simple stuff to save iterations. We also want # the path to end with a slash for ease of parsing, so make sure # there is one (and only one) here. func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` while :; do # Processed it all yet? if test "$func_normal_abspath_tpath" = / ; then # If we ascended to the root using ".." the result may be empty now. if test -z "$func_normal_abspath_result" ; then func_normal_abspath_result=/ fi break fi func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcar"` func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ -e "$pathcdr"` # Figure out what to do with it case $func_normal_abspath_tcomponent in "") # Trailing empty path component, ignore it. ;; ..) # Parent dir; strip last assembled component from result. func_dirname "$func_normal_abspath_result" func_normal_abspath_result=$func_dirname_result ;; *) # Actual path component, append it. func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent ;; esac done # Restore leading double-slash if one was found on entry. func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result } # func_relative_path SRCDIR DSTDIR # generates a relative path from SRCDIR to DSTDIR, with a trailing # slash if non-empty, suitable for immediately appending a filename # without needing to append a separator. # value returned in "$func_relative_path_result" func_relative_path () { func_relative_path_result= func_normal_abspath "$1" func_relative_path_tlibdir=$func_normal_abspath_result func_normal_abspath "$2" func_relative_path_tbindir=$func_normal_abspath_result # Ascend the tree starting from libdir while :; do # check if we have found a prefix of bindir case $func_relative_path_tbindir in $func_relative_path_tlibdir) # found an exact match func_relative_path_tcancelled= break ;; $func_relative_path_tlibdir*) # found a matching prefix func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" func_relative_path_tcancelled=$func_stripname_result if test -z "$func_relative_path_result"; then func_relative_path_result=. fi break ;; *) func_dirname $func_relative_path_tlibdir func_relative_path_tlibdir=${func_dirname_result} if test "x$func_relative_path_tlibdir" = x ; then # Have to descend all the way to the root! func_relative_path_result=../$func_relative_path_result func_relative_path_tcancelled=$func_relative_path_tbindir break fi func_relative_path_result=../$func_relative_path_result ;; esac done # Now calculate path; take care to avoid doubling-up slashes. func_stripname '' '/' "$func_relative_path_result" func_relative_path_result=$func_stripname_result func_stripname '/' '/' "$func_relative_path_tcancelled" if test "x$func_stripname_result" != x ; then func_relative_path_result=${func_relative_path_result}/${func_stripname_result} fi # Normalisation. If bindir is libdir, return empty string, # else relative path ending with a slash; either way, target # file name can be directly appended. if test ! -z "$func_relative_path_result"; then func_stripname './' '' "$func_relative_path_result/" func_relative_path_result=$func_stripname_result fi } # The name of this program: func_dirname_and_basename "$progpath" progname=$func_basename_result # Make sure we have an absolute path for reexecution: case $progpath in [\\/]*|[A-Za-z]:\\*) ;; *[\\/]*) progdir=$func_dirname_result progdir=`cd "$progdir" && pwd` progpath="$progdir/$progname" ;; *) save_IFS="$IFS" IFS=${PATH_SEPARATOR-:} for progdir in $PATH; do IFS="$save_IFS" test -x "$progdir/$progname" && break done IFS="$save_IFS" test -n "$progdir" || progdir=`pwd` progpath="$progdir/$progname" ;; esac # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. Xsed="${SED}"' -e 1s/^X//' sed_quote_subst='s/\([`"$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution that turns a string into a regex matching for the # string literally. sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' # Sed substitution that converts a w32 file name or path # which contains forward slashes, into one that contains # (escaped) backslashes. A very naive implementation. lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' # Re-`\' parameter expansions in output of double_quote_subst that were # `\'-ed in input to the same. If an odd number of `\' preceded a '$' # in input to double_quote_subst, that '$' was protected from expansion. # Since each input `\' is now two `\'s, look for any number of runs of # four `\'s followed by two `\'s and then a '$'. `\' that '$'. bs='\\' bs2='\\\\' bs4='\\\\\\\\' dollar='\$' sed_double_backslash="\ s/$bs4/&\\ /g s/^$bs2$dollar/$bs&/ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g s/\n//g" # Standard options: opt_dry_run=false opt_help=false opt_quiet=false opt_verbose=false opt_warning=: # func_echo arg... # Echo program name prefixed message, along with the current mode # name if it has been set yet. func_echo () { $ECHO "$progname: ${opt_mode+$opt_mode: }$*" } # func_verbose arg... # Echo program name prefixed message in verbose mode only. func_verbose () { $opt_verbose && func_echo ${1+"$@"} # A bug in bash halts the script if the last line of a function # fails when set -e is in force, so we need another command to # work around that: : } # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } # func_error arg... # Echo program name prefixed message to standard error. func_error () { $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 } # func_warning arg... # Echo program name prefixed warning message to standard error. func_warning () { $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 # bash bug again: : } # func_fatal_error arg... # Echo program name prefixed message to standard error, and exit. func_fatal_error () { func_error ${1+"$@"} exit $EXIT_FAILURE } # func_fatal_help arg... # Echo program name prefixed message to standard error, followed by # a help hint, and exit. func_fatal_help () { func_error ${1+"$@"} func_fatal_error "$help" } help="Try \`$progname --help' for more information." ## default # func_grep expression filename # Check whether EXPRESSION matches any line of FILENAME, without output. func_grep () { $GREP "$1" "$2" >/dev/null 2>&1 } # func_mkdir_p directory-path # Make sure the entire path to DIRECTORY-PATH is available. func_mkdir_p () { my_directory_path="$1" my_dir_list= if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then # Protect directory names starting with `-' case $my_directory_path in -*) my_directory_path="./$my_directory_path" ;; esac # While some portion of DIR does not yet exist... while test ! -d "$my_directory_path"; do # ...make a list in topmost first order. Use a colon delimited # list incase some portion of path contains whitespace. my_dir_list="$my_directory_path:$my_dir_list" # If the last portion added has no slash in it, the list is done case $my_directory_path in */*) ;; *) break ;; esac # ...otherwise throw away the child directory and loop my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` done my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` save_mkdir_p_IFS="$IFS"; IFS=':' for my_dir in $my_dir_list; do IFS="$save_mkdir_p_IFS" # mkdir can fail with a `File exist' error if two processes # try to create one of the directories concurrently. Don't # stop in that case! $MKDIR "$my_dir" 2>/dev/null || : done IFS="$save_mkdir_p_IFS" # Bail out if we (or some other process) failed to create a directory. test -d "$my_directory_path" || \ func_fatal_error "Failed to create \`$1'" fi } # func_mktempdir [string] # Make a temporary directory that won't clash with other running # libtool processes, and avoids race conditions if possible. If # given, STRING is the basename for that directory. func_mktempdir () { my_template="${TMPDIR-/tmp}/${1-$progname}" if test "$opt_dry_run" = ":"; then # Return a directory name, but don't create it in dry-run mode my_tmpdir="${my_template}-$$" else # If mktemp works, use that first and foremost my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` if test ! -d "$my_tmpdir"; then # Failing that, at least try and use $RANDOM to avoid a race my_tmpdir="${my_template}-${RANDOM-0}$$" save_mktempdir_umask=`umask` umask 0077 $MKDIR "$my_tmpdir" umask $save_mktempdir_umask fi # If we're not in dry-run mode, bomb out on failure test -d "$my_tmpdir" || \ func_fatal_error "cannot create temporary directory \`$my_tmpdir'" fi $ECHO "$my_tmpdir" } # func_quote_for_eval arg # Aesthetically quote ARG to be evaled later. # This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT # is double-quoted, suitable for a subsequent eval, whereas # FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters # which are still active within double quotes backslashified. func_quote_for_eval () { case $1 in *[\\\`\"\$]*) func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; *) func_quote_for_eval_unquoted_result="$1" ;; esac case $func_quote_for_eval_unquoted_result in # Double-quote args containing shell metacharacters to delay # word splitting, command substitution and and variable # expansion for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" ;; *) func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" esac } # func_quote_for_expand arg # Aesthetically quote ARG to be evaled later; same as above, # but do not quote variable references. func_quote_for_expand () { case $1 in *[\\\`\"]*) my_arg=`$ECHO "$1" | $SED \ -e "$double_quote_subst" -e "$sed_double_backslash"` ;; *) my_arg="$1" ;; esac case $my_arg in # Double-quote args containing shell metacharacters to delay # word splitting and command substitution for a subsequent eval. # Many Bourne shells cannot handle close brackets correctly # in scan sets, so we specify it separately. *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") my_arg="\"$my_arg\"" ;; esac func_quote_for_expand_result="$my_arg" } # func_show_eval cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. func_show_eval () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$my_cmd" my_status=$? if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_show_eval_locale cmd [fail_exp] # Unless opt_silent is true, then output CMD. Then, if opt_dryrun is # not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP # is given, then evaluate it. Use the saved locale for evaluation. func_show_eval_locale () { my_cmd="$1" my_fail_exp="${2-:}" ${opt_silent-false} || { func_quote_for_expand "$my_cmd" eval "func_echo $func_quote_for_expand_result" } if ${opt_dry_run-false}; then :; else eval "$lt_user_locale $my_cmd" my_status=$? eval "$lt_safe_locale" if test "$my_status" -eq 0; then :; else eval "(exit $my_status); $my_fail_exp" fi fi } # func_tr_sh # Turn $1 into a string suitable for a shell variable name. # Result is stored in $func_tr_sh_result. All characters # not in the set a-zA-Z0-9_ are replaced with '_'. Further, # if $1 begins with a digit, a '_' is prepended as well. func_tr_sh () { case $1 in [0-9]* | *[!a-zA-Z0-9_]*) func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` ;; * ) func_tr_sh_result=$1 ;; esac } # func_version # Echo version message to standard output and exit. func_version () { $opt_debug $SED -n '/(C)/!b go :more /\./!{ N s/\n# / / b more } :go /^# '$PROGRAM' (GNU /,/# warranty; / { s/^# // s/^# *$// s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ p }' < "$progpath" exit $? } # func_usage # Echo short help message to standard output and exit. func_usage () { $opt_debug $SED -n '/^# Usage:/,/^# *.*--help/ { s/^# // s/^# *$// s/\$progname/'$progname'/ p }' < "$progpath" echo $ECHO "run \`$progname --help | more' for full usage" exit $? } # func_help [NOEXIT] # Echo long help message to standard output and exit, # unless 'noexit' is passed as argument. func_help () { $opt_debug $SED -n '/^# Usage:/,/# Report bugs to/ { :print s/^# // s/^# *$// s*\$progname*'$progname'* s*\$host*'"$host"'* s*\$SHELL*'"$SHELL"'* s*\$LTCC*'"$LTCC"'* s*\$LTCFLAGS*'"$LTCFLAGS"'* s*\$LD*'"$LD"'* s/\$with_gnu_ld/'"$with_gnu_ld"'/ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ p d } /^# .* home page:/b print /^# General help using/b print ' < "$progpath" ret=$? if test -z "$1"; then exit $ret fi } # func_missing_arg argname # Echo program name prefixed message to standard error and set global # exit_cmd. func_missing_arg () { $opt_debug func_error "missing argument for $1." exit_cmd=exit } # func_split_short_opt shortopt # Set func_split_short_opt_name and func_split_short_opt_arg shell # variables after splitting SHORTOPT after the 2nd character. func_split_short_opt () { my_sed_short_opt='1s/^\(..\).*$/\1/;q' my_sed_short_rest='1s/^..\(.*\)$/\1/;q' func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` } # func_split_short_opt may be replaced by extended shell implementation # func_split_long_opt longopt # Set func_split_long_opt_name and func_split_long_opt_arg shell # variables after splitting LONGOPT at the `=' sign. func_split_long_opt () { my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' my_sed_long_arg='1s/^--[^=]*=//' func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` } # func_split_long_opt may be replaced by extended shell implementation exit_cmd=: magic="%%%MAGIC variable%%%" magic_exe="%%%MAGIC EXE variable%%%" # Global variables. nonopt= preserve_args= lo2o="s/\\.lo\$/.${objext}/" o2lo="s/\\.${objext}\$/.lo/" extracted_archives= extracted_serial=0 # If this variable is set in any of the actions, the command in it # will be execed at the end. This prevents here-documents from being # left over by shells. exec_cmd= # func_append var value # Append VALUE to the end of shell variable VAR. func_append () { eval "${1}=\$${1}\${2}" } # func_append may be replaced by extended shell implementation # func_append_quoted var value # Quote VALUE and append to the end of shell variable VAR, separated # by a space. func_append_quoted () { func_quote_for_eval "${2}" eval "${1}=\$${1}\\ \$func_quote_for_eval_result" } # func_append_quoted may be replaced by extended shell implementation # func_arith arithmetic-term... func_arith () { func_arith_result=`expr "${@}"` } # func_arith may be replaced by extended shell implementation # func_len string # STRING may not start with a hyphen. func_len () { func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` } # func_len may be replaced by extended shell implementation # func_lo2o object func_lo2o () { func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` } # func_lo2o may be replaced by extended shell implementation # func_xform libobj-or-source func_xform () { func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` } # func_xform may be replaced by extended shell implementation # func_fatal_configuration arg... # Echo program name prefixed message to standard error, followed by # a configuration failure hint, and exit. func_fatal_configuration () { func_error ${1+"$@"} func_error "See the $PACKAGE documentation for more information." func_fatal_error "Fatal configuration error." } # func_config # Display the configuration for all the tags in this script. func_config () { re_begincf='^# ### BEGIN LIBTOOL' re_endcf='^# ### END LIBTOOL' # Default configuration. $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" # Now print the configurations for the tags. for tagname in $taglist; do $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" done exit $? } # func_features # Display the features supported by this script. func_features () { echo "host: $host" if test "$build_libtool_libs" = yes; then echo "enable shared libraries" else echo "disable shared libraries" fi if test "$build_old_libs" = yes; then echo "enable static libraries" else echo "disable static libraries" fi exit $? } # func_enable_tag tagname # Verify that TAGNAME is valid, and either flag an error and exit, or # enable the TAGNAME tag. We also add TAGNAME to the global $taglist # variable here. func_enable_tag () { # Global variable: tagname="$1" re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" sed_extractcf="/$re_begincf/,/$re_endcf/p" # Validate tagname. case $tagname in *[!-_A-Za-z0-9,/]*) func_fatal_error "invalid tag name: $tagname" ;; esac # Don't test for the "default" C tag, as we know it's # there but not specially marked. case $tagname in CC) ;; *) if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then taglist="$taglist $tagname" # Evaluate the configuration. Be careful to quote the path # and the sed script, to avoid splitting on whitespace, but # also don't use non-portable quotes within backquotes within # quotes we have to do it in 2 steps: extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` eval "$extractedcf" else func_error "ignoring unknown tag $tagname" fi ;; esac } # func_check_version_match # Ensure that we are using m4 macros, and libtool script from the same # release of libtool. func_check_version_match () { if test "$package_revision" != "$macro_revision"; then if test "$VERSION" != "$macro_version"; then if test -z "$macro_version"; then cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from an older release. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, but the $progname: definition of this LT_INIT comes from $PACKAGE $macro_version. $progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION $progname: and run autoconf again. _LT_EOF fi else cat >&2 <<_LT_EOF $progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, $progname: but the definition of this LT_INIT comes from revision $macro_revision. $progname: You should recreate aclocal.m4 with macros from revision $package_revision $progname: of $PACKAGE $VERSION and run autoconf again. _LT_EOF fi exit $EXIT_MISMATCH fi } # Shorthand for --mode=foo, only valid as the first argument case $1 in clean|clea|cle|cl) shift; set dummy --mode clean ${1+"$@"}; shift ;; compile|compil|compi|comp|com|co|c) shift; set dummy --mode compile ${1+"$@"}; shift ;; execute|execut|execu|exec|exe|ex|e) shift; set dummy --mode execute ${1+"$@"}; shift ;; finish|finis|fini|fin|fi|f) shift; set dummy --mode finish ${1+"$@"}; shift ;; install|instal|insta|inst|ins|in|i) shift; set dummy --mode install ${1+"$@"}; shift ;; link|lin|li|l) shift; set dummy --mode link ${1+"$@"}; shift ;; uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) shift; set dummy --mode uninstall ${1+"$@"}; shift ;; esac # Option defaults: opt_debug=: opt_dry_run=false opt_config=false opt_preserve_dup_deps=false opt_features=false opt_finish=false opt_help=false opt_help_all=false opt_silent=: opt_warning=: opt_verbose=: opt_silent=false opt_verbose=false # Parse options once, thoroughly. This comes as soon as possible in the # script to make things like `--version' happen as quickly as we can. { # this just eases exit handling while test $# -gt 0; do opt="$1" shift case $opt in --debug|-x) opt_debug='set -x' func_echo "enabling shell trace mode" $opt_debug ;; --dry-run|--dryrun|-n) opt_dry_run=: ;; --config) opt_config=: func_config ;; --dlopen|-dlopen) optarg="$1" opt_dlopen="${opt_dlopen+$opt_dlopen }$optarg" shift ;; --preserve-dup-deps) opt_preserve_dup_deps=: ;; --features) opt_features=: func_features ;; --finish) opt_finish=: set dummy --mode finish ${1+"$@"}; shift ;; --help) opt_help=: ;; --help-all) opt_help_all=: opt_help=': help-all' ;; --mode) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_mode="$optarg" case $optarg in # Valid mode arguments: clean|compile|execute|finish|install|link|relink|uninstall) ;; # Catch anything else as an error *) func_error "invalid argument for $opt" exit_cmd=exit break ;; esac shift ;; --no-silent|--no-quiet) opt_silent=false func_append preserve_args " $opt" ;; --no-warning|--no-warn) opt_warning=false func_append preserve_args " $opt" ;; --no-verbose) opt_verbose=false func_append preserve_args " $opt" ;; --silent|--quiet) opt_silent=: func_append preserve_args " $opt" opt_verbose=false ;; --verbose|-v) opt_verbose=: func_append preserve_args " $opt" opt_silent=false ;; --tag) test $# = 0 && func_missing_arg $opt && break optarg="$1" opt_tag="$optarg" func_append preserve_args " $opt $optarg" func_enable_tag "$optarg" shift ;; -\?|-h) func_usage ;; --help) func_help ;; --version) func_version ;; # Separate optargs to long options: --*=*) func_split_long_opt "$opt" set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} shift ;; # Separate non-argument short options: -\?*|-h*|-n*|-v*) func_split_short_opt "$opt" set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} shift ;; --) break ;; -*) func_fatal_help "unrecognized option \`$opt'" ;; *) set dummy "$opt" ${1+"$@"}; shift; break ;; esac done # Validate options: # save first non-option argument if test "$#" -gt 0; then nonopt="$opt" shift fi # preserve --debug test "$opt_debug" = : || func_append preserve_args " --debug" case $host in *cygwin* | *mingw* | *pw32* | *cegcc*) # don't eliminate duplications in $postdeps and $predeps opt_duplicate_compiler_generated_deps=: ;; *) opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps ;; esac $opt_help || { # Sanity checks first: func_check_version_match if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then func_fatal_configuration "not configured to build any kind of library" fi # Darwin sucks eval std_shrext=\"$shrext_cmds\" # Only execute mode is allowed to have -dlopen flags. if test -n "$opt_dlopen" && test "$opt_mode" != execute; then func_error "unrecognized option \`-dlopen'" $ECHO "$help" 1>&2 exit $EXIT_FAILURE fi # Change the help message to a mode-specific one. generic_help="$help" help="Try \`$progname --help --mode=$opt_mode' for more information." } # Bail if the options were screwed $exit_cmd $EXIT_FAILURE } ## ----------- ## ## Main. ## ## ----------- ## # func_lalib_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_lalib_p () { test -f "$1" && $SED -e 4q "$1" 2>/dev/null \ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 } # func_lalib_unsafe_p file # True iff FILE is a libtool `.la' library or `.lo' object file. # This function implements the same check as func_lalib_p without # resorting to external programs. To this end, it redirects stdin and # closes it afterwards, without saving the original file descriptor. # As a safety measure, use it only where a negative result would be # fatal anyway. Works if `file' does not exist. func_lalib_unsafe_p () { lalib_p=no if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then for lalib_p_l in 1 2 3 4 do read lalib_p_line case "$lalib_p_line" in \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; esac done exec 0<&5 5<&- fi test "$lalib_p" = yes } # func_ltwrapper_script_p file # True iff FILE is a libtool wrapper script # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_script_p () { func_lalib_p "$1" } # func_ltwrapper_executable_p file # True iff FILE is a libtool wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_executable_p () { func_ltwrapper_exec_suffix= case $1 in *.exe) ;; *) func_ltwrapper_exec_suffix=.exe ;; esac $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 } # func_ltwrapper_scriptname file # Assumes file is an ltwrapper_executable # uses $file to determine the appropriate filename for a # temporary ltwrapper_script. func_ltwrapper_scriptname () { func_dirname_and_basename "$1" "" "." func_stripname '' '.exe' "$func_basename_result" func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" } # func_ltwrapper_p file # True iff FILE is a libtool wrapper script or wrapper executable # This function is only a basic sanity check; it will hardly flush out # determined imposters. func_ltwrapper_p () { func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" } # func_execute_cmds commands fail_cmd # Execute tilde-delimited COMMANDS. # If FAIL_CMD is given, eval that upon failure. # FAIL_CMD may read-access the current command in variable CMD! func_execute_cmds () { $opt_debug save_ifs=$IFS; IFS='~' for cmd in $1; do IFS=$save_ifs eval cmd=\"$cmd\" func_show_eval "$cmd" "${2-:}" done IFS=$save_ifs } # func_source file # Source FILE, adding directory component if necessary. # Note that it is not necessary on cygwin/mingw to append a dot to # FILE even if both FILE and FILE.exe exist: automatic-append-.exe # behavior happens only for exec(3), not for open(2)! Also, sourcing # `FILE.' does not work on cygwin managed mounts. func_source () { $opt_debug case $1 in */* | *\\*) . "$1" ;; *) . "./$1" ;; esac } # func_resolve_sysroot PATH # Replace a leading = in PATH with a sysroot. Store the result into # func_resolve_sysroot_result func_resolve_sysroot () { func_resolve_sysroot_result=$1 case $func_resolve_sysroot_result in =*) func_stripname '=' '' "$func_resolve_sysroot_result" func_resolve_sysroot_result=$lt_sysroot$func_stripname_result ;; esac } # func_replace_sysroot PATH # If PATH begins with the sysroot, replace it with = and # store the result into func_replace_sysroot_result. func_replace_sysroot () { case "$lt_sysroot:$1" in ?*:"$lt_sysroot"*) func_stripname "$lt_sysroot" '' "$1" func_replace_sysroot_result="=$func_stripname_result" ;; *) # Including no sysroot. func_replace_sysroot_result=$1 ;; esac } # func_infer_tag arg # Infer tagged configuration to use if any are available and # if one wasn't chosen via the "--tag" command line option. # Only attempt this if the compiler in the base compile # command doesn't match the default compiler. # arg is usually of the form 'gcc ...' func_infer_tag () { $opt_debug if test -n "$available_tags" && test -z "$tagname"; then CC_quoted= for arg in $CC; do func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case $@ in # Blanks in the command may have been stripped by the calling shell, # but not from the CC environment variable when configure was run. " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; # Blanks at the start of $base_compile will cause this to fail # if we don't check for them as well. *) for z in $available_tags; do if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then # Evaluate the configuration. eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" CC_quoted= for arg in $CC; do # Double-quote args containing other shell metacharacters. func_append_quoted CC_quoted "$arg" done CC_expanded=`func_echo_all $CC` CC_quoted_expanded=`func_echo_all $CC_quoted` case "$@ " in " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) # The compiler in the base compile command matches # the one in the tagged configuration. # Assume this is the tagged configuration we want. tagname=$z break ;; esac fi done # If $tagname still isn't set, then no tagged configuration # was found and let the user know that the "--tag" command # line option must be used. if test -z "$tagname"; then func_echo "unable to infer tagged configuration" func_fatal_error "specify a tag with \`--tag'" # else # func_verbose "using $tagname tagged configuration" fi ;; esac fi } # func_write_libtool_object output_name pic_name nonpic_name # Create a libtool object file (analogous to a ".la" file), # but don't create it if we're doing a dry run. func_write_libtool_object () { write_libobj=${1} if test "$build_libtool_libs" = yes; then write_lobj=\'${2}\' else write_lobj=none fi if test "$build_old_libs" = yes; then write_oldobj=\'${3}\' else write_oldobj=none fi $opt_dry_run || { cat >${write_libobj}T </dev/null` if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | $SED -e "$lt_sed_naive_backslashify"` else func_convert_core_file_wine_to_w32_result= fi fi } # end: func_convert_core_file_wine_to_w32 # func_convert_core_path_wine_to_w32 ARG # Helper function used by path conversion functions when $build is *nix, and # $host is mingw, cygwin, or some other w32 environment. Relies on a correctly # configured wine environment available, with the winepath program in $build's # $PATH. Assumes ARG has no leading or trailing path separator characters. # # ARG is path to be converted from $build format to win32. # Result is available in $func_convert_core_path_wine_to_w32_result. # Unconvertible file (directory) names in ARG are skipped; if no directory names # are convertible, then the result may be empty. func_convert_core_path_wine_to_w32 () { $opt_debug # unfortunately, winepath doesn't convert paths, only file names func_convert_core_path_wine_to_w32_result="" if test -n "$1"; then oldIFS=$IFS IFS=: for func_convert_core_path_wine_to_w32_f in $1; do IFS=$oldIFS func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" if test -n "$func_convert_core_file_wine_to_w32_result" ; then if test -z "$func_convert_core_path_wine_to_w32_result"; then func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" else func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" fi fi done IFS=$oldIFS fi } # end: func_convert_core_path_wine_to_w32 # func_cygpath ARGS... # Wrapper around calling the cygpath program via LT_CYGPATH. This is used when # when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) # $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or # (2), returns the Cygwin file name or path in func_cygpath_result (input # file name or path is assumed to be in w32 format, as previously converted # from $build's *nix or MSYS format). In case (3), returns the w32 file name # or path in func_cygpath_result (input file name or path is assumed to be in # Cygwin format). Returns an empty string on error. # # ARGS are passed to cygpath, with the last one being the file name or path to # be converted. # # Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH # environment variable; do not put it in $PATH. func_cygpath () { $opt_debug if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` if test "$?" -ne 0; then # on failure, ensure result is empty func_cygpath_result= fi else func_cygpath_result= func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" fi } #end: func_cygpath # func_convert_core_msys_to_w32 ARG # Convert file name or path ARG from MSYS format to w32 format. Return # result in func_convert_core_msys_to_w32_result. func_convert_core_msys_to_w32 () { $opt_debug # awkward: cmd appends spaces to result func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` } #end: func_convert_core_msys_to_w32 # func_convert_file_check ARG1 ARG2 # Verify that ARG1 (a file name in $build format) was converted to $host # format in ARG2. Otherwise, emit an error message, but continue (resetting # func_to_host_file_result to ARG1). func_convert_file_check () { $opt_debug if test -z "$2" && test -n "$1" ; then func_error "Could not determine host file name corresponding to" func_error " \`$1'" func_error "Continuing, but uninstalled executables may not work." # Fallback: func_to_host_file_result="$1" fi } # end func_convert_file_check # func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH # Verify that FROM_PATH (a path in $build format) was converted to $host # format in TO_PATH. Otherwise, emit an error message, but continue, resetting # func_to_host_file_result to a simplistic fallback value (see below). func_convert_path_check () { $opt_debug if test -z "$4" && test -n "$3"; then func_error "Could not determine the host path corresponding to" func_error " \`$3'" func_error "Continuing, but uninstalled executables may not work." # Fallback. This is a deliberately simplistic "conversion" and # should not be "improved". See libtool.info. if test "x$1" != "x$2"; then lt_replace_pathsep_chars="s|$1|$2|g" func_to_host_path_result=`echo "$3" | $SED -e "$lt_replace_pathsep_chars"` else func_to_host_path_result="$3" fi fi } # end func_convert_path_check # func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG # Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT # and appending REPL if ORIG matches BACKPAT. func_convert_path_front_back_pathsep () { $opt_debug case $4 in $1 ) func_to_host_path_result="$3$func_to_host_path_result" ;; esac case $4 in $2 ) func_append func_to_host_path_result "$3" ;; esac } # end func_convert_path_front_back_pathsep ################################################## # $build to $host FILE NAME CONVERSION FUNCTIONS # ################################################## # invoked via `$to_host_file_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # Result will be available in $func_to_host_file_result. # func_to_host_file ARG # Converts the file name ARG from $build format to $host format. Return result # in func_to_host_file_result. func_to_host_file () { $opt_debug $to_host_file_cmd "$1" } # end func_to_host_file # func_to_tool_file ARG LAZY # converts the file name ARG from $build format to toolchain format. Return # result in func_to_tool_file_result. If the conversion in use is listed # in (the comma separated) LAZY, no conversion takes place. func_to_tool_file () { $opt_debug case ,$2, in *,"$to_tool_file_cmd",*) func_to_tool_file_result=$1 ;; *) $to_tool_file_cmd "$1" func_to_tool_file_result=$func_to_host_file_result ;; esac } # end func_to_tool_file # func_convert_file_noop ARG # Copy ARG to func_to_host_file_result. func_convert_file_noop () { func_to_host_file_result="$1" } # end func_convert_file_noop # func_convert_file_msys_to_w32 ARG # Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_file_result. func_convert_file_msys_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_to_host_file_result="$func_convert_core_msys_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_w32 # func_convert_file_cygwin_to_w32 ARG # Convert file name ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_file_cygwin_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # because $build is cygwin, we call "the" cygpath in $PATH; no need to use # LT_CYGPATH in this case. func_to_host_file_result=`cygpath -m "$1"` fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_cygwin_to_w32 # func_convert_file_nix_to_w32 ARG # Convert file name ARG from *nix to w32 format. Requires a wine environment # and a working winepath. Returns result in func_to_host_file_result. func_convert_file_nix_to_w32 () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_file_wine_to_w32 "$1" func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_w32 # func_convert_file_msys_to_cygwin ARG # Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_file_msys_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then func_convert_core_msys_to_w32 "$1" func_cygpath -u "$func_convert_core_msys_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_msys_to_cygwin # func_convert_file_nix_to_cygwin ARG # Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed # in a wine environment, working winepath, and LT_CYGPATH set. Returns result # in func_to_host_file_result. func_convert_file_nix_to_cygwin () { $opt_debug func_to_host_file_result="$1" if test -n "$1"; then # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. func_convert_core_file_wine_to_w32 "$1" func_cygpath -u "$func_convert_core_file_wine_to_w32_result" func_to_host_file_result="$func_cygpath_result" fi func_convert_file_check "$1" "$func_to_host_file_result" } # end func_convert_file_nix_to_cygwin ############################################# # $build to $host PATH CONVERSION FUNCTIONS # ############################################# # invoked via `$to_host_path_cmd ARG' # # In each case, ARG is the path to be converted from $build to $host format. # The result will be available in $func_to_host_path_result. # # Path separators are also converted from $build format to $host format. If # ARG begins or ends with a path separator character, it is preserved (but # converted to $host format) on output. # # All path conversion functions are named using the following convention: # file name conversion function : func_convert_file_X_to_Y () # path conversion function : func_convert_path_X_to_Y () # where, for any given $build/$host combination the 'X_to_Y' value is the # same. If conversion functions are added for new $build/$host combinations, # the two new functions must follow this pattern, or func_init_to_host_path_cmd # will break. # func_init_to_host_path_cmd # Ensures that function "pointer" variable $to_host_path_cmd is set to the # appropriate value, based on the value of $to_host_file_cmd. to_host_path_cmd= func_init_to_host_path_cmd () { $opt_debug if test -z "$to_host_path_cmd"; then func_stripname 'func_convert_file_' '' "$to_host_file_cmd" to_host_path_cmd="func_convert_path_${func_stripname_result}" fi } # func_to_host_path ARG # Converts the path ARG from $build format to $host format. Return result # in func_to_host_path_result. func_to_host_path () { $opt_debug func_init_to_host_path_cmd $to_host_path_cmd "$1" } # end func_to_host_path # func_convert_path_noop ARG # Copy ARG to func_to_host_path_result. func_convert_path_noop () { func_to_host_path_result="$1" } # end func_convert_path_noop # func_convert_path_msys_to_w32 ARG # Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic # conversion to w32 is not available inside the cwrapper. Returns result in # func_to_host_path_result. func_convert_path_msys_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from ARG. MSYS # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; # and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_msys_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_msys_to_w32 # func_convert_path_cygwin_to_w32 ARG # Convert path ARG from Cygwin to w32 format. Returns result in # func_to_host_file_result. func_convert_path_cygwin_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_cygwin_to_w32 # func_convert_path_nix_to_w32 ARG # Convert path ARG from *nix to w32 format. Requires a wine environment and # a working winepath. Returns result in func_to_host_file_result. func_convert_path_nix_to_w32 () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" func_convert_path_check : ";" \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" fi } # end func_convert_path_nix_to_w32 # func_convert_path_msys_to_cygwin ARG # Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. # Returns result in func_to_host_file_result. func_convert_path_msys_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # See func_convert_path_msys_to_w32: func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_msys_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_msys_to_cygwin # func_convert_path_nix_to_cygwin ARG # Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a # a wine environment, working winepath, and LT_CYGPATH set. Returns result in # func_to_host_file_result. func_convert_path_nix_to_cygwin () { $opt_debug func_to_host_path_result="$1" if test -n "$1"; then # Remove leading and trailing path separator characters from # ARG. msys behavior is inconsistent here, cygpath turns them # into '.;' and ';.', and winepath ignores them completely. func_stripname : : "$1" func_to_host_path_tmp1=$func_stripname_result func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" func_to_host_path_result="$func_cygpath_result" func_convert_path_check : : \ "$func_to_host_path_tmp1" "$func_to_host_path_result" func_convert_path_front_back_pathsep ":*" "*:" : "$1" fi } # end func_convert_path_nix_to_cygwin # func_mode_compile arg... func_mode_compile () { $opt_debug # Get the compilation command and the source file. base_compile= srcfile="$nonopt" # always keep a non-empty value in "srcfile" suppress_opt=yes suppress_output= arg_mode=normal libobj= later= pie_flag= for arg do case $arg_mode in arg ) # do not "continue". Instead, add this to base_compile lastarg="$arg" arg_mode=normal ;; target ) libobj="$arg" arg_mode=normal continue ;; normal ) # Accept any command-line options. case $arg in -o) test -n "$libobj" && \ func_fatal_error "you cannot specify \`-o' more than once" arg_mode=target continue ;; -pie | -fpie | -fPIE) func_append pie_flag " $arg" continue ;; -shared | -static | -prefer-pic | -prefer-non-pic) func_append later " $arg" continue ;; -no-suppress) suppress_opt=no continue ;; -Xcompiler) arg_mode=arg # the next one goes into the "base_compile" arg list continue # The current "srcfile" will either be retained or ;; # replaced later. I would guess that would be a bug. -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result lastarg= save_ifs="$IFS"; IFS=',' for arg in $args; do IFS="$save_ifs" func_append_quoted lastarg "$arg" done IFS="$save_ifs" func_stripname ' ' '' "$lastarg" lastarg=$func_stripname_result # Add the arguments to base_compile. func_append base_compile " $lastarg" continue ;; *) # Accept the current argument as the source file. # The previous "srcfile" becomes the current argument. # lastarg="$srcfile" srcfile="$arg" ;; esac # case $arg ;; esac # case $arg_mode # Aesthetically quote the previous argument. func_append_quoted base_compile "$lastarg" done # for arg case $arg_mode in arg) func_fatal_error "you must specify an argument for -Xcompile" ;; target) func_fatal_error "you must specify a target with \`-o'" ;; *) # Get the name of the library object. test -z "$libobj" && { func_basename "$srcfile" libobj="$func_basename_result" } ;; esac # Recognize several different file suffixes. # If the user specifies -o file.o, it is replaced with file.lo case $libobj in *.[cCFSifmso] | \ *.ada | *.adb | *.ads | *.asm | \ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) func_xform "$libobj" libobj=$func_xform_result ;; esac case $libobj in *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; *) func_fatal_error "cannot determine name of library object from \`$libobj'" ;; esac func_infer_tag $base_compile for arg in $later; do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no continue ;; -static) build_libtool_libs=no build_old_libs=yes continue ;; -prefer-pic) pic_mode=yes continue ;; -prefer-non-pic) pic_mode=no continue ;; esac done func_quote_for_eval "$libobj" test "X$libobj" != "X$func_quote_for_eval_result" \ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ && func_warning "libobj name \`$libobj' may not contain shell special characters." func_dirname_and_basename "$obj" "/" "" objname="$func_basename_result" xdir="$func_dirname_result" lobj=${xdir}$objdir/$objname test -z "$base_compile" && \ func_fatal_help "you must specify a compilation command" # Delete any leftover library objects. if test "$build_old_libs" = yes; then removelist="$obj $lobj $libobj ${libobj}T" else removelist="$lobj $libobj ${libobj}T" fi # On Cygwin there's no "real" PIC flag so we must build both object types case $host_os in cygwin* | mingw* | pw32* | os2* | cegcc*) pic_mode=default ;; esac if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then # non-PIC code in shared libraries is not supported pic_mode=default fi # Calculate the filename of the output object if compiler does # not support -o with -c if test "$compiler_c_o" = no; then output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} lockfile="$output_obj.lock" else output_obj= need_locks=no lockfile= fi # Lock this critical section if it is needed # We use this script file to make the link, it avoids creating a new file if test "$need_locks" = yes; then until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done elif test "$need_locks" = warn; then if test -f "$lockfile"; then $ECHO "\ *** ERROR, $lockfile exists and contains: `cat $lockfile 2>/dev/null` This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi func_append removelist " $output_obj" $ECHO "$srcfile" > "$lockfile" fi $opt_dry_run || $RM $removelist func_append removelist " $lockfile" trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 srcfile=$func_to_tool_file_result func_quote_for_eval "$srcfile" qsrcfile=$func_quote_for_eval_result # Only build a PIC object if we are building libtool libraries. if test "$build_libtool_libs" = yes; then # Without this assignment, base_compile gets emptied. fbsd_hideous_sh_bug=$base_compile if test "$pic_mode" != no; then command="$base_compile $qsrcfile $pic_flag" else # Don't build PIC code command="$base_compile $qsrcfile" fi func_mkdir_p "$xdir$objdir" if test -z "$output_obj"; then # Place PIC objects in $objdir func_append command " -o $lobj" fi func_show_eval_locale "$command" \ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed, then go on to compile the next one if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then func_show_eval '$MV "$output_obj" "$lobj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi # Allow error messages only from the first compilation. if test "$suppress_opt" = yes; then suppress_output=' >/dev/null 2>&1' fi fi # Only build a position-dependent object if we build old libraries. if test "$build_old_libs" = yes; then if test "$pic_mode" != yes; then # Don't build PIC code command="$base_compile $qsrcfile$pie_flag" else command="$base_compile $qsrcfile $pic_flag" fi if test "$compiler_c_o" = yes; then func_append command " -o $obj" fi # Suppress compiler output if we already did a PIC compilation. func_append command "$suppress_output" func_show_eval_locale "$command" \ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' if test "$need_locks" = warn && test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then $ECHO "\ *** ERROR, $lockfile contains: `cat $lockfile 2>/dev/null` but it should contain: $srcfile This indicates that another process is trying to use the same temporary object file, and libtool could not work around it because your compiler does not support \`-c' and \`-o' together. If you repeat this compilation, it may succeed, by chance, but you had better avoid parallel builds (make -j) in this platform, or get a better compiler." $opt_dry_run || $RM $removelist exit $EXIT_FAILURE fi # Just move the object if needed if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then func_show_eval '$MV "$output_obj" "$obj"' \ 'error=$?; $opt_dry_run || $RM $removelist; exit $error' fi fi $opt_dry_run || { func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" # Unlock the critical section if it was locked if test "$need_locks" != no; then removelist=$lockfile $RM "$lockfile" fi } exit $EXIT_SUCCESS } $opt_help || { test "$opt_mode" = compile && func_mode_compile ${1+"$@"} } func_mode_help () { # We need to display help for each of the modes. case $opt_mode in "") # Generic help is extracted from the usage comments # at the start of this file. func_help ;; clean) $ECHO \ "Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... Remove files from the build directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, object or program, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; compile) $ECHO \ "Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE Compile a source file into a libtool library object. This mode accepts the following additional options: -o OUTPUT-FILE set the output file name to OUTPUT-FILE -no-suppress do not suppress compiler output for multiple passes -prefer-pic try to build PIC objects only -prefer-non-pic try to build non-PIC objects only -shared do not build a \`.o' file suitable for static linking -static only build a \`.o' file suitable for static linking -Wc,FLAG pass FLAG directly to the compiler COMPILE-COMMAND is a command to be used in creating a \`standard' object file from the given SOURCEFILE. The output file name is determined by removing the directory component from SOURCEFILE, then substituting the C source code suffix \`.c' with the library object suffix, \`.lo'." ;; execute) $ECHO \ "Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... Automatically set library path, then run a program. This mode accepts the following additional options: -dlopen FILE add the directory containing FILE to the library path This mode sets the library path environment variable according to \`-dlopen' flags. If any of the ARGS are libtool executable wrappers, then they are translated into their corresponding uninstalled binary, and any of their required library directories are added to the library path. Then, COMMAND is executed, with ARGS as arguments." ;; finish) $ECHO \ "Usage: $progname [OPTION]... --mode=finish [LIBDIR]... Complete the installation of libtool libraries. Each LIBDIR is a directory that contains libtool libraries. The commands that this mode executes may require superuser privileges. Use the \`--dry-run' option if you just want to see what would be executed." ;; install) $ECHO \ "Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... Install executables or libraries. INSTALL-COMMAND is the installation command. The first component should be either the \`install' or \`cp' program. The following components of INSTALL-COMMAND are treated specially: -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation The rest of the components are interpreted as arguments to that command (only BSD-compatible install options are recognized)." ;; link) $ECHO \ "Usage: $progname [OPTION]... --mode=link LINK-COMMAND... Link object files or libraries together to form another library, or to create an executable program. LINK-COMMAND is a command using the C compiler that you would use to create a program from several object files. The following components of LINK-COMMAND are treated specially: -all-static do not do any dynamic linking at all -avoid-version do not add a version suffix if possible -bindir BINDIR specify path to binaries directory (for systems where libraries must be found in the PATH setting at runtime) -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) -export-symbols SYMFILE try to export only the symbols listed in SYMFILE -export-symbols-regex REGEX try to export only the symbols matching REGEX -LLIBDIR search LIBDIR for required installed libraries -lNAME OUTPUT-FILE requires the installed library libNAME -module build a library that can dlopened -no-fast-install disable the fast-install mode -no-install link a not-installable executable -no-undefined declare that a library does not refer to external symbols -o OUTPUT-FILE create OUTPUT-FILE from the specified objects -objectlist FILE Use a list of object files found in FILE to specify objects -precious-files-regex REGEX don't remove output files matching REGEX -release RELEASE specify package release information -rpath LIBDIR the created library will eventually be installed in LIBDIR -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries -shared only do dynamic linking of libtool libraries -shrext SUFFIX override the standard shared library file extension -static do not do any dynamic linking of uninstalled libtool libraries -static-libtool-libs do not do any dynamic linking of libtool libraries -version-info CURRENT[:REVISION[:AGE]] specify library version info [each variable defaults to 0] -weak LIBNAME declare that the target provides the LIBNAME interface -Wc,FLAG -Xcompiler FLAG pass linker-specific FLAG directly to the compiler -Wl,FLAG -Xlinker FLAG pass linker-specific FLAG directly to the linker -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) All other options (arguments beginning with \`-') are ignored. Every other argument is treated as a filename. Files ending in \`.la' are treated as uninstalled libtool libraries, other files are standard or library object files. If the OUTPUT-FILE ends in \`.la', then a libtool library is created, only library objects (\`.lo' files) may be specified, and \`-rpath' is required, except when creating a convenience library. If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created using \`ar' and \`ranlib', or on Windows using \`lib'. If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file is created, otherwise an executable program is created." ;; uninstall) $ECHO \ "Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... Remove libraries from an installation directory. RM is the name of the program to use to delete files associated with each FILE (typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed to RM. If FILE is a libtool library, all the files associated with it are deleted. Otherwise, only FILE itself is deleted using RM." ;; *) func_fatal_help "invalid operation mode \`$opt_mode'" ;; esac echo $ECHO "Try \`$progname --help' for more information about other modes." } # Now that we've collected a possible --mode arg, show help if necessary if $opt_help; then if test "$opt_help" = :; then func_mode_help else { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do func_mode_help done } | sed -n '1p; 2,$s/^Usage:/ or: /p' { func_help noexit for opt_mode in compile link execute install finish uninstall clean; do echo func_mode_help done } | sed '1d /^When reporting/,/^Report/{ H d } $x /information about other modes/d /more detailed .*MODE/d s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' fi exit $? fi # func_mode_execute arg... func_mode_execute () { $opt_debug # The first argument is the command name. cmd="$nonopt" test -z "$cmd" && \ func_fatal_help "you must specify a COMMAND" # Handle -dlopen flags immediately. for file in $opt_dlopen; do test -f "$file" \ || func_fatal_help "\`$file' is not a file" dir= case $file in *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$lib' is not a valid libtool archive" # Read the libtool library. dlname= library_names= func_source "$file" # Skip this library if it cannot be dlopened. if test -z "$dlname"; then # Warn if it was a shared library. test -n "$library_names" && \ func_warning "\`$file' was not linked with \`-export-dynamic'" continue fi func_dirname "$file" "" "." dir="$func_dirname_result" if test -f "$dir/$objdir/$dlname"; then func_append dir "/$objdir" else if test ! -f "$dir/$dlname"; then func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" fi fi ;; *.lo) # Just add the directory containing the .lo file. func_dirname "$file" "" "." dir="$func_dirname_result" ;; *) func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" continue ;; esac # Get the absolute pathname. absdir=`cd "$dir" && pwd` test -n "$absdir" && dir="$absdir" # Now add the directory to shlibpath_var. if eval "test -z \"\$$shlibpath_var\""; then eval "$shlibpath_var=\"\$dir\"" else eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" fi done # This variable tells wrapper scripts just to set shlibpath_var # rather than running their programs. libtool_execute_magic="$magic" # Check if any of the arguments is a wrapper script. args= for file do case $file in -* | *.la | *.lo ) ;; *) # Do a test to see if this is really a libtool program. if func_ltwrapper_script_p "$file"; then func_source "$file" # Transform arg to wrapped name. file="$progdir/$program" elif func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" func_source "$func_ltwrapper_scriptname_result" # Transform arg to wrapped name. file="$progdir/$program" fi ;; esac # Quote arguments (to preserve shell metacharacters). func_append_quoted args "$file" done if test "X$opt_dry_run" = Xfalse; then if test -n "$shlibpath_var"; then # Export the shlibpath_var. eval "export $shlibpath_var" fi # Restore saved environment variables for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES do eval "if test \"\${save_$lt_var+set}\" = set; then $lt_var=\$save_$lt_var; export $lt_var else $lt_unset $lt_var fi" done # Now prepare to actually exec the command. exec_cmd="\$cmd$args" else # Display what would be done. if test -n "$shlibpath_var"; then eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" echo "export $shlibpath_var" fi $ECHO "$cmd$args" exit $EXIT_SUCCESS fi } test "$opt_mode" = execute && func_mode_execute ${1+"$@"} # func_mode_finish arg... func_mode_finish () { $opt_debug libs= libdirs= admincmds= for opt in "$nonopt" ${1+"$@"} do if test -d "$opt"; then func_append libdirs " $opt" elif test -f "$opt"; then if func_lalib_unsafe_p "$opt"; then func_append libs " $opt" else func_warning "\`$opt' is not a valid libtool archive" fi else func_fatal_error "invalid argument \`$opt'" fi done if test -n "$libs"; then if test -n "$lt_sysroot"; then sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" else sysroot_cmd= fi # Remove sysroot references if $opt_dry_run; then for lib in $libs; do echo "removing references to $lt_sysroot and \`=' prefixes from $lib" done else tmpdir=`func_mktempdir` for lib in $libs; do sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ > $tmpdir/tmp-la mv -f $tmpdir/tmp-la $lib done ${RM}r "$tmpdir" fi fi if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then for libdir in $libdirs; do if test -n "$finish_cmds"; then # Do each command in the finish commands. func_execute_cmds "$finish_cmds" 'admincmds="$admincmds '"$cmd"'"' fi if test -n "$finish_eval"; then # Do the single finish_eval. eval cmds=\"$finish_eval\" $opt_dry_run || eval "$cmds" || func_append admincmds " $cmds" fi done fi # Exit here if they wanted silent mode. $opt_silent && exit $EXIT_SUCCESS if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then echo "----------------------------------------------------------------------" echo "Libraries have been installed in:" for libdir in $libdirs; do $ECHO " $libdir" done echo echo "If you ever happen to want to link against installed libraries" echo "in a given directory, LIBDIR, you must either use libtool, and" echo "specify the full pathname of the library, or use the \`-LLIBDIR'" echo "flag during linking and do at least one of the following:" if test -n "$shlibpath_var"; then echo " - add LIBDIR to the \`$shlibpath_var' environment variable" echo " during execution" fi if test -n "$runpath_var"; then echo " - add LIBDIR to the \`$runpath_var' environment variable" echo " during linking" fi if test -n "$hardcode_libdir_flag_spec"; then libdir=LIBDIR eval flag=\"$hardcode_libdir_flag_spec\" $ECHO " - use the \`$flag' linker flag" fi if test -n "$admincmds"; then $ECHO " - have your system administrator run these commands:$admincmds" fi if test -f /etc/ld.so.conf; then echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" fi echo echo "See any operating system documentation about shared libraries for" case $host in solaris2.[6789]|solaris2.1[0-9]) echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" echo "pages." ;; *) echo "more information, such as the ld(1) and ld.so(8) manual pages." ;; esac echo "----------------------------------------------------------------------" fi exit $EXIT_SUCCESS } test "$opt_mode" = finish && func_mode_finish ${1+"$@"} # func_mode_install arg... func_mode_install () { $opt_debug # There may be an optional sh(1) argument at the beginning of # install_prog (especially on Windows NT). if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || # Allow the use of GNU shtool's install command. case $nonopt in *shtool*) :;; *) false;; esac; then # Aesthetically quote it. func_quote_for_eval "$nonopt" install_prog="$func_quote_for_eval_result " arg=$1 shift else install_prog= arg=$nonopt fi # The real first argument should be the name of the installation program. # Aesthetically quote it. func_quote_for_eval "$arg" func_append install_prog "$func_quote_for_eval_result" install_shared_prog=$install_prog case " $install_prog " in *[\\\ /]cp\ *) install_cp=: ;; *) install_cp=false ;; esac # We need to accept at least all the BSD install flags. dest= files= opts= prev= install_type= isdir=no stripme= no_mode=: for arg do arg2= if test -n "$dest"; then func_append files " $dest" dest=$arg continue fi case $arg in -d) isdir=yes ;; -f) if $install_cp; then :; else prev=$arg fi ;; -g | -m | -o) prev=$arg ;; -s) stripme=" -s" continue ;; -*) ;; *) # If the previous option needed an argument, then skip it. if test -n "$prev"; then if test "x$prev" = x-m && test -n "$install_override_mode"; then arg2=$install_override_mode no_mode=false fi prev= else dest=$arg continue fi ;; esac # Aesthetically quote the argument. func_quote_for_eval "$arg" func_append install_prog " $func_quote_for_eval_result" if test -n "$arg2"; then func_quote_for_eval "$arg2" fi func_append install_shared_prog " $func_quote_for_eval_result" done test -z "$install_prog" && \ func_fatal_help "you must specify an install program" test -n "$prev" && \ func_fatal_help "the \`$prev' option requires an argument" if test -n "$install_override_mode" && $no_mode; then if $install_cp; then :; else func_quote_for_eval "$install_override_mode" func_append install_shared_prog " -m $func_quote_for_eval_result" fi fi if test -z "$files"; then if test -z "$dest"; then func_fatal_help "no file or destination specified" else func_fatal_help "you must specify a destination" fi fi # Strip any trailing slash from the destination. func_stripname '' '/' "$dest" dest=$func_stripname_result # Check to see that the destination is a directory. test -d "$dest" && isdir=yes if test "$isdir" = yes; then destdir="$dest" destname= else func_dirname_and_basename "$dest" "" "." destdir="$func_dirname_result" destname="$func_basename_result" # Not a directory, so check to see that there is only one file specified. set dummy $files; shift test "$#" -gt 1 && \ func_fatal_help "\`$dest' is not a directory" fi case $destdir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) for file in $files; do case $file in *.lo) ;; *) func_fatal_help "\`$destdir' must be an absolute directory name" ;; esac done ;; esac # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" staticlibs= future_libdirs= current_libdirs= for file in $files; do # Do each installation. case $file in *.$libext) # Do the static libraries later. func_append staticlibs " $file" ;; *.la) func_resolve_sysroot "$file" file=$func_resolve_sysroot_result # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$file" \ || func_fatal_help "\`$file' is not a valid libtool archive" library_names= old_library= relink_command= func_source "$file" # Add the libdir to current_libdirs if it is the destination. if test "X$destdir" = "X$libdir"; then case "$current_libdirs " in *" $libdir "*) ;; *) func_append current_libdirs " $libdir" ;; esac else # Note the libdir as a future libdir. case "$future_libdirs " in *" $libdir "*) ;; *) func_append future_libdirs " $libdir" ;; esac fi func_dirname "$file" "/" "" dir="$func_dirname_result" func_append dir "$objdir" if test -n "$relink_command"; then # Determine the prefix the user has applied to our future dir. inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` # Don't allow the user to place us outside of our expected # location b/c this prevents finding dependent libraries that # are installed to the same prefix. # At present, this check doesn't affect windows .dll's that # are installed into $libdir/../bin (currently, that works fine) # but it's something to keep an eye on. test "$inst_prefix_dir" = "$destdir" && \ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" if test -n "$inst_prefix_dir"; then # Stick the inst_prefix_dir data into the link command. relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` else relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` fi func_warning "relinking \`$file'" func_show_eval "$relink_command" \ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' fi # See the names of the shared library. set dummy $library_names; shift if test -n "$1"; then realname="$1" shift srcname="$realname" test -n "$relink_command" && srcname="$realname"T # Install the shared library and build the symlinks. func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ 'exit $?' tstripme="$stripme" case $host_os in cygwin* | mingw* | pw32* | cegcc*) case $realname in *.dll.a) tstripme="" ;; esac ;; esac if test -n "$tstripme" && test -n "$striplib"; then func_show_eval "$striplib $destdir/$realname" 'exit $?' fi if test "$#" -gt 0; then # Delete the old symlinks, and create new ones. # Try `ln -sf' first, because the `ln' binary might depend on # the symlink we replace! Solaris /bin/ln does not understand -f, # so we also need to try rm && ln -s. for linkname do test "$linkname" != "$realname" \ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" done fi # Do each command in the postinstall commands. lib="$destdir/$realname" func_execute_cmds "$postinstall_cmds" 'exit $?' fi # Install the pseudo-library for information purposes. func_basename "$file" name="$func_basename_result" instname="$dir/$name"i func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' # Maybe install the static library, too. test -n "$old_library" && func_append staticlibs " $dir/$old_library" ;; *.lo) # Install (i.e. copy) a libtool object. # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # Deduce the name of the destination old-style object file. case $destfile in *.lo) func_lo2o "$destfile" staticdest=$func_lo2o_result ;; *.$objext) staticdest="$destfile" destfile= ;; *) func_fatal_help "cannot copy a libtool object to \`$destfile'" ;; esac # Install the libtool object if requested. test -n "$destfile" && \ func_show_eval "$install_prog $file $destfile" 'exit $?' # Install the old object if enabled. if test "$build_old_libs" = yes; then # Deduce the name of the old-style object file. func_lo2o "$file" staticobj=$func_lo2o_result func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' fi exit $EXIT_SUCCESS ;; *) # Figure out destination file name, if it wasn't already specified. if test -n "$destname"; then destfile="$destdir/$destname" else func_basename "$file" destfile="$func_basename_result" destfile="$destdir/$destfile" fi # If the file is missing, and there is a .exe on the end, strip it # because it is most likely a libtool script we actually want to # install stripped_ext="" case $file in *.exe) if test ! -f "$file"; then func_stripname '' '.exe' "$file" file=$func_stripname_result stripped_ext=".exe" fi ;; esac # Do a test to see if this is really a libtool program. case $host in *cygwin* | *mingw*) if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" wrapper=$func_ltwrapper_scriptname_result else func_stripname '' '.exe' "$file" wrapper=$func_stripname_result fi ;; *) wrapper=$file ;; esac if func_ltwrapper_script_p "$wrapper"; then notinst_deplibs= relink_command= func_source "$wrapper" # Check the variables that should have been set. test -z "$generated_by_libtool_version" && \ func_fatal_error "invalid libtool wrapper script \`$wrapper'" finalize=yes for lib in $notinst_deplibs; do # Check to see that each library is installed. libdir= if test -f "$lib"; then func_source "$lib" fi libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test if test -n "$libdir" && test ! -f "$libfile"; then func_warning "\`$lib' has not been installed in \`$libdir'" finalize=no fi done relink_command= func_source "$wrapper" outputname= if test "$fast_install" = no && test -n "$relink_command"; then $opt_dry_run || { if test "$finalize" = yes; then tmpdir=`func_mktempdir` func_basename "$file$stripped_ext" file="$func_basename_result" outputname="$tmpdir/$file" # Replace the output file specification. relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` $opt_silent || { func_quote_for_expand "$relink_command" eval "func_echo $func_quote_for_expand_result" } if eval "$relink_command"; then : else func_error "error: relink \`$file' with the above command before installing it" $opt_dry_run || ${RM}r "$tmpdir" continue fi file="$outputname" else func_warning "cannot relink \`$file'" fi } else # Install the binary that we compiled earlier. file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` fi fi # remove .exe since cygwin /usr/bin/install will append another # one anyway case $install_prog,$host in */usr/bin/install*,*cygwin*) case $file:$destfile in *.exe:*.exe) # this is ok ;; *.exe:*) destfile=$destfile.exe ;; *:*.exe) func_stripname '' '.exe' "$destfile" destfile=$func_stripname_result ;; esac ;; esac func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' $opt_dry_run || if test -n "$outputname"; then ${RM}r "$tmpdir" fi ;; esac done for file in $staticlibs; do func_basename "$file" name="$func_basename_result" # Set up the ranlib parameters. oldlib="$destdir/$name" func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result func_show_eval "$install_prog \$file \$oldlib" 'exit $?' if test -n "$stripme" && test -n "$old_striplib"; then func_show_eval "$old_striplib $tool_oldlib" 'exit $?' fi # Do each command in the postinstall commands. func_execute_cmds "$old_postinstall_cmds" 'exit $?' done test -n "$future_libdirs" && \ func_warning "remember to run \`$progname --finish$future_libdirs'" if test -n "$current_libdirs"; then # Maybe just do a dry run. $opt_dry_run && current_libdirs=" -n$current_libdirs" exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' else exit $EXIT_SUCCESS fi } test "$opt_mode" = install && func_mode_install ${1+"$@"} # func_generate_dlsyms outputname originator pic_p # Extract symbols from dlprefiles and create ${outputname}S.o with # a dlpreopen symbol table. func_generate_dlsyms () { $opt_debug my_outputname="$1" my_originator="$2" my_pic_p="${3-no}" my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` my_dlsyms= if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then if test -n "$NM" && test -n "$global_symbol_pipe"; then my_dlsyms="${my_outputname}S.c" else func_error "not configured to extract global symbols from dlpreopened files" fi fi if test -n "$my_dlsyms"; then case $my_dlsyms in "") ;; *.c) # Discover the nlist of each of the dlfiles. nlist="$output_objdir/${my_outputname}.nm" func_show_eval "$RM $nlist ${nlist}S ${nlist}T" # Parse the name list into a source file. func_verbose "creating $output_objdir/$my_dlsyms" $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ /* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ /* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ #ifdef __cplusplus extern \"C\" { #endif #if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) #pragma GCC diagnostic ignored \"-Wstrict-prototypes\" #endif /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif /* External symbol declarations for the compiler. */\ " if test "$dlself" = yes; then func_verbose "generating symbol list for \`$output'" $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" # Add our own program objects to the symbol list. progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` for progfile in $progfiles; do func_to_tool_file "$progfile" func_convert_file_msys_to_w32 func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" done if test -n "$exclude_expsyms"; then $opt_dry_run || { eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi if test -n "$export_symbols_regex"; then $opt_dry_run || { eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' } fi # Prepare the list of exported symbols if test -z "$export_symbols"; then export_symbols="$output_objdir/$outputname.exp" $opt_dry_run || { $RM $export_symbols eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' ;; esac } else $opt_dry_run || { eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' eval '$MV "$nlist"T "$nlist"' case $host in *cygwin* | *mingw* | *cegcc* ) eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' ;; esac } fi fi for dlprefile in $dlprefiles; do func_verbose "extracting global C symbols from \`$dlprefile'" func_basename "$dlprefile" name="$func_basename_result" case $host in *cygwin* | *mingw* | *cegcc* ) # if an import library, we need to obtain dlname if func_win32_import_lib_p "$dlprefile"; then func_tr_sh "$dlprefile" eval "curr_lafile=\$libfile_$func_tr_sh_result" dlprefile_dlbasename="" if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then # Use subshell, to avoid clobbering current variable values dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` if test -n "$dlprefile_dlname" ; then func_basename "$dlprefile_dlname" dlprefile_dlbasename="$func_basename_result" else # no lafile. user explicitly requested -dlpreopen . $sharedlib_from_linklib_cmd "$dlprefile" dlprefile_dlbasename=$sharedlib_from_linklib_result fi fi $opt_dry_run || { if test -n "$dlprefile_dlbasename" ; then eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' else func_warning "Could not compute DLL name from $name" eval '$ECHO ": $name " >> "$nlist"' fi func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" } else # not an import lib $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } fi ;; *) $opt_dry_run || { eval '$ECHO ": $name " >> "$nlist"' func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" } ;; esac done $opt_dry_run || { # Make sure we have at least an empty file. test -f "$nlist" || : > "$nlist" if test -n "$exclude_expsyms"; then $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T $MV "$nlist"T "$nlist" fi # Try sorting and uniquifying the output. if $GREP -v "^: " < "$nlist" | if sort -k 3 /dev/null 2>&1; then sort -k 3 else sort +2 fi | uniq > "$nlist"S; then : else $GREP -v "^: " < "$nlist" > "$nlist"S fi if test -f "$nlist"S; then eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' else echo '/* NONE */' >> "$output_objdir/$my_dlsyms" fi echo >> "$output_objdir/$my_dlsyms" "\ /* The mapping between symbol names and symbols. */ typedef struct { const char *name; void *address; } lt_dlsymlist; extern LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[]; LT_DLSYM_CONST lt_dlsymlist lt_${my_prefix}_LTX_preloaded_symbols[] = {\ { \"$my_originator\", (void *) 0 }," case $need_lib_prefix in no) eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; *) eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" ;; esac echo >> "$output_objdir/$my_dlsyms" "\ {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt_${my_prefix}_LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif\ " } # !$opt_dry_run pic_flag_for_symtable= case "$compile_command " in *" -static "*) ;; *) case $host in # compiling the symbol table file with pic_flag works around # a FreeBSD bug that causes programs to crash when -lm is # linked before any other PIC object. But we must not use # pic_flag when linking with -static. The problem exists in # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; *-*-hpux*) pic_flag_for_symtable=" $pic_flag" ;; *) if test "X$my_pic_p" != Xno; then pic_flag_for_symtable=" $pic_flag" fi ;; esac ;; esac symtab_cflags= for arg in $LTCFLAGS; do case $arg in -pie | -fpie | -fPIE) ;; *) func_append symtab_cflags " $arg" ;; esac done # Now compile the dynamic symbol file. func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' # Clean up the generated files. func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' # Transform the symbol file into the correct name. symfileobj="$output_objdir/${my_outputname}S.$objext" case $host in *cygwin* | *mingw* | *cegcc* ) if test -f "$output_objdir/$my_outputname.def"; then compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` else compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` fi ;; *) compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` ;; esac ;; *) func_fatal_error "unknown suffix for \`$my_dlsyms'" ;; esac else # We keep going just in case the user didn't refer to # lt_preloaded_symbols. The linker will fail if global_symbol_pipe # really was required. # Nullify the symbol file. compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` fi } # func_win32_libid arg # return the library type of file 'arg' # # Need a lot of goo to handle *both* DLLs and import libs # Has to be a shell function in order to 'eat' the argument # that is supplied when $file_magic_command is called. # Despite the name, also deal with 64 bit binaries. func_win32_libid () { $opt_debug win32_libid_type="unknown" win32_fileres=`file -L $1 2>/dev/null` case $win32_fileres in *ar\ archive\ import\ library*) # definitely import win32_libid_type="x86 archive import" ;; *ar\ archive*) # could be an import, or static # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then func_to_tool_file "$1" func_convert_file_msys_to_w32 win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | $SED -n -e ' 1,100{ / I /{ s,.*,import, p q } }'` case $win32_nmres in import*) win32_libid_type="x86 archive import";; *) win32_libid_type="x86 archive static";; esac fi ;; *DLL*) win32_libid_type="x86 DLL" ;; *executable*) # but shell scripts are "executable" too... case $win32_fileres in *MS\ Windows\ PE\ Intel*) win32_libid_type="x86 DLL" ;; esac ;; esac $ECHO "$win32_libid_type" } # func_cygming_dll_for_implib ARG # # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib () { $opt_debug sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` } # func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs # # The is the core of a fallback implementation of a # platform-specific function to extract the name of the # DLL associated with the specified import library LIBNAME. # # SECTION_NAME is either .idata$6 or .idata$7, depending # on the platform and compiler that created the implib. # # Echos the name of the DLL associated with the # specified import library. func_cygming_dll_for_implib_fallback_core () { $opt_debug match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` $OBJDUMP -s --section "$1" "$2" 2>/dev/null | $SED '/^Contents of section '"$match_literal"':/{ # Place marker at beginning of archive member dllname section s/.*/====MARK====/ p d } # These lines can sometimes be longer than 43 characters, but # are always uninteresting /:[ ]*file format pe[i]\{,1\}-/d /^In archive [^:]*:/d # Ensure marker is printed /^====MARK====/p # Remove all lines with less than 43 characters /^.\{43\}/!d # From remaining lines, remove first 43 characters s/^.\{43\}//' | $SED -n ' # Join marker and all lines until next marker into a single line /^====MARK====/ b para H $ b para b :para x s/\n//g # Remove the marker s/^====MARK====// # Remove trailing dots and whitespace s/[\. \t]*$// # Print /./p' | # we now have a list, one entry per line, of the stringified # contents of the appropriate section of all members of the # archive which possess that section. Heuristic: eliminate # all those which have a first or second character that is # a '.' (that is, objdump's representation of an unprintable # character.) This should work for all archives with less than # 0x302f exports -- but will fail for DLLs whose name actually # begins with a literal '.' or a single character followed by # a '.'. # # Of those that remain, print the first one. $SED -e '/^\./d;/^.\./d;q' } # func_cygming_gnu_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is a GNU/binutils-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_gnu_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` test -n "$func_cygming_gnu_implib_tmp" } # func_cygming_ms_implib_p ARG # This predicate returns with zero status (TRUE) if # ARG is an MS-style import library. Returns # with nonzero status (FALSE) otherwise. func_cygming_ms_implib_p () { $opt_debug func_to_tool_file "$1" func_convert_file_msys_to_w32 func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` test -n "$func_cygming_ms_implib_tmp" } # func_cygming_dll_for_implib_fallback ARG # Platform-specific function to extract the # name of the DLL associated with the specified # import library ARG. # # This fallback implementation is for use when $DLLTOOL # does not support the --identify-strict option. # Invoked by eval'ing the libtool variable # $sharedlib_from_linklib_cmd # Result is available in the variable # $sharedlib_from_linklib_result func_cygming_dll_for_implib_fallback () { $opt_debug if func_cygming_gnu_implib_p "$1" ; then # binutils import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` elif func_cygming_ms_implib_p "$1" ; then # ms-generated import library sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` else # unknown sharedlib_from_linklib_result="" fi } # func_extract_an_archive dir oldlib func_extract_an_archive () { $opt_debug f_ex_an_ar_dir="$1"; shift f_ex_an_ar_oldlib="$1" if test "$lock_old_archive_extraction" = yes; then lockfile=$f_ex_an_ar_oldlib.lock until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do func_echo "Waiting for $lockfile to be removed" sleep 2 done fi func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ 'stat=$?; rm -f "$lockfile"; exit $stat' if test "$lock_old_archive_extraction" = yes; then $opt_dry_run || rm -f "$lockfile" fi if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then : else func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" fi } # func_extract_archives gentop oldlib ... func_extract_archives () { $opt_debug my_gentop="$1"; shift my_oldlibs=${1+"$@"} my_oldobjs="" my_xlib="" my_xabs="" my_xdir="" for my_xlib in $my_oldlibs; do # Extract the objects. case $my_xlib in [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; *) my_xabs=`pwd`"/$my_xlib" ;; esac func_basename "$my_xlib" my_xlib="$func_basename_result" my_xlib_u=$my_xlib while :; do case " $extracted_archives " in *" $my_xlib_u "*) func_arith $extracted_serial + 1 extracted_serial=$func_arith_result my_xlib_u=lt$extracted_serial-$my_xlib ;; *) break ;; esac done extracted_archives="$extracted_archives $my_xlib_u" my_xdir="$my_gentop/$my_xlib_u" func_mkdir_p "$my_xdir" case $host in *-darwin*) func_verbose "Extracting $my_xabs" # Do not bother doing anything if just a dry run $opt_dry_run || { darwin_orig_dir=`pwd` cd $my_xdir || exit $? darwin_archive=$my_xabs darwin_curdir=`pwd` darwin_base_archive=`basename "$darwin_archive"` darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` if test -n "$darwin_arches"; then darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` darwin_arch= func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" for darwin_arch in $darwin_arches ; do func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" func_extract_an_archive "`pwd`" "${darwin_base_archive}" cd "$darwin_curdir" $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" done # $darwin_arches ## Okay now we've a bunch of thin objects, gotta fatten them up :) darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` darwin_file= darwin_files= for darwin_file in $darwin_filelist; do darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` $LIPO -create -output "$darwin_file" $darwin_files done # $darwin_filelist $RM -rf unfat-$$ cd "$darwin_orig_dir" else cd $darwin_orig_dir func_extract_an_archive "$my_xdir" "$my_xabs" fi # $darwin_arches } # !$opt_dry_run ;; *) func_extract_an_archive "$my_xdir" "$my_xabs" ;; esac my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` done func_extract_archives_result="$my_oldobjs" } # func_emit_wrapper [arg=no] # # Emit a libtool wrapper script on stdout. # Don't directly open a file because we may want to # incorporate the script contents within a cygwin/mingw # wrapper executable. Must ONLY be called from within # func_mode_link because it depends on a number of variables # set therein. # # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR # variable will take. If 'yes', then the emitted script # will assume that the directory in which it is stored is # the $objdir directory. This is a cygwin/mingw-specific # behavior. func_emit_wrapper () { func_emit_wrapper_arg1=${1-no} $ECHO "\ #! $SHELL # $output - temporary wrapper script for $objdir/$outputname # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # The $output program cannot be directly executed until all the libtool # libraries that it depends on are installed. # # This wrapper script should never be moved out of the build directory. # If it is, it will not operate correctly. # Sed substitution that helps us do robust quoting. It backslashifies # metacharacters that are still active within double-quoted strings. sed_quote_subst='$sed_quote_subst' # Be Bourne compatible if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac fi BIN_SH=xpg4; export BIN_SH # for Tru64 DUALCASE=1; export DUALCASE # for MKS sh # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH relink_command=\"$relink_command\" # This environment variable determines our operation mode. if test \"\$libtool_install_magic\" = \"$magic\"; then # install mode needs the following variables: generated_by_libtool_version='$macro_version' notinst_deplibs='$notinst_deplibs' else # When we are sourced in execute mode, \$file and \$ECHO are already set. if test \"\$libtool_execute_magic\" != \"$magic\"; then file=\"\$0\"" qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` $ECHO "\ # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } ECHO=\"$qECHO\" fi # Very basic option parsing. These options are (a) specific to # the libtool wrapper, (b) are identical between the wrapper # /script/ and the wrapper /executable/ which is used only on # windows platforms, and (c) all begin with the string "--lt-" # (application programs are unlikely to have options which match # this pattern). # # There are only two supported options: --lt-debug and # --lt-dump-script. There is, deliberately, no --lt-help. # # The first argument to this parsing function should be the # script's $0 value, followed by "$@". lt_option_debug= func_parse_lt_options () { lt_script_arg0=\$0 shift for lt_opt do case \"\$lt_opt\" in --lt-debug) lt_option_debug=1 ;; --lt-dump-script) lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` cat \"\$lt_dump_D/\$lt_dump_F\" exit 0 ;; --lt-*) \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 exit 1 ;; esac done # Print the debug banner immediately: if test -n \"\$lt_option_debug\"; then echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 fi } # Used when --lt-debug. Prints its arguments to stdout # (redirection is the responsibility of the caller) func_lt_dump_args () { lt_dump_args_N=1; for lt_arg do \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` done } # Core function for launching the target application func_exec_program_core () { " case $host in # Backslashes separate directories on plain windows *-*-mingw | *-*-os2* | *-cegcc*) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} " ;; *) $ECHO "\ if test -n \"\$lt_option_debug\"; then \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 func_lt_dump_args \${1+\"\$@\"} 1>&2 fi exec \"\$progdir/\$program\" \${1+\"\$@\"} " ;; esac $ECHO "\ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 exit 1 } # A function to encapsulate launching the target application # Strips options in the --lt-* namespace from \$@ and # launches target application with the remaining arguments. func_exec_program () { case \" \$* \" in *\\ --lt-*) for lt_wr_arg do case \$lt_wr_arg in --lt-*) ;; *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; esac shift done ;; esac func_exec_program_core \${1+\"\$@\"} } # Parse options func_parse_lt_options \"\$0\" \${1+\"\$@\"} # Find the directory that this script lives in. thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` test \"x\$thisdir\" = \"x\$file\" && thisdir=. # Follow symbolic links until we get to the real thisdir. file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` while test -n \"\$file\"; do destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` # If there was a directory component, then change thisdir. if test \"x\$destdir\" != \"x\$file\"; then case \"\$destdir\" in [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; *) thisdir=\"\$thisdir/\$destdir\" ;; esac fi file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` done # Usually 'no', except on cygwin/mingw when embedded into # the cwrapper. WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then # special case for '.' if test \"\$thisdir\" = \".\"; then thisdir=\`pwd\` fi # remove .libs from thisdir case \"\$thisdir\" in *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; $objdir ) thisdir=. ;; esac fi # Try to get the absolute directory name. absdir=\`cd \"\$thisdir\" && pwd\` test -n \"\$absdir\" && thisdir=\"\$absdir\" " if test "$fast_install" = yes; then $ECHO "\ program=lt-'$outputname'$exeext progdir=\"\$thisdir/$objdir\" if test ! -f \"\$progdir/\$program\" || { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ test \"X\$file\" != \"X\$progdir/\$program\"; }; then file=\"\$\$-\$program\" if test ! -d \"\$progdir\"; then $MKDIR \"\$progdir\" else $RM \"\$progdir/\$file\" fi" $ECHO "\ # relink executable if necessary if test -n \"\$relink_command\"; then if relink_command_output=\`eval \$relink_command 2>&1\`; then : else $ECHO \"\$relink_command_output\" >&2 $RM \"\$progdir/\$file\" exit 1 fi fi $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || { $RM \"\$progdir/\$program\"; $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } $RM \"\$progdir/\$file\" fi" else $ECHO "\ program='$outputname' progdir=\"\$thisdir/$objdir\" " fi $ECHO "\ if test -f \"\$progdir/\$program\"; then" # fixup the dll searchpath if we need to. # # Fix the DLL searchpath if we need to. Do this before prepending # to shlibpath, because on Windows, both are PATH and uninstalled # libraries must come first. if test -n "$dllsearchpath"; then $ECHO "\ # Add the dll search path components to the executable PATH PATH=$dllsearchpath:\$PATH " fi # Export our shlibpath_var if we have one. if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then $ECHO "\ # Add our own library path to $shlibpath_var $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" # Some systems cannot cope with colon-terminated $shlibpath_var # The second colon is a workaround for a bug in BeOS R4 sed $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` export $shlibpath_var " fi $ECHO "\ if test \"\$libtool_execute_magic\" != \"$magic\"; then # Run the actual program with our arguments. func_exec_program \${1+\"\$@\"} fi else # The program doesn't exist. \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 exit 1 fi fi\ " } # func_emit_cwrapperexe_src # emit the source code for a wrapper executable on stdout # Must ONLY be called from within func_mode_link because # it depends on a number of variable set therein. func_emit_cwrapperexe_src () { cat < #include #ifdef _MSC_VER # include # include # include #else # include # include # ifdef __CYGWIN__ # include # endif #endif #include #include #include #include #include #include #include #include /* declarations of non-ANSI functions */ #if defined(__MINGW32__) # ifdef __STRICT_ANSI__ int _putenv (const char *); # endif #elif defined(__CYGWIN__) # ifdef __STRICT_ANSI__ char *realpath (const char *, char *); int putenv (char *); int setenv (const char *, const char *, int); # endif /* #elif defined (other platforms) ... */ #endif /* portability defines, excluding path handling macros */ #if defined(_MSC_VER) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv # define S_IXUSR _S_IEXEC # ifndef _INTPTR_T_DEFINED # define _INTPTR_T_DEFINED # define intptr_t int # endif #elif defined(__MINGW32__) # define setmode _setmode # define stat _stat # define chmod _chmod # define getcwd _getcwd # define putenv _putenv #elif defined(__CYGWIN__) # define HAVE_SETENV # define FOPEN_WB "wb" /* #elif defined (other platforms) ... */ #endif #if defined(PATH_MAX) # define LT_PATHMAX PATH_MAX #elif defined(MAXPATHLEN) # define LT_PATHMAX MAXPATHLEN #else # define LT_PATHMAX 1024 #endif #ifndef S_IXOTH # define S_IXOTH 0 #endif #ifndef S_IXGRP # define S_IXGRP 0 #endif /* path handling portability macros */ #ifndef DIR_SEPARATOR # define DIR_SEPARATOR '/' # define PATH_SEPARATOR ':' #endif #if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ defined (__OS2__) # define HAVE_DOS_BASED_FILE_SYSTEM # define FOPEN_WB "wb" # ifndef DIR_SEPARATOR_2 # define DIR_SEPARATOR_2 '\\' # endif # ifndef PATH_SEPARATOR_2 # define PATH_SEPARATOR_2 ';' # endif #endif #ifndef DIR_SEPARATOR_2 # define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) #else /* DIR_SEPARATOR_2 */ # define IS_DIR_SEPARATOR(ch) \ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) #endif /* DIR_SEPARATOR_2 */ #ifndef PATH_SEPARATOR_2 # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) #else /* PATH_SEPARATOR_2 */ # define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) #endif /* PATH_SEPARATOR_2 */ #ifndef FOPEN_WB # define FOPEN_WB "w" #endif #ifndef _O_BINARY # define _O_BINARY 0 #endif #define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) #define XFREE(stale) do { \ if (stale) { free ((void *) stale); stale = 0; } \ } while (0) #if defined(LT_DEBUGWRAPPER) static int lt_debug = 1; #else static int lt_debug = 0; #endif const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ void *xmalloc (size_t num); char *xstrdup (const char *string); const char *base_name (const char *name); char *find_executable (const char *wrapper); char *chase_symlinks (const char *pathspec); int make_executable (const char *path); int check_executable (const char *path); char *strendzap (char *str, const char *pat); void lt_debugprintf (const char *file, int line, const char *fmt, ...); void lt_fatal (const char *file, int line, const char *message, ...); static const char *nonnull (const char *s); static const char *nonempty (const char *s); void lt_setenv (const char *name, const char *value); char *lt_extend_str (const char *orig_value, const char *add, int to_end); void lt_update_exe_path (const char *name, const char *value); void lt_update_lib_path (const char *name, const char *value); char **prepare_spawn (char **argv); void lt_dump_script (FILE *f); EOF cat <= 0) && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return 1; else return 0; } int make_executable (const char *path) { int rval = 0; struct stat st; lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", nonempty (path)); if ((!path) || (!*path)) return 0; if (stat (path, &st) >= 0) { rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); } return rval; } /* Searches for the full path of the wrapper. Returns newly allocated full path name if found, NULL otherwise Does not chase symlinks, even on platforms that support them. */ char * find_executable (const char *wrapper) { int has_slash = 0; const char *p; const char *p_next; /* static buffer for getcwd */ char tmp[LT_PATHMAX + 1]; int tmp_len; char *concat_name; lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", nonempty (wrapper)); if ((wrapper == NULL) || (*wrapper == '\0')) return NULL; /* Absolute path? */ #if defined (HAVE_DOS_BASED_FILE_SYSTEM) if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } else { #endif if (IS_DIR_SEPARATOR (wrapper[0])) { concat_name = xstrdup (wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } #if defined (HAVE_DOS_BASED_FILE_SYSTEM) } #endif for (p = wrapper; *p; p++) if (*p == '/') { has_slash = 1; break; } if (!has_slash) { /* no slashes; search PATH */ const char *path = getenv ("PATH"); if (path != NULL) { for (p = path; *p; p = p_next) { const char *q; size_t p_len; for (q = p; *q; q++) if (IS_PATH_SEPARATOR (*q)) break; p_len = q - p; p_next = (*q == '\0' ? q : q + 1); if (p_len == 0) { /* empty path: current directory */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); } else { concat_name = XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, p, p_len); concat_name[p_len] = '/'; strcpy (concat_name + p_len + 1, wrapper); } if (check_executable (concat_name)) return concat_name; XFREE (concat_name); } } /* not found in PATH; assume curdir */ } /* Relative path | not found in path: prepend cwd */ if (getcwd (tmp, LT_PATHMAX) == NULL) lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", nonnull (strerror (errno))); tmp_len = strlen (tmp); concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); memcpy (concat_name, tmp, tmp_len); concat_name[tmp_len] = '/'; strcpy (concat_name + tmp_len + 1, wrapper); if (check_executable (concat_name)) return concat_name; XFREE (concat_name); return NULL; } char * chase_symlinks (const char *pathspec) { #ifndef S_ISLNK return xstrdup (pathspec); #else char buf[LT_PATHMAX]; struct stat s; char *tmp_pathspec = xstrdup (pathspec); char *p; int has_symlinks = 0; while (strlen (tmp_pathspec) && !has_symlinks) { lt_debugprintf (__FILE__, __LINE__, "checking path component for symlinks: %s\n", tmp_pathspec); if (lstat (tmp_pathspec, &s) == 0) { if (S_ISLNK (s.st_mode) != 0) { has_symlinks = 1; break; } /* search backwards for last DIR_SEPARATOR */ p = tmp_pathspec + strlen (tmp_pathspec) - 1; while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) p--; if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) { /* no more DIR_SEPARATORS left */ break; } *p = '\0'; } else { lt_fatal (__FILE__, __LINE__, "error accessing file \"%s\": %s", tmp_pathspec, nonnull (strerror (errno))); } } XFREE (tmp_pathspec); if (!has_symlinks) { return xstrdup (pathspec); } tmp_pathspec = realpath (pathspec, buf); if (tmp_pathspec == 0) { lt_fatal (__FILE__, __LINE__, "could not follow symlinks for %s", pathspec); } return xstrdup (tmp_pathspec); #endif } char * strendzap (char *str, const char *pat) { size_t len, patlen; assert (str != NULL); assert (pat != NULL); len = strlen (str); patlen = strlen (pat); if (patlen <= len) { str += len - patlen; if (strcmp (str, pat) == 0) *str = '\0'; } return str; } void lt_debugprintf (const char *file, int line, const char *fmt, ...) { va_list args; if (lt_debug) { (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); va_start (args, fmt); (void) vfprintf (stderr, fmt, args); va_end (args); } } static void lt_error_core (int exit_status, const char *file, int line, const char *mode, const char *message, va_list ap) { fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); vfprintf (stderr, message, ap); fprintf (stderr, ".\n"); if (exit_status >= 0) exit (exit_status); } void lt_fatal (const char *file, int line, const char *message, ...) { va_list ap; va_start (ap, message); lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); va_end (ap); } static const char * nonnull (const char *s) { return s ? s : "(null)"; } static const char * nonempty (const char *s) { return (s && !*s) ? "(empty)" : nonnull (s); } void lt_setenv (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_setenv) setting '%s' to '%s'\n", nonnull (name), nonnull (value)); { #ifdef HAVE_SETENV /* always make a copy, for consistency with !HAVE_SETENV */ char *str = xstrdup (value); setenv (name, str, 1); #else int len = strlen (name) + 1 + strlen (value) + 1; char *str = XMALLOC (char, len); sprintf (str, "%s=%s", name, value); if (putenv (str) != EXIT_SUCCESS) { XFREE (str); } #endif } } char * lt_extend_str (const char *orig_value, const char *add, int to_end) { char *new_value; if (orig_value && *orig_value) { int orig_value_len = strlen (orig_value); int add_len = strlen (add); new_value = XMALLOC (char, add_len + orig_value_len + 1); if (to_end) { strcpy (new_value, orig_value); strcpy (new_value + orig_value_len, add); } else { strcpy (new_value, add); strcpy (new_value + add_len, orig_value); } } else { new_value = xstrdup (add); } return new_value; } void lt_update_exe_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); /* some systems can't cope with a ':'-terminated path #' */ int len = strlen (new_value); while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) { new_value[len-1] = '\0'; } lt_setenv (name, new_value); XFREE (new_value); } } void lt_update_lib_path (const char *name, const char *value) { lt_debugprintf (__FILE__, __LINE__, "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", nonnull (name), nonnull (value)); if (name && *name && value && *value) { char *new_value = lt_extend_str (getenv (name), value, 0); lt_setenv (name, new_value); XFREE (new_value); } } EOF case $host_os in mingw*) cat <<"EOF" /* Prepares an argument vector before calling spawn(). Note that spawn() does not by itself call the command interpreter (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&v); v.dwPlatformId == VER_PLATFORM_WIN32_NT; }) ? "cmd.exe" : "command.com"). Instead it simply concatenates the arguments, separated by ' ', and calls CreateProcess(). We must quote the arguments since Win32 CreateProcess() interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a special way: - Space and tab are interpreted as delimiters. They are not treated as delimiters if they are surrounded by double quotes: "...". - Unescaped double quotes are removed from the input. Their only effect is that within double quotes, space and tab are treated like normal characters. - Backslashes not followed by double quotes are not special. - But 2*n+1 backslashes followed by a double quote become n backslashes followed by a double quote (n >= 0): \" -> " \\\" -> \" \\\\\" -> \\" */ #define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" #define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" char ** prepare_spawn (char **argv) { size_t argc; char **new_argv; size_t i; /* Count number of arguments. */ for (argc = 0; argv[argc] != NULL; argc++) ; /* Allocate new argument vector. */ new_argv = XMALLOC (char *, argc + 1); /* Put quoted arguments into the new argument vector. */ for (i = 0; i < argc; i++) { const char *string = argv[i]; if (string[0] == '\0') new_argv[i] = xstrdup ("\"\""); else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) { int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); size_t length; unsigned int backslashes; const char *s; char *quoted_string; char *p; length = 0; backslashes = 0; if (quote_around) length++; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') length += backslashes + 1; length++; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) length += backslashes + 1; quoted_string = XMALLOC (char, length + 1); p = quoted_string; backslashes = 0; if (quote_around) *p++ = '"'; for (s = string; *s != '\0'; s++) { char c = *s; if (c == '"') { unsigned int j; for (j = backslashes + 1; j > 0; j--) *p++ = '\\'; } *p++ = c; if (c == '\\') backslashes++; else backslashes = 0; } if (quote_around) { unsigned int j; for (j = backslashes; j > 0; j--) *p++ = '\\'; *p++ = '"'; } *p = '\0'; new_argv[i] = quoted_string; } else new_argv[i] = (char *) string; } new_argv[argc] = NULL; return new_argv; } EOF ;; esac cat <<"EOF" void lt_dump_script (FILE* f) { EOF func_emit_wrapper yes | $SED -n -e ' s/^\(.\{79\}\)\(..*\)/\1\ \2/ h s/\([\\"]\)/\\\1/g s/$/\\n/ s/\([^\n]*\).*/ fputs ("\1", f);/p g D' cat <<"EOF" } EOF } # end: func_emit_cwrapperexe_src # func_win32_import_lib_p ARG # True if ARG is an import lib, as indicated by $file_magic_cmd func_win32_import_lib_p () { $opt_debug case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in *import*) : ;; *) false ;; esac } # func_mode_link arg... func_mode_link () { $opt_debug case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) # It is impossible to link a dll without this setting, and # we shouldn't force the makefile maintainer to figure out # which system we are compiling for in order to pass an extra # flag for every libtool invocation. # allow_undefined=no # FIXME: Unfortunately, there are problems with the above when trying # to make a dll which has undefined symbols, in which case not # even a static library is built. For now, we need to specify # -no-undefined on the libtool link line when we can be certain # that all symbols are satisfied, otherwise we get a static library. allow_undefined=yes ;; *) allow_undefined=yes ;; esac libtool_args=$nonopt base_compile="$nonopt $@" compile_command=$nonopt finalize_command=$nonopt compile_rpath= finalize_rpath= compile_shlibpath= finalize_shlibpath= convenience= old_convenience= deplibs= old_deplibs= compiler_flags= linker_flags= dllsearchpath= lib_search_path=`pwd` inst_prefix_dir= new_inherited_linker_flags= avoid_version=no bindir= dlfiles= dlprefiles= dlself=no export_dynamic=no export_symbols= export_symbols_regex= generated= libobjs= ltlibs= module=no no_install=no objs= non_pic_objects= precious_files_regex= prefer_static_libs=no preload=no prev= prevarg= release= rpath= xrpath= perm_rpath= temp_rpath= thread_safe=no vinfo= vinfo_number=no weak_libs= single_module="${wl}-single_module" func_infer_tag $base_compile # We need to know -static, to get the right output filenames. for arg do case $arg in -shared) test "$build_libtool_libs" != yes && \ func_fatal_configuration "can not build a shared library" build_old_libs=no break ;; -all-static | -static | -static-libtool-libs) case $arg in -all-static) if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then func_warning "complete static linking is impossible in this configuration" fi if test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; -static) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=built ;; -static-libtool-libs) if test -z "$pic_flag" && test -n "$link_static_flag"; then dlopen_self=$dlopen_self_static fi prefer_static_libs=yes ;; esac build_libtool_libs=no build_old_libs=yes break ;; esac done # See if our shared archives depend on static archives. test -n "$old_archive_from_new_cmds" && build_old_libs=yes # Go through the arguments, transforming them on the way. while test "$#" -gt 0; do arg="$1" shift func_quote_for_eval "$arg" qarg=$func_quote_for_eval_unquoted_result func_append libtool_args " $func_quote_for_eval_result" # If the previous option needs an argument, assign it. if test -n "$prev"; then case $prev in output) func_append compile_command " @OUTPUT@" func_append finalize_command " @OUTPUT@" ;; esac case $prev in bindir) bindir="$arg" prev= continue ;; dlfiles|dlprefiles) if test "$preload" = no; then # Add the symbol object into the linking commands. func_append compile_command " @SYMFILE@" func_append finalize_command " @SYMFILE@" preload=yes fi case $arg in *.la | *.lo) ;; # We handle these cases below. force) if test "$dlself" = no; then dlself=needless export_dynamic=yes fi prev= continue ;; self) if test "$prev" = dlprefiles; then dlself=yes elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then dlself=yes else dlself=needless export_dynamic=yes fi prev= continue ;; *) if test "$prev" = dlfiles; then func_append dlfiles " $arg" else func_append dlprefiles " $arg" fi prev= continue ;; esac ;; expsyms) export_symbols="$arg" test -f "$arg" \ || func_fatal_error "symbol file \`$arg' does not exist" prev= continue ;; expsyms_regex) export_symbols_regex="$arg" prev= continue ;; framework) case $host in *-*-darwin*) case "$deplibs " in *" $qarg.ltframework "*) ;; *) func_append deplibs " $qarg.ltframework" # this is fixed later ;; esac ;; esac prev= continue ;; inst_prefix) inst_prefix_dir="$arg" prev= continue ;; objectlist) if test -f "$arg"; then save_arg=$arg moreargs= for fil in `cat "$save_arg"` do # func_append moreargs " $fil" arg=$fil # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi done else func_fatal_error "link input file \`$arg' does not exist" fi arg=$save_arg prev= continue ;; precious_regex) precious_files_regex="$arg" prev= continue ;; release) release="-$arg" prev= continue ;; rpath | xrpath) # We need an absolute path. case $arg in [\\/]* | [A-Za-z]:[\\/]*) ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac if test "$prev" = rpath; then case "$rpath " in *" $arg "*) ;; *) func_append rpath " $arg" ;; esac else case "$xrpath " in *" $arg "*) ;; *) func_append xrpath " $arg" ;; esac fi prev= continue ;; shrext) shrext_cmds="$arg" prev= continue ;; weak) func_append weak_libs " $arg" prev= continue ;; xcclinker) func_append linker_flags " $qarg" func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xcompiler) func_append compiler_flags " $qarg" prev= func_append compile_command " $qarg" func_append finalize_command " $qarg" continue ;; xlinker) func_append linker_flags " $qarg" func_append compiler_flags " $wl$qarg" prev= func_append compile_command " $wl$qarg" func_append finalize_command " $wl$qarg" continue ;; *) eval "$prev=\"\$arg\"" prev= continue ;; esac fi # test -n "$prev" prevarg="$arg" case $arg in -all-static) if test -n "$link_static_flag"; then # See comment for -static flag below, for more details. func_append compile_command " $link_static_flag" func_append finalize_command " $link_static_flag" fi continue ;; -allow-undefined) # FIXME: remove this flag sometime in the future. func_fatal_error "\`-allow-undefined' must not be used because it is the default" ;; -avoid-version) avoid_version=yes continue ;; -bindir) prev=bindir continue ;; -dlopen) prev=dlfiles continue ;; -dlpreopen) prev=dlprefiles continue ;; -export-dynamic) export_dynamic=yes continue ;; -export-symbols | -export-symbols-regex) if test -n "$export_symbols" || test -n "$export_symbols_regex"; then func_fatal_error "more than one -exported-symbols argument is not allowed" fi if test "X$arg" = "X-export-symbols"; then prev=expsyms else prev=expsyms_regex fi continue ;; -framework) prev=framework continue ;; -inst-prefix-dir) prev=inst_prefix continue ;; # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* # so, if we see these flags be careful not to treat them like -L -L[A-Z][A-Z]*:*) case $with_gcc/$host in no/*-*-irix* | /*-*-irix*) func_append compile_command " $arg" func_append finalize_command " $arg" ;; esac continue ;; -L*) func_stripname "-L" '' "$arg" if test -z "$func_stripname_result"; then if test "$#" -gt 0; then func_fatal_error "require no space between \`-L' and \`$1'" else func_fatal_error "need path for \`-L' option" fi fi func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; *) absdir=`cd "$dir" && pwd` test -z "$absdir" && \ func_fatal_error "cannot determine absolute directory name of \`$dir'" dir="$absdir" ;; esac case "$deplibs " in *" -L$dir "* | *" $arg "*) # Will only happen for absolute or sysroot arguments ;; *) # Preserve sysroot, but never include relative directories case $dir in [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; *) func_append deplibs " -L$dir" ;; esac func_append lib_search_path " $dir" ;; esac case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` case :$dllsearchpath: in *":$dir:"*) ;; ::) dllsearchpath=$dir;; *) func_append dllsearchpath ":$dir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac continue ;; -l*) if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) # These systems don't actually have a C or math library (as such) continue ;; *-*-os2*) # These systems don't actually have a C library (as such) test "X$arg" = "X-lc" && continue ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. test "X$arg" = "X-lc" && continue ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C and math libraries are in the System framework func_append deplibs " System.ltframework" continue ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype test "X$arg" = "X-lc" && continue ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work test "X$arg" = "X-lc" && continue ;; esac elif test "X$arg" = "X-lc_r"; then case $host in *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc_r directly, use -pthread flag. continue ;; esac fi func_append deplibs " $arg" continue ;; -module) module=yes continue ;; # Tru64 UNIX uses -model [arg] to determine the layout of C++ # classes, name mangling, and exception handling. # Darwin uses the -arch flag to determine output architecture. -model|-arch|-isysroot|--sysroot) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" prev=xcompiler continue ;; -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) func_append compiler_flags " $arg" func_append compile_command " $arg" func_append finalize_command " $arg" case "$new_inherited_linker_flags " in *" $arg "*) ;; * ) func_append new_inherited_linker_flags " $arg" ;; esac continue ;; -multi_module) single_module="${wl}-multi_module" continue ;; -no-fast-install) fast_install=no continue ;; -no-install) case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) # The PATH hackery in wrapper scripts is required on Windows # and Darwin in order for the loader to find any dlls it needs. func_warning "\`-no-install' is ignored for $host" func_warning "assuming \`-no-fast-install' instead" fast_install=no ;; *) no_install=yes ;; esac continue ;; -no-undefined) allow_undefined=no continue ;; -objectlist) prev=objectlist continue ;; -o) prev=output ;; -precious-files-regex) prev=precious_regex continue ;; -release) prev=release continue ;; -rpath) prev=rpath continue ;; -R) prev=xrpath continue ;; -R*) func_stripname '-R' '' "$arg" dir=$func_stripname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) ;; =*) func_stripname '=' '' "$dir" dir=$lt_sysroot$func_stripname_result ;; *) func_fatal_error "only absolute run-paths are allowed" ;; esac case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac continue ;; -shared) # The effects of -shared are defined in a previous loop. continue ;; -shrext) prev=shrext continue ;; -static | -static-libtool-libs) # The effects of -static are defined in a previous loop. # We used to do the same as -all-static on platforms that # didn't have a PIC flag, but the assumption that the effects # would be equivalent was wrong. It would break on at least # Digital Unix and AIX. continue ;; -thread-safe) thread_safe=yes continue ;; -version-info) prev=vinfo continue ;; -version-number) prev=vinfo vinfo_number=yes continue ;; -weak) prev=weak continue ;; -Wc,*) func_stripname '-Wc,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $func_quote_for_eval_result" func_append compiler_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Wl,*) func_stripname '-Wl,' '' "$arg" args=$func_stripname_result arg= save_ifs="$IFS"; IFS=',' for flag in $args; do IFS="$save_ifs" func_quote_for_eval "$flag" func_append arg " $wl$func_quote_for_eval_result" func_append compiler_flags " $wl$func_quote_for_eval_result" func_append linker_flags " $func_quote_for_eval_result" done IFS="$save_ifs" func_stripname ' ' '' "$arg" arg=$func_stripname_result ;; -Xcompiler) prev=xcompiler continue ;; -Xlinker) prev=xlinker continue ;; -XCClinker) prev=xcclinker continue ;; # -msg_* for osf cc -msg_*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; # Flags to be passed through unchanged, with rationale: # -64, -mips[0-9] enable 64-bit mode for the SGI compiler # -r[0-9][0-9]* specify processor for the SGI compiler # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler # +DA*, +DD* enable 64-bit mode for the HP compiler # -q* compiler args for the IBM compiler # -m*, -t[45]*, -txscale* architecture-specific flags for GCC # -F/path path to uninstalled frameworks, gcc on darwin # -p, -pg, --coverage, -fprofile-* profiling flags for GCC # @file GCC response files # -tp=* Portland pgcc target processor selection # --sysroot=* for sysroot support # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ -O*|-flto*|-fwhopr*|-fuse-linker-plugin) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" func_append compile_command " $arg" func_append finalize_command " $arg" func_append compiler_flags " $arg" continue ;; # Some other compiler flag. -* | +*) func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; *.$objext) # A standard object. func_append objs " $arg" ;; *.lo) # A libtool-controlled object. # Check to see that this really is a libtool object. if func_lalib_unsafe_p "$arg"; then pic_object= non_pic_object= # Read the .lo file func_source "$arg" if test -z "$pic_object" || test -z "$non_pic_object" || test "$pic_object" = none && test "$non_pic_object" = none; then func_fatal_error "cannot find name of object for \`$arg'" fi # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" if test "$pic_object" != none; then # Prepend the subdirectory the object is found in. pic_object="$xdir$pic_object" if test "$prev" = dlfiles; then if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then func_append dlfiles " $pic_object" prev= continue else # If libtool objects are unsupported, then we need to preload. prev=dlprefiles fi fi # CHECK ME: I think I busted this. -Ossama if test "$prev" = dlprefiles; then # Preload the old-style object. func_append dlprefiles " $pic_object" prev= fi # A PIC object. func_append libobjs " $pic_object" arg="$pic_object" fi # Non-PIC object. if test "$non_pic_object" != none; then # Prepend the subdirectory the object is found in. non_pic_object="$xdir$non_pic_object" # A standard non-PIC object func_append non_pic_objects " $non_pic_object" if test -z "$pic_object" || test "$pic_object" = none ; then arg="$non_pic_object" fi else # If the PIC object exists, use it instead. # $xdir was prepended to $pic_object above. non_pic_object="$pic_object" func_append non_pic_objects " $non_pic_object" fi else # Only an error if not doing a dry-run. if $opt_dry_run; then # Extract subdirectory from the argument. func_dirname "$arg" "/" "" xdir="$func_dirname_result" func_lo2o "$arg" pic_object=$xdir$objdir/$func_lo2o_result non_pic_object=$xdir$func_lo2o_result func_append libobjs " $pic_object" func_append non_pic_objects " $non_pic_object" else func_fatal_error "\`$arg' is not a valid libtool object" fi fi ;; *.$libext) # An archive. func_append deplibs " $arg" func_append old_deplibs " $arg" continue ;; *.la) # A libtool-controlled library. func_resolve_sysroot "$arg" if test "$prev" = dlfiles; then # This library was specified with -dlopen. func_append dlfiles " $func_resolve_sysroot_result" prev= elif test "$prev" = dlprefiles; then # The library was specified with -dlpreopen. func_append dlprefiles " $func_resolve_sysroot_result" prev= else func_append deplibs " $func_resolve_sysroot_result" fi continue ;; # Some other compiler argument. *) # Unknown arguments in both finalize_command and compile_command need # to be aesthetically quoted because they are evaled later. func_quote_for_eval "$arg" arg="$func_quote_for_eval_result" ;; esac # arg # Now actually substitute the argument into the commands. if test -n "$arg"; then func_append compile_command " $arg" func_append finalize_command " $arg" fi done # argument parsing loop test -n "$prev" && \ func_fatal_help "the \`$prevarg' option requires an argument" if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then eval arg=\"$export_dynamic_flag_spec\" func_append compile_command " $arg" func_append finalize_command " $arg" fi oldlibs= # calculate the name of the file, without its directory func_basename "$output" outputname="$func_basename_result" libobjs_save="$libobjs" if test -n "$shlibpath_var"; then # get the directories listed in $shlibpath_var eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` else shlib_search_path= fi eval sys_lib_search_path=\"$sys_lib_search_path_spec\" eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" func_dirname "$output" "/" "" output_objdir="$func_dirname_result$objdir" func_to_tool_file "$output_objdir/" tool_output_objdir=$func_to_tool_file_result # Create the object directory. func_mkdir_p "$output_objdir" # Determine the type of output case $output in "") func_fatal_help "you must specify an output file" ;; *.$libext) linkmode=oldlib ;; *.lo | *.$objext) linkmode=obj ;; *.la) linkmode=lib ;; *) linkmode=prog ;; # Anything else should be a program. esac specialdeplibs= libs= # Find all interdependent deplibs by searching for libraries # that are linked more than once (e.g. -la -lb -la) for deplib in $deplibs; do if $opt_preserve_dup_deps ; then case "$libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append libs " $deplib" done if test "$linkmode" = lib; then libs="$predeps $libs $compiler_lib_search_path $postdeps" # Compute libraries that are listed more than once in $predeps # $postdeps and mark them as special (i.e., whose duplicates are # not to be eliminated). pre_post_deps= if $opt_duplicate_compiler_generated_deps; then for pre_post_dep in $predeps $postdeps; do case "$pre_post_deps " in *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; esac func_append pre_post_deps " $pre_post_dep" done fi pre_post_deps= fi deplibs= newdependency_libs= newlib_search_path= need_relink=no # whether we're linking any uninstalled libtool libraries notinst_deplibs= # not-installed libtool libraries notinst_path= # paths that contain not-installed libtool libraries case $linkmode in lib) passes="conv dlpreopen link" for file in $dlfiles $dlprefiles; do case $file in *.la) ;; *) func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" ;; esac done ;; prog) compile_deplibs= finalize_deplibs= alldeplibs=no newdlfiles= newdlprefiles= passes="conv scan dlopen dlpreopen link" ;; *) passes="conv" ;; esac for pass in $passes; do # The preopen pass in lib mode reverses $deplibs; put it back here # so that -L comes before libs that need it for instance... if test "$linkmode,$pass" = "lib,link"; then ## FIXME: Find the place where the list is rebuilt in the wrong ## order, and fix it there properly tmp_deplibs= for deplib in $deplibs; do tmp_deplibs="$deplib $tmp_deplibs" done deplibs="$tmp_deplibs" fi if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan"; then libs="$deplibs" deplibs= fi if test "$linkmode" = prog; then case $pass in dlopen) libs="$dlfiles" ;; dlpreopen) libs="$dlprefiles" ;; link) libs="$deplibs %DEPLIBS%" test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" ;; esac fi if test "$linkmode,$pass" = "lib,dlpreopen"; then # Collect and forward deplibs of preopened libtool libs for lib in $dlprefiles; do # Ignore non-libtool-libs dependency_libs= func_resolve_sysroot "$lib" case $lib in *.la) func_source "$func_resolve_sysroot_result" ;; esac # Collect preopened libtool deplibs, except any this library # has declared as weak libs for deplib in $dependency_libs; do func_basename "$deplib" deplib_base=$func_basename_result case " $weak_libs " in *" $deplib_base "*) ;; *) func_append deplibs " $deplib" ;; esac done done libs="$dlprefiles" fi if test "$pass" = dlopen; then # Collect dlpreopened libraries save_deplibs="$deplibs" deplibs= fi for deplib in $libs; do lib= found=no case $deplib in -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append compiler_flags " $deplib" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -l*) if test "$linkmode" != lib && test "$linkmode" != prog; then func_warning "\`-l' is ignored for archives/objects" continue fi func_stripname '-l' '' "$deplib" name=$func_stripname_result if test "$linkmode" = lib; then searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" else searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" fi for searchdir in $searchdirs; do for search_ext in .la $std_shrext .so .a; do # Search the libtool library lib="$searchdir/lib${name}${search_ext}" if test -f "$lib"; then if test "$search_ext" = ".la"; then found=yes else found=no fi break 2 fi done done if test "$found" != yes; then # deplib doesn't seem to be a libtool library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue else # deplib is a libtool library # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, # We need to do some special things here, and not later. if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $deplib "*) if func_lalib_p "$lib"; then library_names= old_library= func_source "$lib" for l in $old_library $library_names; do ll="$l" done if test "X$ll" = "X$old_library" ; then # only static version available found=no func_dirname "$lib" "" "." ladir="$func_dirname_result" lib=$ladir/$old_library if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" fi continue fi fi ;; *) ;; esac fi fi ;; # -l *.ltframework) if test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else deplibs="$deplib $deplibs" if test "$linkmode" = lib ; then case "$new_inherited_linker_flags " in *" $deplib "*) ;; * ) func_append new_inherited_linker_flags " $deplib" ;; esac fi fi continue ;; -L*) case $linkmode in lib) deplibs="$deplib $deplibs" test "$pass" = conv && continue newdependency_libs="$deplib $newdependency_libs" func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; prog) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi if test "$pass" = scan; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; *) func_warning "\`-L' is ignored for archives/objects" ;; esac # linkmode continue ;; # -L -R*) if test "$pass" = link; then func_stripname '-R' '' "$deplib" func_resolve_sysroot "$func_stripname_result" dir=$func_resolve_sysroot_result # Make sure the xrpath contains only unique directories. case "$xrpath " in *" $dir "*) ;; *) func_append xrpath " $dir" ;; esac fi deplibs="$deplib $deplibs" continue ;; *.la) func_resolve_sysroot "$deplib" lib=$func_resolve_sysroot_result ;; *.$libext) if test "$pass" = conv; then deplibs="$deplib $deplibs" continue fi case $linkmode in lib) # Linking convenience modules into shared libraries is allowed, # but linking other static libraries is non-portable. case " $dlpreconveniencelibs " in *" $deplib "*) ;; *) valid_a_lib=no case $deplibs_check_method in match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ | $EGREP "$match_pattern_regex" > /dev/null; then valid_a_lib=yes fi ;; pass_all) valid_a_lib=yes ;; esac if test "$valid_a_lib" != yes; then echo $ECHO "*** Warning: Trying to link with static lib archive $deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because the file extensions .$libext of this argument makes me believe" echo "*** that it is just a static archive that I should not use here." else echo $ECHO "*** Warning: Linking the shared library $output against the" $ECHO "*** static library $deplib is not portable!" deplibs="$deplib $deplibs" fi ;; esac continue ;; prog) if test "$pass" != link; then deplibs="$deplib $deplibs" else compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" fi continue ;; esac # linkmode ;; # *.$libext *.lo | *.$objext) if test "$pass" = conv; then deplibs="$deplib $deplibs" elif test "$linkmode" = prog; then if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlopen support or we're linking statically, # we need to preload. func_append newdlprefiles " $deplib" compile_deplibs="$deplib $compile_deplibs" finalize_deplibs="$deplib $finalize_deplibs" else func_append newdlfiles " $deplib" fi fi continue ;; %DEPLIBS%) alldeplibs=yes continue ;; esac # case $deplib if test "$found" = yes || test -f "$lib"; then : else func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" fi # Check to see that this really is a libtool archive. func_lalib_unsafe_p "$lib" \ || func_fatal_error "\`$lib' is not a valid libtool archive" func_dirname "$lib" "" "." ladir="$func_dirname_result" dlname= dlopen= dlpreopen= libdir= library_names= old_library= inherited_linker_flags= # If the library was installed with an old release of libtool, # it will not redefine variables installed, or shouldnotlink installed=yes shouldnotlink=no avoidtemprpath= # Read the .la file func_source "$lib" # Convert "-framework foo" to "foo.ltframework" if test -n "$inherited_linker_flags"; then tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do case " $new_inherited_linker_flags " in *" $tmp_inherited_linker_flag "*) ;; *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; esac done fi dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` if test "$linkmode,$pass" = "lib,link" || test "$linkmode,$pass" = "prog,scan" || { test "$linkmode" != prog && test "$linkmode" != lib; }; then test -n "$dlopen" && func_append dlfiles " $dlopen" test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" fi if test "$pass" = conv; then # Only check for convenience libraries deplibs="$lib $deplibs" if test -z "$libdir"; then if test -z "$old_library"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # It is a libtool convenience library, so add in its objects. func_append convenience " $ladir/$objdir/$old_library" func_append old_convenience " $ladir/$objdir/$old_library" tmp_libs= for deplib in $dependency_libs; do deplibs="$deplib $deplibs" if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done elif test "$linkmode" != prog && test "$linkmode" != lib; then func_fatal_error "\`$lib' is not a convenience library" fi continue fi # $pass = conv # Get the name of the library we link against. linklib= if test -n "$old_library" && { test "$prefer_static_libs" = yes || test "$prefer_static_libs,$installed" = "built,no"; }; then linklib=$old_library else for l in $old_library $library_names; do linklib="$l" done fi if test -z "$linklib"; then func_fatal_error "cannot find name of link library for \`$lib'" fi # This library was specified with -dlopen. if test "$pass" = dlopen; then if test -z "$libdir"; then func_fatal_error "cannot -dlopen a convenience library: \`$lib'" fi if test -z "$dlname" || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then # If there is no dlname, no dlopen support or we're linking # statically, we need to preload. We also need to preload any # dependent libraries so libltdl's deplib preloader doesn't # bomb out in the load deplibs phase. func_append dlprefiles " $lib $dependency_libs" else func_append newdlfiles " $lib" fi continue fi # $pass = dlopen # We need an absolute path. case $ladir in [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; *) abs_ladir=`cd "$ladir" && pwd` if test -z "$abs_ladir"; then func_warning "cannot determine absolute directory name of \`$ladir'" func_warning "passing it literally to the linker, although it might fail" abs_ladir="$ladir" fi ;; esac func_basename "$lib" laname="$func_basename_result" # Find the relevant object directory and library name. if test "X$installed" = Xyes; then if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then func_warning "library \`$lib' was moved." dir="$ladir" absdir="$abs_ladir" libdir="$abs_ladir" else dir="$lt_sysroot$libdir" absdir="$lt_sysroot$libdir" fi test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes else if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then dir="$ladir" absdir="$abs_ladir" # Remove this search path later func_append notinst_path " $abs_ladir" else dir="$ladir/$objdir" absdir="$abs_ladir/$objdir" # Remove this search path later func_append notinst_path " $abs_ladir" fi fi # $installed = yes func_stripname 'lib' '.la' "$laname" name=$func_stripname_result # This library was specified with -dlpreopen. if test "$pass" = dlpreopen; then if test -z "$libdir" && test "$linkmode" = prog; then func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" fi case "$host" in # special handling for platforms with PE-DLLs. *cygwin* | *mingw* | *cegcc* ) # Linker will automatically link against shared library if both # static and shared are present. Therefore, ensure we extract # symbols from the import library if a shared library is present # (otherwise, the dlopen module name will be incorrect). We do # this by putting the import library name into $newdlprefiles. # We recover the dlopen module name by 'saving' the la file # name in a special purpose variable, and (later) extracting the # dlname from the la file. if test -n "$dlname"; then func_tr_sh "$dir/$linklib" eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" func_append newdlprefiles " $dir/$linklib" else func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" fi ;; * ) # Prefer using a static library (so that no silly _DYNAMIC symbols # are required to link). if test -n "$old_library"; then func_append newdlprefiles " $dir/$old_library" # Keep a list of preopened convenience libraries to check # that they are being used correctly in the link pass. test -z "$libdir" && \ func_append dlpreconveniencelibs " $dir/$old_library" # Otherwise, use the dlname, so that lt_dlopen finds it. elif test -n "$dlname"; then func_append newdlprefiles " $dir/$dlname" else func_append newdlprefiles " $dir/$linklib" fi ;; esac fi # $pass = dlpreopen if test -z "$libdir"; then # Link the convenience library if test "$linkmode" = lib; then deplibs="$dir/$old_library $deplibs" elif test "$linkmode,$pass" = "prog,link"; then compile_deplibs="$dir/$old_library $compile_deplibs" finalize_deplibs="$dir/$old_library $finalize_deplibs" else deplibs="$lib $deplibs" # used for prog,scan pass fi continue fi if test "$linkmode" = prog && test "$pass" != link; then func_append newlib_search_path " $ladir" deplibs="$lib $deplibs" linkalldeplibs=no if test "$link_all_deplibs" != no || test -z "$library_names" || test "$build_libtool_libs" = no; then linkalldeplibs=yes fi tmp_libs= for deplib in $dependency_libs; do case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result" func_append newlib_search_path " $func_resolve_sysroot_result" ;; esac # Need to link against all dependency_libs? if test "$linkalldeplibs" = yes; then deplibs="$deplib $deplibs" else # Need to hardcode shared library paths # or/and link against static libraries newdependency_libs="$deplib $newdependency_libs" fi if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $deplib "*) func_append specialdeplibs " $deplib" ;; esac fi func_append tmp_libs " $deplib" done # for deplib continue fi # $linkmode = prog... if test "$linkmode,$pass" = "prog,link"; then if test -n "$library_names" && { { test "$prefer_static_libs" = no || test "$prefer_static_libs,$installed" = "built,yes"; } || test -z "$old_library"; }; then # We need to hardcode the library path if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then # Make sure the rpath contains only unique directories. case "$temp_rpath:" in *"$absdir:"*) ;; *) func_append temp_rpath "$absdir:" ;; esac fi # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi # $linkmode,$pass = prog,link... if test "$alldeplibs" = yes && { test "$deplibs_check_method" = pass_all || { test "$build_libtool_libs" = yes && test -n "$library_names"; }; }; then # We only need to search for static libraries continue fi fi link_static=no # Whether the deplib will be linked statically use_static_libs=$prefer_static_libs if test "$use_static_libs" = built && test "$installed" = yes; then use_static_libs=no fi if test -n "$library_names" && { test "$use_static_libs" = no || test -z "$old_library"; }; then case $host in *cygwin* | *mingw* | *cegcc*) # No point in relinking DLLs because paths are not encoded func_append notinst_deplibs " $lib" need_relink=no ;; *) if test "$installed" = no; then func_append notinst_deplibs " $lib" need_relink=yes fi ;; esac # This is a shared library # Warn about portability, can't link against -module's on some # systems (darwin). Don't bleat about dlopened modules though! dlopenmodule="" for dlpremoduletest in $dlprefiles; do if test "X$dlpremoduletest" = "X$lib"; then dlopenmodule="$dlpremoduletest" break fi done if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then echo if test "$linkmode" = prog; then $ECHO "*** Warning: Linking the executable $output against the loadable module" else $ECHO "*** Warning: Linking the shared library $output against the loadable module" fi $ECHO "*** $linklib is not portable!" fi if test "$linkmode" = lib && test "$hardcode_into_libs" = yes; then # Hardcode the library path. # Skip directories that are in the system default run-time # search path. case " $sys_lib_dlsearch_path " in *" $absdir "*) ;; *) case "$compile_rpath " in *" $absdir "*) ;; *) func_append compile_rpath " $absdir" ;; esac ;; esac case " $sys_lib_dlsearch_path " in *" $libdir "*) ;; *) case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac ;; esac fi if test -n "$old_archive_from_expsyms_cmds"; then # figure out the soname set dummy $library_names shift realname="$1" shift libname=`eval "\\$ECHO \"$libname_spec\""` # use dlname if we got it. it's perfectly good, no? if test -n "$dlname"; then soname="$dlname" elif test -n "$soname_spec"; then # bleh windows case $host in *cygwin* | mingw* | *cegcc*) func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; esac eval soname=\"$soname_spec\" else soname="$realname" fi # Make a new name for the extract_expsyms_cmds to use soroot="$soname" func_basename "$soroot" soname="$func_basename_result" func_stripname 'lib' '.dll' "$soname" newlib=libimp-$func_stripname_result.a # If the library has no export list, then create one now if test -f "$output_objdir/$soname-def"; then : else func_verbose "extracting exported symbol list from \`$soname'" func_execute_cmds "$extract_expsyms_cmds" 'exit $?' fi # Create $newlib if test -f "$output_objdir/$newlib"; then :; else func_verbose "generating import library for \`$soname'" func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' fi # make sure the library variables are pointing to the new library dir=$output_objdir linklib=$newlib fi # test -n "$old_archive_from_expsyms_cmds" if test "$linkmode" = prog || test "$opt_mode" != relink; then add_shlibpath= add_dir= add= lib_linked=yes case $hardcode_action in immediate | unsupported) if test "$hardcode_direct" = no; then add="$dir/$linklib" case $host in *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; *-*-sysv4*uw2*) add_dir="-L$dir" ;; *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ *-*-unixware7*) add_dir="-L$dir" ;; *-*-darwin* ) # if the lib is a (non-dlopened) module then we can not # link against it, someone is ignoring the earlier warnings if /usr/bin/file -L $add 2> /dev/null | $GREP ": [^:]* bundle" >/dev/null ; then if test "X$dlopenmodule" != "X$lib"; then $ECHO "*** Warning: lib $linklib is a module, not a shared library" if test -z "$old_library" ; then echo echo "*** And there doesn't seem to be a static archive available" echo "*** The link will probably fail, sorry" else add="$dir/$old_library" fi elif test -n "$old_library"; then add="$dir/$old_library" fi fi esac elif test "$hardcode_minus_L" = no; then case $host in *-*-sunos*) add_shlibpath="$dir" ;; esac add_dir="-L$dir" add="-l$name" elif test "$hardcode_shlibpath_var" = no; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; relink) if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$dir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$absdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then add_shlibpath="$dir" add="-l$name" else lib_linked=no fi ;; *) lib_linked=no ;; esac if test "$lib_linked" != yes; then func_fatal_configuration "unsupported hardcode properties" fi if test -n "$add_shlibpath"; then case :$compile_shlibpath: in *":$add_shlibpath:"*) ;; *) func_append compile_shlibpath "$add_shlibpath:" ;; esac fi if test "$linkmode" = prog; then test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" test -n "$add" && compile_deplibs="$add $compile_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" if test "$hardcode_direct" != yes && test "$hardcode_minus_L" != yes && test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac fi fi fi if test "$linkmode" = prog || test "$opt_mode" = relink; then add_shlibpath= add_dir= add= # Finalize command for both is simple: just hardcode it. if test "$hardcode_direct" = yes && test "$hardcode_direct_absolute" = no; then add="$libdir/$linklib" elif test "$hardcode_minus_L" = yes; then add_dir="-L$libdir" add="-l$name" elif test "$hardcode_shlibpath_var" = yes; then case :$finalize_shlibpath: in *":$libdir:"*) ;; *) func_append finalize_shlibpath "$libdir:" ;; esac add="-l$name" elif test "$hardcode_automatic" = yes; then if test -n "$inst_prefix_dir" && test -f "$inst_prefix_dir$libdir/$linklib" ; then add="$inst_prefix_dir$libdir/$linklib" else add="$libdir/$linklib" fi else # We cannot seem to hardcode it, guess we'll fake it. add_dir="-L$libdir" # Try looking first in the location we're being installed to. if test -n "$inst_prefix_dir"; then case $libdir in [\\/]*) func_append add_dir " -L$inst_prefix_dir$libdir" ;; esac fi add="-l$name" fi if test "$linkmode" = prog; then test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" test -n "$add" && finalize_deplibs="$add $finalize_deplibs" else test -n "$add_dir" && deplibs="$add_dir $deplibs" test -n "$add" && deplibs="$add $deplibs" fi fi elif test "$linkmode" = prog; then # Here we assume that one of hardcode_direct or hardcode_minus_L # is not unsupported. This is valid on all known static and # shared platforms. if test "$hardcode_direct" != unsupported; then test -n "$old_library" && linklib="$old_library" compile_deplibs="$dir/$linklib $compile_deplibs" finalize_deplibs="$dir/$linklib $finalize_deplibs" else compile_deplibs="-l$name -L$dir $compile_deplibs" finalize_deplibs="-l$name -L$dir $finalize_deplibs" fi elif test "$build_libtool_libs" = yes; then # Not a shared library if test "$deplibs_check_method" != pass_all; then # We're trying link a shared library against a static one # but the system doesn't support it. # Just print a warning and add the library to dependency_libs so # that the program can be linked against the static library. echo $ECHO "*** Warning: This system can not link to static lib archive $lib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have." if test "$module" = yes; then echo "*** But as you try to build a module library, libtool will still create " echo "*** a static module, that should work as long as the dlopening application" echo "*** is linked with the -dlopen flag to resolve symbols at runtime." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi else deplibs="$dir/$old_library $deplibs" link_static=yes fi fi # link shared/static library? if test "$linkmode" = lib; then if test -n "$dependency_libs" && { test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes || test "$link_static" = yes; }; then # Extract -R from dependency_libs temp_deplibs= for libdir in $dependency_libs; do case $libdir in -R*) func_stripname '-R' '' "$libdir" temp_xrpath=$func_stripname_result case " $xrpath " in *" $temp_xrpath "*) ;; *) func_append xrpath " $temp_xrpath";; esac;; *) func_append temp_deplibs " $libdir";; esac done dependency_libs="$temp_deplibs" fi func_append newlib_search_path " $absdir" # Link against this library test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" # ... and its dependency_libs tmp_libs= for deplib in $dependency_libs; do newdependency_libs="$deplib $newdependency_libs" case $deplib in -L*) func_stripname '-L' '' "$deplib" func_resolve_sysroot "$func_stripname_result";; *) func_resolve_sysroot "$deplib" ;; esac if $opt_preserve_dup_deps ; then case "$tmp_libs " in *" $func_resolve_sysroot_result "*) func_append specialdeplibs " $func_resolve_sysroot_result" ;; esac fi func_append tmp_libs " $func_resolve_sysroot_result" done if test "$link_all_deplibs" != no; then # Add the search paths of all dependency libraries for deplib in $dependency_libs; do path= case $deplib in -L*) path="$deplib" ;; *.la) func_resolve_sysroot "$deplib" deplib=$func_resolve_sysroot_result func_dirname "$deplib" "" "." dir=$func_dirname_result # We need an absolute path. case $dir in [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; *) absdir=`cd "$dir" && pwd` if test -z "$absdir"; then func_warning "cannot determine absolute directory name of \`$dir'" absdir="$dir" fi ;; esac if $GREP "^installed=no" $deplib > /dev/null; then case $host in *-*-darwin*) depdepl= eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` if test -n "$deplibrary_names" ; then for tmp in $deplibrary_names ; do depdepl=$tmp done if test -f "$absdir/$objdir/$depdepl" ; then depdepl="$absdir/$objdir/$depdepl" darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` if test -z "$darwin_install_name"; then darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` fi func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" path= fi fi ;; *) path="-L$absdir/$objdir" ;; esac else eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" test "$absdir" != "$libdir" && \ func_warning "\`$deplib' seems to be moved" path="-L$absdir" fi ;; esac case " $deplibs " in *" $path "*) ;; *) deplibs="$path $deplibs" ;; esac done fi # link_all_deplibs != no fi # linkmode = lib done # for deplib in $libs if test "$pass" = link; then if test "$linkmode" = "prog"; then compile_deplibs="$new_inherited_linker_flags $compile_deplibs" finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" else compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` fi fi dependency_libs="$newdependency_libs" if test "$pass" = dlpreopen; then # Link the dlpreopened libraries before other libraries for deplib in $save_deplibs; do deplibs="$deplib $deplibs" done fi if test "$pass" != dlopen; then if test "$pass" != conv; then # Make sure lib_search_path contains only unique directories. lib_search_path= for dir in $newlib_search_path; do case "$lib_search_path " in *" $dir "*) ;; *) func_append lib_search_path " $dir" ;; esac done newlib_search_path= fi if test "$linkmode,$pass" != "prog,link"; then vars="deplibs" else vars="compile_deplibs finalize_deplibs" fi for var in $vars dependency_libs; do # Add libraries to $var in reverse order eval tmp_libs=\"\$$var\" new_libs= for deplib in $tmp_libs; do # FIXME: Pedantically, this is the right thing to do, so # that some nasty dependency loop isn't accidentally # broken: #new_libs="$deplib $new_libs" # Pragmatically, this seems to cause very few problems in # practice: case $deplib in -L*) new_libs="$deplib $new_libs" ;; -R*) ;; *) # And here is the reason: when a library appears more # than once as an explicit dependence of a library, or # is implicitly linked in more than once by the # compiler, it is considered special, and multiple # occurrences thereof are not removed. Compare this # with having the same library being listed as a # dependency of multiple other libraries: in this case, # we know (pedantically, we assume) the library does not # need to be listed more than once, so we keep only the # last copy. This is not always right, but it is rare # enough that we require users that really mean to play # such unportable linking tricks to link the library # using -Wl,-lname, so that libtool does not consider it # for duplicate removal. case " $specialdeplibs " in *" $deplib "*) new_libs="$deplib $new_libs" ;; *) case " $new_libs " in *" $deplib "*) ;; *) new_libs="$deplib $new_libs" ;; esac ;; esac ;; esac done tmp_libs= for deplib in $new_libs; do case $deplib in -L*) case " $tmp_libs " in *" $deplib "*) ;; *) func_append tmp_libs " $deplib" ;; esac ;; *) func_append tmp_libs " $deplib" ;; esac done eval $var=\"$tmp_libs\" done # for var fi # Last step: remove runtime libs from dependency_libs # (they stay in deplibs) tmp_libs= for i in $dependency_libs ; do case " $predeps $postdeps $compiler_lib_search_path " in *" $i "*) i="" ;; esac if test -n "$i" ; then func_append tmp_libs " $i" fi done dependency_libs=$tmp_libs done # for pass if test "$linkmode" = prog; then dlfiles="$newdlfiles" fi if test "$linkmode" = prog || test "$linkmode" = lib; then dlprefiles="$newdlprefiles" fi case $linkmode in oldlib) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for archives" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for archives" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for archives" test -n "$xrpath" && \ func_warning "\`-R' is ignored for archives" test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for archives" test -n "$release" && \ func_warning "\`-release' is ignored for archives" test -n "$export_symbols$export_symbols_regex" && \ func_warning "\`-export-symbols' is ignored for archives" # Now set the variables for building old libraries. build_libtool_libs=no oldlibs="$output" func_append objs "$old_deplibs" ;; lib) # Make sure we only generate libraries of the form `libNAME.la'. case $outputname in lib*) func_stripname 'lib' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" ;; *) test "$module" = no && \ func_fatal_help "libtool library \`$output' must begin with \`lib'" if test "$need_lib_prefix" != no; then # Add the "lib" prefix for modules if required func_stripname '' '.la' "$outputname" name=$func_stripname_result eval shared_ext=\"$shrext_cmds\" eval libname=\"$libname_spec\" else func_stripname '' '.la' "$outputname" libname=$func_stripname_result fi ;; esac if test -n "$objs"; then if test "$deplibs_check_method" != pass_all; then func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" else echo $ECHO "*** Warning: Linking the shared library $output against the non-libtool" $ECHO "*** objects $objs is not portable!" func_append libobjs " $objs" fi fi test "$dlself" != no && \ func_warning "\`-dlopen self' is ignored for libtool libraries" set dummy $rpath shift test "$#" -gt 1 && \ func_warning "ignoring multiple \`-rpath's for a libtool library" install_libdir="$1" oldlibs= if test -z "$rpath"; then if test "$build_libtool_libs" = yes; then # Building a libtool convenience library. # Some compilers have problems with a `.al' extension so # convenience libraries should have the same extension an # archive normally would. oldlibs="$output_objdir/$libname.$libext $oldlibs" build_libtool_libs=convenience build_old_libs=yes fi test -n "$vinfo" && \ func_warning "\`-version-info/-version-number' is ignored for convenience libraries" test -n "$release" && \ func_warning "\`-release' is ignored for convenience libraries" else # Parse the version information argument. save_ifs="$IFS"; IFS=':' set dummy $vinfo 0 0 0 shift IFS="$save_ifs" test -n "$7" && \ func_fatal_help "too many parameters to \`-version-info'" # convert absolute version numbers to libtool ages # this retains compatibility with .la files and attempts # to make the code below a bit more comprehensible case $vinfo_number in yes) number_major="$1" number_minor="$2" number_revision="$3" # # There are really only two kinds -- those that # use the current revision as the major version # and those that subtract age and use age as # a minor version. But, then there is irix # which has an extra 1 added just for fun # case $version_type in # correct linux to gnu/linux during the next big refactor darwin|linux|osf|windows|none) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_revision" ;; freebsd-aout|freebsd-elf|qnx|sunos) current="$number_major" revision="$number_minor" age="0" ;; irix|nonstopux) func_arith $number_major + $number_minor current=$func_arith_result age="$number_minor" revision="$number_minor" lt_irix_increment=no ;; *) func_fatal_configuration "$modename: unknown library version type \`$version_type'" ;; esac ;; no) current="$1" revision="$2" age="$3" ;; esac # Check that each of the things are valid numbers. case $current in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "CURRENT \`$current' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $revision in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "REVISION \`$revision' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac case $age in 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; *) func_error "AGE \`$age' must be a nonnegative integer" func_fatal_error "\`$vinfo' is not valid version information" ;; esac if test "$age" -gt "$current"; then func_error "AGE \`$age' is greater than the current interface number \`$current'" func_fatal_error "\`$vinfo' is not valid version information" fi # Calculate the version variables. major= versuffix= verstring= case $version_type in none) ;; darwin) # Like Linux, but with the current version available in # verstring for coding it into the library header func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" # Darwin ld doesn't like 0 for these options... func_arith $current + 1 minor_current=$func_arith_result xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" ;; freebsd-aout) major=".$current" versuffix=".$current.$revision"; ;; freebsd-elf) major=".$current" versuffix=".$current" ;; irix | nonstopux) if test "X$lt_irix_increment" = "Xno"; then func_arith $current - $age else func_arith $current - $age + 1 fi major=$func_arith_result case $version_type in nonstopux) verstring_prefix=nonstopux ;; *) verstring_prefix=sgi ;; esac verstring="$verstring_prefix$major.$revision" # Add in all the interfaces that we are compatible with. loop=$revision while test "$loop" -ne 0; do func_arith $revision - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring_prefix$major.$iface:$verstring" done # Before this point, $major must not contain `.'. major=.$major versuffix="$major.$revision" ;; linux) # correct to gnu/linux during the next big refactor func_arith $current - $age major=.$func_arith_result versuffix="$major.$age.$revision" ;; osf) func_arith $current - $age major=.$func_arith_result versuffix=".$current.$age.$revision" verstring="$current.$age.$revision" # Add in all the interfaces that we are compatible with. loop=$age while test "$loop" -ne 0; do func_arith $current - $loop iface=$func_arith_result func_arith $loop - 1 loop=$func_arith_result verstring="$verstring:${iface}.0" done # Make executables depend on our current version. func_append verstring ":${current}.0" ;; qnx) major=".$current" versuffix=".$current" ;; sunos) major=".$current" versuffix=".$current.$revision" ;; windows) # Use '-' rather than '.', since we only want one # extension on DOS 8.3 filesystems. func_arith $current - $age major=$func_arith_result versuffix="-$major" ;; *) func_fatal_configuration "unknown library version type \`$version_type'" ;; esac # Clear the version info if we defaulted, and they specified a release. if test -z "$vinfo" && test -n "$release"; then major= case $version_type in darwin) # we can't check for "0.0" in archive_cmds due to quoting # problems, so we reset it completely verstring= ;; *) verstring="0.0" ;; esac if test "$need_version" = no; then versuffix= else versuffix=".0.0" fi fi # Remove version info from name if versioning should be avoided if test "$avoid_version" = yes && test "$need_version" = no; then major= versuffix= verstring="" fi # Check to see if the archive will have undefined symbols. if test "$allow_undefined" = yes; then if test "$allow_undefined_flag" = unsupported; then func_warning "undefined symbols not allowed in $host shared libraries" build_libtool_libs=no build_old_libs=yes fi else # Don't allow undefined symbols. allow_undefined_flag="$no_undefined_flag" fi fi func_generate_dlsyms "$libname" "$libname" "yes" func_append libobjs " $symfileobj" test "X$libobjs" = "X " && libobjs= if test "$opt_mode" != relink; then # Remove our outputs, but don't remove object files since they # may have been created when compiling PIC objects. removelist= tempremovelist=`$ECHO "$output_objdir/*"` for p in $tempremovelist; do case $p in *.$objext | *.gcno) ;; $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) if test "X$precious_files_regex" != "X"; then if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 then continue fi fi func_append removelist " $p" ;; *) ;; esac done test -n "$removelist" && \ func_show_eval "${RM}r \$removelist" fi # Now set the variables for building old libraries. if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then func_append oldlibs " $output_objdir/$libname.$libext" # Transform .lo files to .o files. oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` fi # Eliminate all temporary directories. #for path in $notinst_path; do # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` #done if test -n "$xrpath"; then # If the user specified any rpath flags, then add them. temp_xrpath= for libdir in $xrpath; do func_replace_sysroot "$libdir" func_append temp_xrpath " -R$func_replace_sysroot_result" case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then dependency_libs="$temp_xrpath $dependency_libs" fi fi # Make sure dlfiles contains only unique files that won't be dlpreopened old_dlfiles="$dlfiles" dlfiles= for lib in $old_dlfiles; do case " $dlprefiles $dlfiles " in *" $lib "*) ;; *) func_append dlfiles " $lib" ;; esac done # Make sure dlprefiles contains only unique files old_dlprefiles="$dlprefiles" dlprefiles= for lib in $old_dlprefiles; do case "$dlprefiles " in *" $lib "*) ;; *) func_append dlprefiles " $lib" ;; esac done if test "$build_libtool_libs" = yes; then if test -n "$rpath"; then case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) # these systems don't actually have a c library (as such)! ;; *-*-rhapsody* | *-*-darwin1.[012]) # Rhapsody C library is in the System framework func_append deplibs " System.ltframework" ;; *-*-netbsd*) # Don't link with libc until the a.out ld.so is fixed. ;; *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) # Do not include libc due to us having libc/libc_r. ;; *-*-sco3.2v5* | *-*-sco5v6*) # Causes problems with __ctype ;; *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) # Compiler inserts libc in the correct place for threads to work ;; *) # Add libc to deplibs on all other systems if necessary. if test "$build_libtool_need_lc" = "yes"; then func_append deplibs " -lc" fi ;; esac fi # Transform deplibs into only deplibs that can be linked in shared. name_save=$name libname_save=$libname release_save=$release versuffix_save=$versuffix major_save=$major # I'm not sure if I'm treating the release correctly. I think # release should show up in the -l (ie -lgmp5) so we don't want to # add it in twice. Is that correct? release="" versuffix="" major="" newdeplibs= droppeddeps=no case $deplibs_check_method in pass_all) # Don't check for shared/static. Everything works. # This might be a little naive. We might want to check # whether the library exists or not. But this is on # osf3 & osf4 and I'm not really sure... Just # implementing what was already the behavior. newdeplibs=$deplibs ;; test_compile) # This code stresses the "libraries are programs" paradigm to its # limits. Maybe even breaks it. We compile a program, linking it # against the deplibs as a proxy for the library. Then we can check # whether they linked in statically or dynamically with ldd. $opt_dry_run || $RM conftest.c cat > conftest.c </dev/null` $nocaseglob else potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` fi for potent_lib in $potential_libs; do # Follow soft links. if ls -lLd "$potent_lib" 2>/dev/null | $GREP " -> " >/dev/null; then continue fi # The statement above tries to avoid entering an # endless loop below, in case of cyclic links. # We might still enter an endless loop, since a link # loop can be closed while we follow links, # but so what? potlib="$potent_lib" while test -h "$potlib" 2>/dev/null; do potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` case $potliblink in [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; esac done if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | $SED -e 10q | $EGREP "$file_magic_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for file magic test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a file magic. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; match_pattern*) set dummy $deplibs_check_method; shift match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` for a_deplib in $deplibs; do case $a_deplib in -l*) func_stripname -l '' "$a_deplib" name=$func_stripname_result if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then case " $predeps $postdeps " in *" $a_deplib "*) func_append newdeplibs " $a_deplib" a_deplib="" ;; esac fi if test -n "$a_deplib" ; then libname=`eval "\\$ECHO \"$libname_spec\""` for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do potential_libs=`ls $i/$libname[.-]* 2>/dev/null` for potent_lib in $potential_libs; do potlib="$potent_lib" # see symlink-check above in file_magic test if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ $EGREP "$match_pattern_regex" > /dev/null; then func_append newdeplibs " $a_deplib" a_deplib="" break 2 fi done done fi if test -n "$a_deplib" ; then droppeddeps=yes echo $ECHO "*** Warning: linker path does not have real file for library $a_deplib." echo "*** I have the capability to make that library automatically link in when" echo "*** you link to this library. But I can only do this if you have a" echo "*** shared version of the library, which you do not appear to have" echo "*** because I did check the linker path looking for a file starting" if test -z "$potlib" ; then $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" else $ECHO "*** with $libname and none of the candidates passed a file format test" $ECHO "*** using a regex pattern. Last file checked: $potlib" fi fi ;; *) # Add a -L argument. func_append newdeplibs " $a_deplib" ;; esac done # Gone through all deplibs. ;; none | unknown | *) newdeplibs="" tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then for i in $predeps $postdeps ; do # can't use Xsed below, because $i might contain '/' tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` done fi case $tmp_deplibs in *[!\ \ ]*) echo if test "X$deplibs_check_method" = "Xnone"; then echo "*** Warning: inter-library dependencies are not supported in this platform." else echo "*** Warning: inter-library dependencies are not known to be supported." fi echo "*** All declared inter-library dependencies are being dropped." droppeddeps=yes ;; esac ;; esac versuffix=$versuffix_save major=$major_save release=$release_save libname=$libname_save name=$name_save case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library with the System framework newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac if test "$droppeddeps" = yes; then if test "$module" = yes; then echo echo "*** Warning: libtool could not satisfy all declared inter-library" $ECHO "*** dependencies of module $libname. Therefore, libtool will create" echo "*** a static module, that should work as long as the dlopening" echo "*** application is linked with the -dlopen flag." if test -z "$global_symbol_pipe"; then echo echo "*** However, this would only work if libtool was able to extract symbol" echo "*** lists from a program, using \`nm' or equivalent, but libtool could" echo "*** not find such a program. So, this module is probably useless." echo "*** \`nm' from GNU binutils and a full rebuild may help." fi if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi else echo "*** The inter-library dependencies that have been dropped here will be" echo "*** automatically added whenever a program is linked with this library" echo "*** or is declared to -dlopen it." if test "$allow_undefined" = no; then echo echo "*** Since this library must not contain undefined symbols," echo "*** because either the platform does not support them or" echo "*** it was explicitly requested with -no-undefined," echo "*** libtool will only create a static version of it." if test "$build_old_libs" = no; then oldlibs="$output_objdir/$libname.$libext" build_libtool_libs=module build_old_libs=yes else build_libtool_libs=no fi fi fi fi # Done checking deplibs! deplibs=$newdeplibs fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" case $host in *-*-darwin*) newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done deplibs="$new_libs" # All the library-specific variables (install_libdir is set above). library_names= old_library= dlname= # Test again, we may have decided not to build it any more if test "$build_libtool_libs" = yes; then # Remove ${wl} instances when linking with ld. # FIXME: should test the right _cmds variable. case $archive_cmds in *\$LD\ *) wl= ;; esac if test "$hardcode_into_libs" = yes; then # Hardcode the library paths hardcode_libdirs= dep_rpath= rpath="$finalize_rpath" test "$opt_mode" != relink && rpath="$compile_rpath$rpath" for libdir in $rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then func_replace_sysroot "$libdir" libdir=$func_replace_sysroot_result if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append dep_rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" fi if test -n "$runpath_var" && test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" fi test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" fi shlibpath="$finalize_shlibpath" test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" if test -n "$shlibpath"; then eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" fi # Get the real and link names of the library. eval shared_ext=\"$shrext_cmds\" eval library_names=\"$library_names_spec\" set dummy $library_names shift realname="$1" shift if test -n "$soname_spec"; then eval soname=\"$soname_spec\" else soname="$realname" fi if test -z "$dlname"; then dlname=$soname fi lib="$output_objdir/$realname" linknames= for link do func_append linknames " $link" done # Use standard objects if they are pic test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` test "X$libobjs" = "X " && libobjs= delfiles= if test -n "$export_symbols" && test -n "$include_expsyms"; then $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" export_symbols="$output_objdir/$libname.uexp" func_append delfiles " $export_symbols" fi orig_export_symbols= case $host_os in cygwin* | mingw* | cegcc*) if test -n "$export_symbols" && test -z "$export_symbols_regex"; then # exporting using user supplied symfile if test "x`$SED 1q $export_symbols`" != xEXPORTS; then # and it's NOT already a .def file. Must figure out # which of the given symbols are data symbols and tag # them as such. So, trigger use of export_symbols_cmds. # export_symbols gets reassigned inside the "prepare # the list of exported symbols" if statement, so the # include_expsyms logic still works. orig_export_symbols="$export_symbols" export_symbols= always_export_symbols=yes fi fi ;; esac # Prepare the list of exported symbols if test -z "$export_symbols"; then if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols cmds=$export_symbols_cmds save_ifs="$IFS"; IFS='~' for cmd1 in $cmds; do IFS="$save_ifs" # Take the normal branch if the nm_file_list_spec branch # doesn't work or if tool conversion is not needed. case $nm_file_list_spec~$to_tool_file_cmd in *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) try_normal_branch=yes eval cmd=\"$cmd1\" func_len " $cmd" len=$func_len_result ;; *) try_normal_branch=no ;; esac if test "$try_normal_branch" = yes \ && { test "$len" -lt "$max_cmd_len" \ || test "$max_cmd_len" -le -1; } then func_show_eval "$cmd" 'exit $?' skipped_export=false elif test -n "$nm_file_list_spec"; then func_basename "$output" output_la=$func_basename_result save_libobjs=$libobjs save_output=$output output=${output_objdir}/${output_la}.nm func_to_tool_file "$output" libobjs=$nm_file_list_spec$func_to_tool_file_result func_append delfiles " $output" func_verbose "creating $NM input file list: $output" for obj in $save_libobjs; do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > "$output" eval cmd=\"$cmd1\" func_show_eval "$cmd" 'exit $?' output=$save_output libobjs=$save_libobjs skipped_export=false else # The command line is too long to execute in one step. func_verbose "using reloadable object file for export list..." skipped_export=: # Break out early, otherwise skipped_export may be # set to false by a later but shorter cmd. break fi done IFS="$save_ifs" if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi fi if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi tmp_deplibs= for test_deplib in $deplibs; do case " $convenience " in *" $test_deplib "*) ;; *) func_append tmp_deplibs " $test_deplib" ;; esac done deplibs="$tmp_deplibs" if test -n "$convenience"; then if test -n "$whole_archive_flag_spec" && test "$compiler_needs_object" = yes && test -z "$libobjs"; then # extract the archives, so we have objects to list. # TODO: could optimize this to just extract one archive. whole_archive_flag_spec= fi if test -n "$whole_archive_flag_spec"; then save_libobjs=$libobjs eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= else gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $convenience func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi fi if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then eval flag=\"$thread_safe_flag_spec\" func_append linker_flags " $flag" fi # Make a backup of the uninstalled library when relinking if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? fi # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then eval test_cmds=\"$module_expsym_cmds\" cmds=$module_expsym_cmds else eval test_cmds=\"$module_cmds\" cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then eval test_cmds=\"$archive_expsym_cmds\" cmds=$archive_expsym_cmds else eval test_cmds=\"$archive_cmds\" cmds=$archive_cmds fi fi if test "X$skipped_export" != "X:" && func_len " $test_cmds" && len=$func_len_result && test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then : else # The command line is too long to link in one step, link piecewise # or, if using GNU ld and skipped_export is not :, use a linker # script. # Save the value of $output and $libobjs because we want to # use them later. If we have whole_archive_flag_spec, we # want to use save_libobjs as it was before # whole_archive_flag_spec was expanded, because we can't # assume the linker understands whole_archive_flag_spec. # This may have to be revisited, in case too many # convenience libraries get linked in and end up exceeding # the spec. if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then save_libobjs=$libobjs fi save_output=$output func_basename "$output" output_la=$func_basename_result # Clear the reloadable object creation command queue and # initialize k to one. test_cmds= concat_cmds= objlist= last_robj= k=1 if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then output=${output_objdir}/${output_la}.lnkscript func_verbose "creating GNU ld script: $output" echo 'INPUT (' > $output for obj in $save_libobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done echo ')' >> $output func_append delfiles " $output" func_to_tool_file "$output" output=$func_to_tool_file_result elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then output=${output_objdir}/${output_la}.lnk func_verbose "creating linker input file list: $output" : > $output set x $save_libobjs shift firstobj= if test "$compiler_needs_object" = yes; then firstobj="$1 " shift fi for obj do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" >> $output done func_append delfiles " $output" func_to_tool_file "$output" output=$firstobj\"$file_list_spec$func_to_tool_file_result\" else if test -n "$save_libobjs"; then func_verbose "creating reloadable object files..." output=$output_objdir/$output_la-${k}.$objext eval test_cmds=\"$reload_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 # Loop over the list of objects to be linked. for obj in $save_libobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result if test "X$objlist" = X || test "$len" -lt "$max_cmd_len"; then func_append objlist " $obj" else # The command $test_cmds is almost too long, add a # command to the queue. if test "$k" -eq 1 ; then # The first file doesn't have a previous command to add. reload_objs=$objlist eval concat_cmds=\"$reload_cmds\" else # All subsequent reloadable object files will link in # the last one created. reload_objs="$objlist $last_robj" eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" fi last_robj=$output_objdir/$output_la-${k}.$objext func_arith $k + 1 k=$func_arith_result output=$output_objdir/$output_la-${k}.$objext objlist=" $obj" func_len " $last_robj" func_arith $len0 + $func_len_result len=$func_arith_result fi done # Handle the remaining objects by creating one last # reloadable object file. All subsequent reloadable object # files will link in the last one created. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ reload_objs="$objlist $last_robj" eval concat_cmds=\"\${concat_cmds}$reload_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" fi func_append delfiles " $output" else output= fi if ${skipped_export-false}; then func_verbose "generating symbol list for \`$libname.la'" export_symbols="$output_objdir/$libname.exp" $opt_dry_run || $RM $export_symbols libobjs=$output # Append the command to create the export file. test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" if test -n "$last_robj"; then eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" fi fi test -n "$save_libobjs" && func_verbose "creating a temporary reloadable object file: $output" # Loop through the commands generated above and execute them. save_ifs="$IFS"; IFS='~' for cmd in $concat_cmds; do IFS="$save_ifs" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" if test -n "$export_symbols_regex" && ${skipped_export-false}; then func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' func_show_eval '$MV "${export_symbols}T" "$export_symbols"' fi fi if ${skipped_export-false}; then if test -n "$export_symbols" && test -n "$include_expsyms"; then tmp_export_symbols="$export_symbols" test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' fi if test -n "$orig_export_symbols"; then # The given exports_symbols file has to be filtered, so filter it. func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" # FIXME: $output_objdir/$libname.filter potentially contains lots of # 's' commands which not all seds can handle. GNU sed should be fine # though. Also, the filter scales superlinearly with the number of # global variables. join(1) would be nice here, but unfortunately # isn't a blessed tool. $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter func_append delfiles " $export_symbols $output_objdir/$libname.filter" export_symbols=$output_objdir/$libname.def $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols fi fi libobjs=$output # Restore the value of output. output=$save_output if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then eval libobjs=\"\$libobjs $whole_archive_flag_spec\" test "X$libobjs" = "X " && libobjs= fi # Expand the library linking commands again to reset the # value of $libobjs for piecewise linking. # Do each of the archive commands. if test "$module" = yes && test -n "$module_cmds" ; then if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then cmds=$module_expsym_cmds else cmds=$module_cmds fi else if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then cmds=$archive_expsym_cmds else cmds=$archive_cmds fi fi fi if test -n "$delfiles"; then # Append the command to remove temporary files to $cmds. eval cmds=\"\$cmds~\$RM $delfiles\" fi # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append libobjs " $func_extract_archives_result" test "X$libobjs" = "X " && libobjs= fi save_ifs="$IFS"; IFS='~' for cmd in $cmds; do IFS="$save_ifs" eval cmd=\"$cmd\" $opt_silent || { func_quote_for_expand "$cmd" eval "func_echo $func_quote_for_expand_result" } $opt_dry_run || eval "$cmd" || { lt_exit=$? # Restore the uninstalled library and exit if test "$opt_mode" = relink; then ( cd "$output_objdir" && \ $RM "${realname}T" && \ $MV "${realname}U" "$realname" ) fi exit $lt_exit } done IFS="$save_ifs" # Restore the uninstalled library and exit if test "$opt_mode" = relink; then $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? if test -n "$convenience"; then if test -z "$whole_archive_flag_spec"; then func_show_eval '${RM}r "$gentop"' fi fi exit $EXIT_SUCCESS fi # Create links to the real library. for linkname in $linknames; do if test "$realname" != "$linkname"; then func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' fi done # If -module or -export-dynamic was specified, set the dlname. if test "$module" = yes || test "$export_dynamic" = yes; then # On all known operating systems, these are identical. dlname="$soname" fi fi ;; obj) if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then func_warning "\`-dlopen' is ignored for objects" fi case " $deplibs" in *\ -l* | *\ -L*) func_warning "\`-l' and \`-L' are ignored for objects" ;; esac test -n "$rpath" && \ func_warning "\`-rpath' is ignored for objects" test -n "$xrpath" && \ func_warning "\`-R' is ignored for objects" test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for objects" test -n "$release" && \ func_warning "\`-release' is ignored for objects" case $output in *.lo) test -n "$objs$old_deplibs" && \ func_fatal_error "cannot build library object \`$output' from non-libtool objects" libobj=$output func_lo2o "$libobj" obj=$func_lo2o_result ;; *) libobj= obj="$output" ;; esac # Delete the old objects. $opt_dry_run || $RM $obj $libobj # Objects from convenience libraries. This assumes # single-version convenience libraries. Whenever we create # different ones for PIC/non-PIC, this we'll have to duplicate # the extraction. reload_conv_objs= gentop= # reload_cmds runs $LD directly, so let us get rid of # -Wl from whole_archive_flag_spec and hope we can get by with # turning comma into space.. wl= if test -n "$convenience"; then if test -n "$whole_archive_flag_spec"; then eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` else gentop="$output_objdir/${obj}x" func_append generated " $gentop" func_extract_archives $gentop $convenience reload_conv_objs="$reload_objs $func_extract_archives_result" fi fi # If we're not building shared, we need to use non_pic_objs test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" # Create the old-style object. reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test output="$obj" func_execute_cmds "$reload_cmds" 'exit $?' # Exit if we aren't doing a library object file. if test -z "$libobj"; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS fi if test "$build_libtool_libs" != yes; then if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi # Create an invalid libtool object if no PIC, so that we don't # accidentally link it into a program. # $show "echo timestamp > $libobj" # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? exit $EXIT_SUCCESS fi if test -n "$pic_flag" || test "$pic_mode" != default; then # Only do commands if we really have different PIC objects. reload_objs="$libobjs $reload_conv_objs" output="$libobj" func_execute_cmds "$reload_cmds" 'exit $?' fi if test -n "$gentop"; then func_show_eval '${RM}r "$gentop"' fi exit $EXIT_SUCCESS ;; prog) case $host in *cygwin*) func_stripname '' '.exe' "$output" output=$func_stripname_result.exe;; esac test -n "$vinfo" && \ func_warning "\`-version-info' is ignored for programs" test -n "$release" && \ func_warning "\`-release' is ignored for programs" test "$preload" = yes \ && test "$dlopen_support" = unknown \ && test "$dlopen_self" = unknown \ && test "$dlopen_self_static" = unknown && \ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." case $host in *-*-rhapsody* | *-*-darwin1.[012]) # On Rhapsody replace the C library is the System framework compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` ;; esac case $host in *-*-darwin*) # Don't allow lazy linking, it breaks C++ global constructors # But is supposedly fixed on 10.4 or later (yay!). if test "$tagname" = CXX ; then case ${MACOSX_DEPLOYMENT_TARGET-10.0} in 10.[0123]) func_append compile_command " ${wl}-bind_at_load" func_append finalize_command " ${wl}-bind_at_load" ;; esac fi # Time to change all our "foo.ltframework" stuff back to "-framework foo" compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` ;; esac # move library search paths that coincide with paths to not yet # installed libraries to the beginning of the library search list new_libs= for path in $notinst_path; do case " $new_libs " in *" -L$path/$objdir "*) ;; *) case " $compile_deplibs " in *" -L$path/$objdir "*) func_append new_libs " -L$path/$objdir" ;; esac ;; esac done for deplib in $compile_deplibs; do case $deplib in -L*) case " $new_libs " in *" $deplib "*) ;; *) func_append new_libs " $deplib" ;; esac ;; *) func_append new_libs " $deplib" ;; esac done compile_deplibs="$new_libs" func_append compile_command " $compile_deplibs" func_append finalize_command " $finalize_deplibs" if test -n "$rpath$xrpath"; then # If the user specified any rpath flags, then add them. for libdir in $rpath $xrpath; do # This is the magic to use -rpath. case "$finalize_rpath " in *" $libdir "*) ;; *) func_append finalize_rpath " $libdir" ;; esac done fi # Now hardcode the library paths rpath= hardcode_libdirs= for libdir in $compile_rpath $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$perm_rpath " in *" $libdir "*) ;; *) func_append perm_rpath " $libdir" ;; esac fi case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` case :$dllsearchpath: in *":$libdir:"*) ;; ::) dllsearchpath=$libdir;; *) func_append dllsearchpath ":$libdir";; esac case :$dllsearchpath: in *":$testbindir:"*) ;; ::) dllsearchpath=$testbindir;; *) func_append dllsearchpath ":$testbindir";; esac ;; esac done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi compile_rpath="$rpath" rpath= hardcode_libdirs= for libdir in $finalize_rpath; do if test -n "$hardcode_libdir_flag_spec"; then if test -n "$hardcode_libdir_separator"; then if test -z "$hardcode_libdirs"; then hardcode_libdirs="$libdir" else # Just accumulate the unique libdirs. case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) ;; *) func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" ;; esac fi else eval flag=\"$hardcode_libdir_flag_spec\" func_append rpath " $flag" fi elif test -n "$runpath_var"; then case "$finalize_perm_rpath " in *" $libdir "*) ;; *) func_append finalize_perm_rpath " $libdir" ;; esac fi done # Substitute the hardcoded libdirs into the rpath. if test -n "$hardcode_libdir_separator" && test -n "$hardcode_libdirs"; then libdir="$hardcode_libdirs" eval rpath=\" $hardcode_libdir_flag_spec\" fi finalize_rpath="$rpath" if test -n "$libobjs" && test "$build_old_libs" = yes; then # Transform all the library objects into standard objects. compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` fi func_generate_dlsyms "$outputname" "@PROGRAM@" "no" # template prelinking step if test -n "$prelink_cmds"; then func_execute_cmds "$prelink_cmds" 'exit $?' fi wrappers_required=yes case $host in *cegcc* | *mingw32ce*) # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. wrappers_required=no ;; *cygwin* | *mingw* ) if test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; *) if test "$need_relink" = no || test "$build_libtool_libs" != yes; then wrappers_required=no fi ;; esac if test "$wrappers_required" = no; then # Replace the output file specification. compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` link_command="$compile_command$compile_rpath" # We have no uninstalled library dependencies, so finalize right now. exit_status=0 func_show_eval "$link_command" 'exit_status=$?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Delete the generated files. if test -f "$output_objdir/${outputname}S.${objext}"; then func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' fi exit $exit_status fi if test -n "$compile_shlibpath$finalize_shlibpath"; then compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" fi if test -n "$finalize_shlibpath"; then finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" fi compile_var= finalize_var= if test -n "$runpath_var"; then if test -n "$perm_rpath"; then # We should set the runpath_var. rpath= for dir in $perm_rpath; do func_append rpath "$dir:" done compile_var="$runpath_var=\"$rpath\$$runpath_var\" " fi if test -n "$finalize_perm_rpath"; then # We should set the runpath_var. rpath= for dir in $finalize_perm_rpath; do func_append rpath "$dir:" done finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " fi fi if test "$no_install" = yes; then # We don't need to create a wrapper script. link_command="$compile_var$compile_command$compile_rpath" # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` # Delete the old output file. $opt_dry_run || $RM $output # Link the executable and exit func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi exit $EXIT_SUCCESS fi if test "$hardcode_action" = relink; then # Fast installation is not supported link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" func_warning "this platform does not like uninstalled shared libraries" func_warning "\`$output' will be relinked during installation" else if test "$fast_install" != no; then link_command="$finalize_var$compile_command$finalize_rpath" if test "$fast_install" = yes; then relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` else # fast_install is set to needless relink_command= fi else link_command="$compile_var$compile_command$compile_rpath" relink_command="$finalize_var$finalize_command$finalize_rpath" fi fi # Replace the output file specification. link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` # Delete the old output files. $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname func_show_eval "$link_command" 'exit $?' if test -n "$postlink_cmds"; then func_to_tool_file "$output_objdir/$outputname" postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` func_execute_cmds "$postlink_cmds" 'exit $?' fi # Now create the wrapper script. func_verbose "creating $output" # Quote the relink command for shipping. if test -n "$relink_command"; then # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done relink_command="(cd `pwd`; $relink_command)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` fi # Only actually do things if not in dry run mode. $opt_dry_run || { # win32 will think the script is a binary if it has # a .exe suffix, so we strip it off here. case $output in *.exe) func_stripname '' '.exe' "$output" output=$func_stripname_result ;; esac # test for cygwin because mv fails w/o .exe extensions case $host in *cygwin*) exeext=.exe func_stripname '' '.exe' "$outputname" outputname=$func_stripname_result ;; *) exeext= ;; esac case $host in *cygwin* | *mingw* ) func_dirname_and_basename "$output" "" "." output_name=$func_basename_result output_path=$func_dirname_result cwrappersource="$output_path/$objdir/lt-$output_name.c" cwrapper="$output_path/$output_name.exe" $RM $cwrappersource $cwrapper trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 func_emit_cwrapperexe_src > $cwrappersource # The wrapper executable is built using the $host compiler, # because it contains $host paths and files. If cross- # compiling, it, like the target executable, must be # executed on the $host or under an emulation environment. $opt_dry_run || { $LTCC $LTCFLAGS -o $cwrapper $cwrappersource $STRIP $cwrapper } # Now, create the wrapper script for func_source use: func_ltwrapper_scriptname $cwrapper $RM $func_ltwrapper_scriptname_result trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 $opt_dry_run || { # note: this script will not be executed, so do not chmod. if test "x$build" = "x$host" ; then $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result else func_emit_wrapper no > $func_ltwrapper_scriptname_result fi } ;; * ) $RM $output trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 func_emit_wrapper no > $output chmod +x $output ;; esac } exit $EXIT_SUCCESS ;; esac # See if we need to build an old-fashioned archive. for oldlib in $oldlibs; do if test "$build_libtool_libs" = convenience; then oldobjs="$libobjs_save $symfileobj" addlibs="$convenience" build_libtool_libs=no else if test "$build_libtool_libs" = module; then oldobjs="$libobjs_save" build_libtool_libs=no else oldobjs="$old_deplibs $non_pic_objects" if test "$preload" = yes && test -f "$symfileobj"; then func_append oldobjs " $symfileobj" fi fi addlibs="$old_convenience" fi if test -n "$addlibs"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $addlibs func_append oldobjs " $func_extract_archives_result" fi # Do each command in the archive commands. if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then cmds=$old_archive_from_new_cmds else # Add any objects from preloaded convenience libraries if test -n "$dlprefiles"; then gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_extract_archives $gentop $dlprefiles func_append oldobjs " $func_extract_archives_result" fi # POSIX demands no paths to be encoded in archives. We have # to avoid creating archives with duplicate basenames if we # might have to extract them afterwards, e.g., when creating a # static archive out of a convenience library, or when linking # the entirety of a libtool archive into another (currently # not supported by libtool). if (for obj in $oldobjs do func_basename "$obj" $ECHO "$func_basename_result" done | sort | sort -uc >/dev/null 2>&1); then : else echo "copying selected object files to avoid basename conflicts..." gentop="$output_objdir/${outputname}x" func_append generated " $gentop" func_mkdir_p "$gentop" save_oldobjs=$oldobjs oldobjs= counter=1 for obj in $save_oldobjs do func_basename "$obj" objbase="$func_basename_result" case " $oldobjs " in " ") oldobjs=$obj ;; *[\ /]"$objbase "*) while :; do # Make sure we don't pick an alternate name that also # overlaps. newobj=lt$counter-$objbase func_arith $counter + 1 counter=$func_arith_result case " $oldobjs " in *[\ /]"$newobj "*) ;; *) if test ! -f "$gentop/$newobj"; then break; fi ;; esac done func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" func_append oldobjs " $gentop/$newobj" ;; *) func_append oldobjs " $obj" ;; esac done fi func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 tool_oldlib=$func_to_tool_file_result eval cmds=\"$old_archive_cmds\" func_len " $cmds" len=$func_len_result if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then cmds=$old_archive_cmds elif test -n "$archiver_list_spec"; then func_verbose "using command file archive linking..." for obj in $oldobjs do func_to_tool_file "$obj" $ECHO "$func_to_tool_file_result" done > $output_objdir/$libname.libcmd func_to_tool_file "$output_objdir/$libname.libcmd" oldobjs=" $archiver_list_spec$func_to_tool_file_result" cmds=$old_archive_cmds else # the command line is too long to link in one step, link in parts func_verbose "using piecewise archive linking..." save_RANLIB=$RANLIB RANLIB=: objlist= concat_cmds= save_oldobjs=$oldobjs oldobjs= # Is there a better way of finding the last object in the list? for obj in $save_oldobjs do last_oldobj=$obj done eval test_cmds=\"$old_archive_cmds\" func_len " $test_cmds" len0=$func_len_result len=$len0 for obj in $save_oldobjs do func_len " $obj" func_arith $len + $func_len_result len=$func_arith_result func_append objlist " $obj" if test "$len" -lt "$max_cmd_len"; then : else # the above command should be used before it gets too long oldobjs=$objlist if test "$obj" = "$last_oldobj" ; then RANLIB=$save_RANLIB fi test -z "$concat_cmds" || concat_cmds=$concat_cmds~ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" objlist= len=$len0 fi done RANLIB=$save_RANLIB oldobjs=$objlist if test "X$oldobjs" = "X" ; then eval cmds=\"\$concat_cmds\" else eval cmds=\"\$concat_cmds~\$old_archive_cmds\" fi fi fi func_execute_cmds "$cmds" 'exit $?' done test -n "$generated" && \ func_show_eval "${RM}r$generated" # Now create the libtool archive. case $output in *.la) old_library= test "$build_old_libs" = yes && old_library="$libname.$libext" func_verbose "creating $output" # Preserve any variables that may affect compiler behavior for var in $variables_saved_for_relink; do if eval test -z \"\${$var+set}\"; then relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" elif eval var_value=\$$var; test -z "$var_value"; then relink_command="$var=; export $var; $relink_command" else func_quote_for_eval "$var_value" relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" fi done # Quote the link command for shipping. relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` if test "$hardcode_automatic" = yes ; then relink_command= fi # Only create the output if not a dry run. $opt_dry_run || { for installed in no yes; do if test "$installed" = yes; then if test -z "$install_libdir"; then break fi output="$output_objdir/$outputname"i # Replace all uninstalled libtool libraries with the installed ones newdependency_libs= for deplib in $dependency_libs; do case $deplib in *.la) func_basename "$deplib" name="$func_basename_result" func_resolve_sysroot "$deplib" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` test -z "$libdir" && \ func_fatal_error "\`$deplib' is not a valid libtool archive" func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" ;; -L*) func_stripname -L '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -L$func_replace_sysroot_result" ;; -R*) func_stripname -R '' "$deplib" func_replace_sysroot "$func_stripname_result" func_append newdependency_libs " -R$func_replace_sysroot_result" ;; *) func_append newdependency_libs " $deplib" ;; esac done dependency_libs="$newdependency_libs" newdlfiles= for lib in $dlfiles; do case $lib in *.la) func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" ;; *) func_append newdlfiles " $lib" ;; esac done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in *.la) # Only pass preopened files to the pseudo-archive (for # eventual linking with the app. that links it) if we # didn't already link the preopened objects directly into # the library: func_basename "$lib" name="$func_basename_result" eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` test -z "$libdir" && \ func_fatal_error "\`$lib' is not a valid libtool archive" func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" ;; esac done dlprefiles="$newdlprefiles" else newdlfiles= for lib in $dlfiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlfiles " $abs" done dlfiles="$newdlfiles" newdlprefiles= for lib in $dlprefiles; do case $lib in [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; *) abs=`pwd`"/$lib" ;; esac func_append newdlprefiles " $abs" done dlprefiles="$newdlprefiles" fi $RM $output # place dlname in correct position for cygwin # In fact, it would be nice if we could use this code for all target # systems that can't hard-code library paths into their executables # and that have no shared library path variable independent of PATH, # but it turns out we can't easily determine that from inspecting # libtool variables, so we have to hard-code the OSs to which it # applies here; at the moment, that means platforms that use the PE # object format with DLL files. See the long comment at the top of # tests/bindir.at for full details. tdlname=$dlname case $host,$output,$installed,$module,$dlname in *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) # If a -bindir argument was supplied, place the dll there. if test "x$bindir" != x ; then func_relative_path "$install_libdir" "$bindir" tdlname=$func_relative_path_result$dlname else # Otherwise fall back on heuristic. tdlname=../bin/$dlname fi ;; esac $ECHO > $output "\ # $outputname - a libtool library file # Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION # # Please DO NOT delete this file! # It is necessary for linking the library. # The name that we can dlopen(3). dlname='$tdlname' # Names of this library. library_names='$library_names' # The name of the static archive. old_library='$old_library' # Linker flags that can not go in dependency_libs. inherited_linker_flags='$new_inherited_linker_flags' # Libraries that this one depends upon. dependency_libs='$dependency_libs' # Names of additional weak libraries provided by this library weak_library_names='$weak_libs' # Version information for $libname. current=$current age=$age revision=$revision # Is this an already installed library? installed=$installed # Should we warn about portability when linking against -modules? shouldnotlink=$module # Files to dlopen/dlpreopen dlopen='$dlfiles' dlpreopen='$dlprefiles' # Directory that this library needs to be installed in: libdir='$install_libdir'" if test "$installed" = no && test "$need_relink" = yes; then $ECHO >> $output "\ relink_command=\"$relink_command\"" fi done } # Do a symbolic link so that the libtool archive can be found in # LD_LIBRARY_PATH before the program is installed. func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' ;; esac exit $EXIT_SUCCESS } { test "$opt_mode" = link || test "$opt_mode" = relink; } && func_mode_link ${1+"$@"} # func_mode_uninstall arg... func_mode_uninstall () { $opt_debug RM="$nonopt" files= rmforce= exit_status=0 # This variable tells wrapper scripts just to set variables rather # than running their programs. libtool_install_magic="$magic" for arg do case $arg in -f) func_append RM " $arg"; rmforce=yes ;; -*) func_append RM " $arg" ;; *) func_append files " $arg" ;; esac done test -z "$RM" && \ func_fatal_help "you must specify an RM program" rmdirs= for file in $files; do func_dirname "$file" "" "." dir="$func_dirname_result" if test "X$dir" = X.; then odir="$objdir" else odir="$dir/$objdir" fi func_basename "$file" name="$func_basename_result" test "$opt_mode" = uninstall && odir="$dir" # Remember odir for removal later, being careful to avoid duplicates if test "$opt_mode" = clean; then case " $rmdirs " in *" $odir "*) ;; *) func_append rmdirs " $odir" ;; esac fi # Don't error if the file doesn't exist and rm -f was used. if { test -L "$file"; } >/dev/null 2>&1 || { test -h "$file"; } >/dev/null 2>&1 || test -f "$file"; then : elif test -d "$file"; then exit_status=1 continue elif test "$rmforce" = yes; then continue fi rmfiles="$file" case $name in *.la) # Possibly a libtool archive, so verify it. if func_lalib_p "$file"; then func_source $dir/$name # Delete the libtool libraries and symlinks. for n in $library_names; do func_append rmfiles " $odir/$n" done test -n "$old_library" && func_append rmfiles " $odir/$old_library" case "$opt_mode" in clean) case " $library_names " in *" $dlname "*) ;; *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; esac test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" ;; uninstall) if test -n "$library_names"; then # Do each command in the postuninstall commands. func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi if test -n "$old_library"; then # Do each command in the old_postuninstall commands. func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' fi # FIXME: should reinstall the best remaining shared library. ;; esac fi ;; *.lo) # Possibly a libtool object, so verify it. if func_lalib_p "$file"; then # Read the .lo file func_source $dir/$name # Add PIC object to the list of files to remove. if test -n "$pic_object" && test "$pic_object" != none; then func_append rmfiles " $dir/$pic_object" fi # Add non-PIC object to the list of files to remove. if test -n "$non_pic_object" && test "$non_pic_object" != none; then func_append rmfiles " $dir/$non_pic_object" fi fi ;; *) if test "$opt_mode" = clean ; then noexename=$name case $file in *.exe) func_stripname '' '.exe' "$file" file=$func_stripname_result func_stripname '' '.exe' "$name" noexename=$func_stripname_result # $file with .exe has already been added to rmfiles, # add $file without .exe func_append rmfiles " $file" ;; esac # Do a test to see if this is a libtool program. if func_ltwrapper_p "$file"; then if func_ltwrapper_executable_p "$file"; then func_ltwrapper_scriptname "$file" relink_command= func_source $func_ltwrapper_scriptname_result func_append rmfiles " $func_ltwrapper_scriptname_result" else relink_command= func_source $dir/$noexename fi # note $name still contains .exe if it was in $file originally # as does the version of $file that was added into $rmfiles func_append rmfiles " $odir/$name $odir/${name}S.${objext}" if test "$fast_install" = yes && test -n "$relink_command"; then func_append rmfiles " $odir/lt-$name" fi if test "X$noexename" != "X$name" ; then func_append rmfiles " $odir/lt-${noexename}.c" fi fi fi ;; esac func_show_eval "$RM $rmfiles" 'exit_status=1' done # Try to remove the ${objdir}s in the directories where we deleted files for dir in $rmdirs; do if test -d "$dir"; then func_show_eval "rmdir $dir >/dev/null 2>&1" fi done exit $exit_status } { test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && func_mode_uninstall ${1+"$@"} test -z "$opt_mode" && { help="$generic_help" func_fatal_help "you must specify a MODE" } test -z "$exec_cmd" && \ func_fatal_help "invalid operation mode \`$opt_mode'" if test -n "$exec_cmd"; then eval exec "$exec_cmd" exit $EXIT_FAILURE fi exit $exit_status # The TAGs below are defined such that we never get into a situation # in which we disable both kinds of libraries. Given conflicting # choices, we go for a static library, that is the most portable, # since we can't tell whether shared libraries were disabled because # the user asked for that or because the platform doesn't support # them. This is particularly important on AIX, because we don't # support having both static and shared libraries enabled at the same # time on that platform, so we default to a shared-only configuration. # If a disable-shared tag is given, we'll fallback to a static-only # configuration. But we'll never go from static-only to shared-only. # ### BEGIN LIBTOOL TAG CONFIG: disable-shared build_libtool_libs=no build_old_libs=yes # ### END LIBTOOL TAG CONFIG: disable-shared # ### BEGIN LIBTOOL TAG CONFIG: disable-static build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` # ### END LIBTOOL TAG CONFIG: disable-static # Local Variables: # mode:shell-script # sh-indentation:2 # End: # vi:sw=2 sg3_utils-1.40/COVERAGE0000664000175000017500000001334612430315266013477 0ustar douggdougg Command coverage ================ The following table lists SCSI commands in alphabetical order on the left and the sg3_utils (or related) utilities that implement invocations of them on the right. The second table lists supported ATA commands. SCSI command sg3_utils utilities that use this SCSI command ------------ ------------------------------------------------- ATA COMMAND PASS-THROUGH(16) sg_sat_identify, sg_sat_set_features, sg_sat_phy_event, sg_sat_read_gplog ++ [sg_sat_chk_power, sg__sat_identify, sg__sat_set_features, sg_sat_smart_rd_data (previous four in the examples directory)] ATA COMMAND PASS-THROUGH(12) sg_sat_identify, ++ COMPARE AND WRITE sg_compare_and_write COPY OPERATION ABORT ddptctl, ++ EXTENDED COPY(LID1) sg_xcopy, ddpt, ++ GET CONFIGURATION sg_get_config, ++ GET LBA STATUS sg_get_lba_status, ++ INQUIRY sg_dd, sg_format, sg_inq, sginfo, sg_logs, sg_map('-i'), sg_modes, sg_opcodes, sg_persist, sg_scan, sg_ses, sg_vpd ++ FORMAT UNIT sg_format, ++ LOG SELECT sg_logs('-r' or '-select'), ++ LOG SENSE sg_logs, ++ MODE SELECT(6) sdparm, sg_wr_mode, sginfo, sg_format, sg_emc_trespass, sg_rdac, ++ MODE SELECT(10) sdparm, sg_wr_mode, sginfo, sg_format, sg_emc_trespass, sg_rdac, ++ MODE SENSE(6) sdparm, sg_modes, sg_wr_mode, sginfo, sg_format, sg_senddiag('-e'), sg_rdac, ++ MODE SENSE(10) sdparm, sg_modes, sg_wr_mode, sginfo, sg_format, sg_senddiag('-e'), sg_rdac, ++ PERSISTENT RESERVE IN sg_persist, ++ PERSISTENT RESERVE OUT sg_persist, ++ POPULATE TOKEN ddpt, ddptctl, ++ PREVENT ALLOW MEDIUM REMOVAL sg_prevent, ++ READ(6) sg_dd, sgm_dd, sgp_dd, sg_read READ(10) sg_dd, sgm_dd, sgp_dd, sg_read READ(12) sg_dd, sgm_dd, sgp_dd, sg_read READ(16) sg_dd, sgm_dd, sgp_dd, sg_read READ BLOCK LIMITS sg_read_block_limits, ++ READ BUFFER sg_rbuf, sg_test_rwbuf, sg_read_buffer, sg_safte, ++ READ CAPACITY(10) sg_readcap, sg_dd, sgm_dd, sgp_dd, sg_format, ++ READ CAPACITY(16) sg_readcap, sg_dd, sgm_dd, sgp_dd, sg_format, ++ READ DEFECT(10) sginfo('-d' or '-G'), sg_reassign('-g'), smartmontools, ++ READ DEFECT(12) sginfo('-d' or '-G'), smartmontools READ LONG(10) sg_read_long, sg_dd, ++ READ LONG(16) sg_read_long, ++ READ MEDIA SERIAL NUMBER sg_rmsn, ++ REASSIGN BLOCKS sg_reassign, ++ RECEIVE COPY DATA(LID1) sg_copy_results, ++ RECEIVE COPY FAILURE DETAILS(LID1) sg_copy_results, ++ RECEIVE COPY OPERATING PARAMETERS ddpt, sg_copy_results, sg_xcopy, ++ RECEIVE COPY STATUS(LID1) sg_copy_results, ++ RECEIVE DIAGNOSTIC RESULTS sg_senddiag, sg_ses, sg_ses_microcode ++ RECEIVE ROD TOKEN INFORMATION ddpt, ddptctl ++ REPORT ALL ROD TOKENS ddptctl ++ REPORT IDENTIFYING INFORMATION sg_ident, ++ (2) REPORT LUNS sg_luns, ++ REPORT REFERRALS sg_referrals, ++ REPORT SUPPORTED OPERATION CODES sg_opcodes REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS sg_opcodes REPORT TARGET PORT GROUPS sg_rtpg, sg_stpg ++ REPORT ZONES sg_rep_zones REQUEST SENSE sg_requests, ++ RESET WRITE POINTER sg_reset_wp SANITIZE sg_sanitize SEND DIAGNOSTIC sg_senddiag, sg_ses, sg_ses_microcode ++ SET IDENTIFYING INFORMATION sg_ident, ++ (3) SET TARGET PORT GROUPS sg_stpg, ++ START STOP sg_start, ++ SYNCHRONIZE CACHE(10) sg_sync, sg_dd, sgm_dd, sgp_dd, ++ SYNCHRONIZE CACHE(16) sg_sync++ TEST UNIT READY sg_turs, sg_format, ++ UNMAP sg_unmap, ++ VERIFY(10) sg_verify, ++ VERIFY(16) sg_verify, ++ WRITE(6) sg_dd, sgm_dd, sgp_dd WRITE(10) sg_dd, sgm_dd, sgp_dd WRITE(12) sg_dd, sgm_dd, sgp_dd WRITE(16) sg_dd, sgm_dd, sgp_dd WRITE AND VERIFY(10) sg_write_verify WRITE AND VERIFY(16) sg_write_verify WRITE ATOMIC(16) ddpt WRITE BUFFER sg_test_rwbuf, sg_write_buffer, ++ WRITE LONG(10) sg_write_long, ++ WRITE LONG(16) sg_write_long, ++ WRITE SAME(10) sg_write_same WRITE SAME(16) sg_write_same WRITE SAME(32) sg_write_same WRITE USING TOKEN ddpt, ddptctl, ++ sg_raw ATA command sg3_utils utilities that use this SCSI command ----------- ---------------------------------------------- CHECK POWER MODE examples/sg_sat_chk_power IDENTIFY DEVICE sg_inq, sg_scan, sg_sat_identify, examples/sg__sat_identify IDENTIFY PACKET DEVICE sg_inq, sg_sat_identify, examples/sg__sat_identify READ LOG EXT sg_sat_phy_event, examples/sg__sat_phy_event sg_sat_read_gplog READ LOG DMA EXT sg_sat_read_gplog SET FEATURES sg_sat_set_features examples/sg__sat_set_features SMART READ DATA examples/sg_sat_smart_rd_data ++ command wrapper found in sg_cmds_basic.c, sg_cmds_mmc.c or sg_cmds_extra.c for this command (2) this command was known as REPORT DEVICE IDENTIFIER prior to spc4r07 (3) this command was known as SET DEVICE IDENTIFIER prior to spc4r07 Note that any SCSI command, including bi-directional and variable length commands (whose cdb size is > 16 bytes) can be issued by the sg_raw utility. The RECEIVE COPY * commands in SPC-4 were grouped as one command name with 4 service actions in SPC-3 and earlier. The single SPC-3 command name is RECEIVE COPY RESULTS. The two opcodes associated with all EXTENDED COPY commands are now known as THIRD PARTY COPY IN (0x84) and THIRD PARTY COPY IN (0x83). Douglas Gilbert 7th November 2014 sg3_utils-1.40/README.freebsd0000664000175000017500000001076312076116252014652 0ustar douggdouggIntroduction ============ The FreeBSD port of sg3_utils contains those utilities that are _not_ specific to Linux. In some cases the FreeBSD camcontrol command supplies similar functionality; for example 'sg_map' is similar to 'camcontrol devlist'. The dd variants from the sg3_utils package (e.g. sg_dd) rely on too many Linux idiosyncrasies to be easily ported. A new package called 'ddpt' contains a utility with similar functionality to sg_dd and ddpt is available for FreeBSD. Supported Utilities =================== Here is a list of utilities that have been ported: sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident sg_inq [dropped ATA IDENTIFY DEVICE capability] sg_logs sg_luns sg_modes sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_read_block_limits sg_read_buffer sg_read_long sg_readcap sg_reassign sg_referrals sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync sg_turs sg_verify sg_unmap sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same Most utility names are indicative of the main SCSI command that they execute. Some utilities are slightly higher level, for example sg_ses fetches SCSI Enclosure Services (SES) status pages and can send control pages. Each utility has a man page (placed in section 8). An overview of sg3_utils can be found at: http://sg.danny.cz/sg/sg3_utils.html . A copy of the "sg3_utils.html" file is in the "doc" subdirectory. The executables and library can be built from the source code in the tarball and installed with the familiar "./configure ; make ; make install" sequence. If this fails try running the "./autogen.sh" script prior to that sequence. There are generic instruction on configure and friend in the INSTALL file. Some man pages have examples which use Linux device names which hopefully will not confuse the FreeBSD users. Device naming ============= In FreeBSD disks have block names like '/dev/da0' with a corresponding pass-through device name like '/dev/pass0'. Use this command "camcontrol devlist" to see that SCSI devices available. FreeBSD installation ==================== The traditional './configure ; make ; make install' sequence from the top level of the unpacked tarball will work on FreeBSD. But the man pages will be placed under the /usr/local/share/man directory which unfortunately is not on the standard manpath. One solution is to add this path by creating a file with a name like local_share.conf in the /usr/local/etc/man.d/ directory and placing this line in it: MANPATH /usr/local/share/man FreeBSD 9.0 has a "ports" entry for sg3_utils under the /usr/ports/sysutils directory. It points to version 1.28 of sg3_utils which is now a bit dated. It could be used as a template to point to more recent versions. kFreeBSD ======== sg3_utils can be built into a Debian package for kFreeBSD using the ./build_debian.sh script in the top level directory. This has been tested with Debian 6.0 release. Details ======= Most of the ported utilities listed above use SCSI command functions declared in sg_cmds_*.h headers . Those SCSI command functions are implemented in the corresponding ".c" files. The ".c" files pass SCSI commands to the host operating system via an interface declared in sg_pt.h . There are currently five implementations of that interface depending on the host operating system: - sg_pt_linux.c - sg_pt_freebsd.c - sg_pt_osf1.c [Tru64] - sg_pt_win32.c - sg_pt_solaris.c The sg_pt_freebsd.c file uses the FreeBSD CAM SCSI pass through mechanism. Hence only FreeBSD device nodes that support CAM can be used. These can be viewed with the "camcontrol devlist" command. To access ATAPI devices (e.g. ATAPI DVD drives) the kernel may need to be configured with the "atapicam" device. Attempts to send SCSI commands with data-in or data-out buffers around 64 KB and larger failed on a FreeBSD 7.0 with an "argument list too long" error message. There is an associated kernel message (viewable with dmesg) that an attempt has been made to map bytes which is greater than DFLTPHYS(65536). Still a problem in FreeBSD 8.1 . Due to CAM overhead the largest power of 2 that can fit through with one command is 32768 bytes (32 KB). FreeBSD 9.0 is the most recent version of FreeBSD tested with these utilities. Douglas Gilbert 14th January 2013 sg3_utils-1.40/build_debian.sh0000775000175000017500000000074312144707462015323 0ustar douggdougg#!/bin/sh # If this script fails on a Debian 4.0 ("etch") system then read # the debian/README.debian4 file. echo "chmod +x debian/rules" chmod +x debian/rules # in some environments the '-rfakeroot' can cause a failure (e.g. when # building as root). If so, remove that argument from the following: echo "dpkg-buildpackage -b -rfakeroot -us -uc" dpkg-buildpackage -b -rfakeroot -us -uc # If the above succeeds then the ".deb" binary package is placed in the # parent directory. sg3_utils-1.40/INSTALL0000664000175000017500000002270111170007606013401 0ustar douggdouggInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== Briefly, the shell commands './configure; make; make install' should configure, build, and install this package. If that fails try doing './autogen.sh' first and then repeat the above sequence. The autogen.sh script may require some autotools packages to be loaded. The following more detailed instructions are generic; see the `README' file for instructions specific to this package. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. Running `configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 6. Often, you can also type `make uninstall' to remove the installed files again. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. With a non-GNU `make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for `CONFIG_SHELL' due to an Autoconf bug. Until the bug is fixed you can use this workaround: CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. sg3_utils-1.40/depcomp0000775000175000017500000005601612234470316013737 0ustar douggdougg#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # 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. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: sg3_utils-1.40/src/0000755000175000017500000000000012431015530013127 5ustar douggdouggsg3_utils-1.40/src/sgm_dd.c0000664000175000017500000014405312335513125014547 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2014 D. Gilbert and P. Allworth * 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. This program is a specialisation of the Unix "dd" command in which either the input or the output file is a scsi generic device or a raw device. The block size ('bs') is assumed to be 512 if not given. This program complains if 'ibs' or 'obs' are given with a value that differs from 'bs' (or the default 512). If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is not given or 'of=-' then stdout assumed. A non-standard argument "bpt" (blocks per transfer) is added to control the maximum number of blocks in each transfer. The default value is 128. For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB in this case) is transferred to or from the sg device in a single SCSI command. This version uses memory-mapped transfers (i.e. mmap() call from the user space) to speed transfers. If both sides of copy are sg devices then only the read side will be mmap-ed, while the write side will use normal IO. This version is designed for the linux kernel 2.4, 2.6 and 3 series. */ #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include #include #include /* */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" /* #define SG_WANT_SHARED_MMAP_IO 1 */ #ifdef SG_WANT_SHARED_MMAP_IO static const char * version_str = "1.39 20140516 shared_mmap"; #else static const char * version_str = "1.39 20140516"; #endif #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 ME "sgm_dd: " /* #define SG_DEBUG */ #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #ifndef SERVICE_ACTION_IN #define SERVICE_ACTION_IN 0x9e #endif #ifndef SAI_READ_CAPACITY_16 #define SAI_READ_CAPACITY_16 0x10 #endif #ifdef SG_WANT_SHARED_MMAP_IO #ifndef SG_FLAG_SHARED_MMAP_IO #define SG_FLAG_SHARED_MMAP_IO 8 #endif #ifndef SG_INFO_SHARED_MMAP_IO #define SG_INFO_SHARED_MMAP_IO 8 #endif #endif #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikey value */ #endif #define FT_OTHER 1 /* filetype other than one of following */ #define FT_SG 2 /* filetype is sg char device */ #define FT_RAW 4 /* filetype is raw char device */ #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */ #define FT_ST 16 /* filetype is st char device (tape) */ #define FT_BLOCK 32 /* filetype is a block device */ #define FT_ERROR 64 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 #define MIN_RESERVED_SIZE 8192 static int sum_of_resids = 0; static int64_t dd_count = -1; static int64_t req_count = 0; static int64_t in_full = 0; static int in_partial = 0; static int64_t out_full = 0; static int out_partial = 0; static int verbose = 0; static int do_time = 0; static int start_tm_valid = 0; static struct timeval start_tm; static int blk_sz = 0; #ifdef SG_WANT_SHARED_MMAP_IO static int shared_mm_req = 0; static int shared_mm_done = 0; #endif static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; struct flags_t { int append; int dio; int direct; int dpo; int dsync; int excl; int fua; #ifdef SG_WANT_SHARED_MMAP_IO int smmap; #endif }; static void install_handler(int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } static void print_stats() { if (0 != dd_count) fprintf(stderr, " remaining block count=%" PRId64 "\n", dd_count); fprintf(stderr, "%" PRId64 "+%d records in\n", in_full - in_partial, in_partial); fprintf(stderr, "%" PRId64 "+%d records out\n", out_full - out_partial, out_partial); } static void calc_duration_throughput(int contin) { struct timeval end_tm, res_tm; double a, b; if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) { 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)blk_sz * (req_count - dd_count); fprintf(stderr, "time to transfer data%s: %d.%06d secs", (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) fprintf(stderr, " at %.2f MB/sec\n", b / (a * 1000000.0)); else fprintf(stderr, "\n"); } } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig, &sigact, NULL); fprintf(stderr, "Interrupted by signal,"); print_stats (); if (do_time) calc_duration_throughput(0); kill (getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ fprintf(stderr, "Progress report, continuing ...\n"); print_stats(); if (do_time) calc_duration_throughput(1); } static int dd_filetype(const char * filename) { struct stat st; size_t len = strlen(filename); if ((1 == len) && ('.' == filename[0])) return FT_DEV_NULL; if (stat(filename, &st) < 0) return FT_ERROR; if (S_ISCHR(st.st_mode)) { if ((MEM_MAJOR == major(st.st_rdev)) && (DEV_NULL_MINOR_NUM == minor(st.st_rdev))) return FT_DEV_NULL; if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; return FT_OTHER; } static char * dd_filetype_str(int ft, char * buff) { int off = 0; if (FT_DEV_NULL & ft) off += snprintf(buff + off, 32, "null device "); if (FT_SG & ft) off += snprintf(buff + off, 32, "SCSI generic (sg) device "); if (FT_BLOCK & ft) off += snprintf(buff + off, 32, "block device "); if (FT_ST & ft) off += snprintf(buff + off, 32, "SCSI tape device "); if (FT_RAW & ft) off += snprintf(buff + off, 32, "raw device "); if (FT_OTHER & ft) off += snprintf(buff + off, 32, "other (perhaps ordinary file) "); if (FT_ERROR & ft) off += snprintf(buff + off, 32, "unable to 'stat' file "); return buff; } static void usage() { fprintf(stderr, "Usage: " "sgm_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]" " [iflag=FLAGS]\n" " [obs=BS] [of=OFILE] [oflag=FLAGS] " "[seek=SEEK] [skip=SKIP]\n" " [--help] [--version]\n\n"); fprintf(stderr, " [bpt=BPT] [cdbsz=6|10|12|16] [dio=0|1] " "[fua=0|1|2|3]\n" " [sync=0|1] [time=0|1] [verbose=VERB]\n\n" " where:\n" " bpt is blocks_per_transfer (default is 128)\n" " bs must be device block size (default 512)\n" " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n" " count number of blocks to copy (def: device size)\n" " dio 0->indirect IO on write, 1->direct IO on write\n" " (only when read side is sg device (using mmap))\n" " fua force unit access: 0->don't(def), 1->OFILE, " "2->IFILE,\n" " 3->OFILE+IFILE\n" " if file or device to read from (def: stdin)\n"); fprintf(stderr, " iflag comma separated list from: [direct,dpo,dsync," "excl,fua,\n" " null]\n" " of file or device to write to (def: stdout), " "OFILE of '.'\n" " treated as /dev/null\n" " oflag comma separated list from: [append,dio,direct," "dpo,dsync,\n" #ifdef SG_WANT_SHARED_MMAP_IO " excl,fua,null,smmap]\n" #else " excl,fua,null]\n" #endif " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE " "after copy\n" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose 0->quiet(def), 1->some noise, 2->more noise, " "etc\n" " --help print usage message then exit\n" " --version print version information then exit\n\n" "Copy from IFILE to OFILE, similar to dd command\n" "specialized for SCSI devices for which mmap-ed IO attempted\n"); } /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { int k, res; unsigned int ui; unsigned char rcBuff[RCAP16_REPLY_LEN]; int verb; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0, verb); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { int64_t ls; res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0, verb); if (0 != res) return res; for (k = 0, ls = 0; k < 8; ++k) { ls <<= 8; ls |= rcBuff[k]; } *num_sect = ls + 1; *sect_sz = (rcBuff[8] << 24) | (rcBuff[9] << 16) | (rcBuff[10] << 8) | rcBuff[11]; } else { ui = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]); /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)ui + 1; *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | (rcBuff[6] << 8) | rcBuff[7]; } if (verbose) fprintf(stderr, " number of blocks=%" PRId64 " [0x%" PRIx64 "], block size=%d\n", *num_sect, *num_sect, *sect_sz); return 0; } /* Return of 0 -> success, -1 -> failure. BLKGETSIZE64, BLKGETSIZE and */ /* BLKSSZGET macros problematic (from or ). */ static int read_blkdev_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { #ifdef BLKSSZGET if ((ioctl(sg_fd, BLKSSZGET, sect_sz) < 0) && (*sect_sz > 0)) { perror("BLKSSZGET ioctl error"); return -1; } else { #ifdef BLKGETSIZE64 uint64_t ull; if (ioctl(sg_fd, BLKGETSIZE64, &ull) < 0) { perror("BLKGETSIZE64 ioctl error"); return -1; } *num_sect = ((int64_t)ull / (int64_t)*sect_sz); if (verbose) fprintf(stderr, " [bgs64] number of blocks=%" PRId64 " [0x%" PRIx64 "], block size=%d\n", *num_sect, *num_sect, *sect_sz); #else unsigned long ul; if (ioctl(sg_fd, BLKGETSIZE, &ul) < 0) { perror("BLKGETSIZE ioctl error"); return -1; } *num_sect = (int64_t)ul; if (verbose) fprintf(stderr, " [bgs] number of blocks=%" PRId64 " [0x%" PRIx64 "], block size=%d\n", *num_sect, *num_sect, *sect_sz); #endif } return 0; #else if (verbose) fprintf(stderr, " BLKSSZGET+BLKGETSIZE ioctl not available\n"); *num_sect = 0; *sect_sz = 0; return -1; #endif } static int sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, int write_true, int fua, int dpo) { int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f); cdbp[2] = (unsigned char)((start_block >> 8) & 0xff); cdbp[3] = (unsigned char)(start_block & 0xff); cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks; if (blocks > 256) { fprintf(stderr, ME "for 6 byte commands, maximum number of " "blocks is 256\n"); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { fprintf(stderr, ME "for 6 byte commands, can't address blocks" " beyond %d\n", 0x1fffff); return 1; } if (dpo || fua) { fprintf(stderr, ME "for 6 byte commands, neither dpo nor fua" " bits supported\n"); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[7] = (unsigned char)((blocks >> 8) & 0xff); cdbp[8] = (unsigned char)(blocks & 0xff); if (blocks & (~0xffff)) { fprintf(stderr, ME "for 10 byte commands, maximum number of " "blocks is %d\n", 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[6] = (unsigned char)((blocks >> 24) & 0xff); cdbp[7] = (unsigned char)((blocks >> 16) & 0xff); cdbp[8] = (unsigned char)((blocks >> 8) & 0xff); cdbp[9] = (unsigned char)(blocks & 0xff); break; case 16: sz_ind = 3; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 56) & 0xff); cdbp[3] = (unsigned char)((start_block >> 48) & 0xff); cdbp[4] = (unsigned char)((start_block >> 40) & 0xff); cdbp[5] = (unsigned char)((start_block >> 32) & 0xff); cdbp[6] = (unsigned char)((start_block >> 24) & 0xff); cdbp[7] = (unsigned char)((start_block >> 16) & 0xff); cdbp[8] = (unsigned char)((start_block >> 8) & 0xff); cdbp[9] = (unsigned char)(start_block & 0xff); cdbp[10] = (unsigned char)((blocks >> 24) & 0xff); cdbp[11] = (unsigned char)((blocks >> 16) & 0xff); cdbp[12] = (unsigned char)((blocks >> 8) & 0xff); cdbp[13] = (unsigned char)(blocks & 0xff); break; default: fprintf(stderr, ME "expected cdb size of 6, 10, 12, or 16 but got" " %d\n", cdb_sz); return 1; } return 0; } /* Returns 0 -> successful, various SG_LIB_CAT_* positive values, * -2 -> recoverable (ENOMEM), -1 -> unrecoverable error */ static int sg_read(int sg_fd, unsigned char * buff, int blocks, int64_t from_block, int bs, int cdbsz, int fua, int dpo, int do_mmap) { unsigned char rdCmd[MAX_SCSI_CDBSZ]; unsigned char senseBuff[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; int k, res; if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, dpo)) { fprintf(stderr, ME "bad rd cdb build, from_block=%" PRId64 ", blocks=%d\n", from_block, blocks); return SG_LIB_SYNTAX_ERROR; } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = cdbsz; io_hdr.cmdp = rdCmd; io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = bs * blocks; if (! do_mmap) io_hdr.dxferp = buff; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = (int)from_block; if (do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; if (verbose > 2) { fprintf(stderr, " read cdb: "); for (k = 0; k < cdbsz; ++k) fprintf(stderr, "%02x ", rdCmd[k]); fprintf(stderr, "\n"); } #if 1 while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)) sleep(1); if (res < 0) { perror(ME "SG_IO error (sg_read)"); return -1; } #else while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return -2; perror("reading (wr) on sg device, error"); return -1; } while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { perror("reading (rd) on sg device, error"); return -1; } #endif if (verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("Reading, continuing", &io_hdr, verbose > 1); break; case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_MEDIUM_HARD: return res; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_ILLEGAL_REQ: default: sg_chk_n_print3("reading", &io_hdr, verbose > 1); return res; } sum_of_resids += io_hdr.resid; #ifdef SG_DEBUG fprintf(stderr, "duration=%u ms\n", io_hdr.duration); #endif return 0; } /* Returns 0 -> successful, various SG_LIB_CAT_* positive values, * -2 -> recoverable (ENOMEM), -1 -> unrecoverable error */ static int sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block, int bs, int cdbsz, int fua, int dpo, int do_mmap, #ifdef SG_WANT_SHARED_MMAP_IO int mmap_shareable, #endif int * diop) { unsigned char wrCmd[MAX_SCSI_CDBSZ]; unsigned char senseBuff[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; int k, res; if (sg_build_scsi_cdb(wrCmd, cdbsz, blocks, to_block, 1, fua, dpo)) { fprintf(stderr, ME "bad wr cdb build, to_block=%" PRId64 ", blocks=%d\n", to_block, blocks); return SG_LIB_SYNTAX_ERROR; } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = cdbsz; io_hdr.cmdp = wrCmd; io_hdr.dxfer_direction = SG_DXFER_TO_DEV; io_hdr.dxfer_len = bs * blocks; #ifdef SG_WANT_SHARED_MMAP_IO if (mmap_shareable || (! do_mmap)) #else if (! do_mmap) #endif io_hdr.dxferp = buff; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = (int)to_block; #ifdef SG_WANT_SHARED_MMAP_IO if (mmap_shareable) { io_hdr.flags |= SG_FLAG_SHARED_MMAP_IO; ++shared_mm_req; } else #endif /* nasty conditional split */ if (do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; else if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (verbose > 2) { fprintf(stderr, " write cdb: "); for (k = 0; k < cdbsz; ++k) fprintf(stderr, "%02x ", wrCmd[k]); fprintf(stderr, "\n"); } #if 1 while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)) sleep(1); if (res < 0) { perror(ME "SG_IO error (sg_write)"); return -1; } #else while (((res = write(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return -2; perror("writing (wr) on sg device, error"); return -1; } while (((res = read(sg_fd, &io_hdr, sizeof(io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { perror("writing (rd) on sg device, error"); return -1; } #endif if (verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("Writing, continuing", &io_hdr, verbose > 1); break; case SG_LIB_CAT_NOT_READY: case SG_LIB_CAT_MEDIUM_HARD: return res; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: case SG_LIB_CAT_ILLEGAL_REQ: default: sg_chk_n_print3("writing", &io_hdr, verbose > 1); return res; } #ifdef SG_WANT_SHARED_MMAP_IO if ((mmap_shareable) && (SG_INFO_SHARED_MMAP_IO & io_hdr.info)) ++shared_mm_done; #endif if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = 0; /* flag that dio not done (completely) */ return 0; } static int process_flags(const char * arg, struct flags_t * fp) { char buff[256]; char * cp; char * np; strncpy(buff, arg, sizeof(buff)); buff[sizeof(buff) - 1] = '\0'; if ('\0' == buff[0]) { fprintf(stderr, "no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = 1; else if (0 == strcmp(cp, "dio")) fp->dio = 1; else if (0 == strcmp(cp, "direct")) fp->direct = 1; else if (0 == strcmp(cp, "dpo")) fp->dpo = 1; else if (0 == strcmp(cp, "dsync")) fp->dsync = 1; else if (0 == strcmp(cp, "excl")) fp->excl = 1; else if (0 == strcmp(cp, "fua")) fp->fua = 1; else if (0 == strcmp(cp, "null")) ; #ifdef SG_WANT_SHARED_MMAP_IO else if (0 == strcmp(cp, "smmap")) fp->smmap = 1; #endif else { fprintf(stderr, "unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 512 int main(int argc, char * argv[]) { int64_t skip = 0; int64_t seek = 0; int ibs = 0; int obs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int bpt_given = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; int in_type = FT_OTHER; char outf[INOUTF_SZ]; int out_type = FT_OTHER; int res, k, t; int infd, outfd, blocks; unsigned char * wrkPos; unsigned char * wrkBuff = NULL; unsigned char * wrkMmap = NULL; int64_t in_num_sect = -1; int in_res_sz = 0; int64_t out_num_sect = -1; int out_res_sz = 0; int scsi_cdbsz_in = DEF_SCSI_CDBSZ; int scsi_cdbsz_out = DEF_SCSI_CDBSZ; int cdbsz_given = 0; int do_coe = 0; /* dummy, just accept + ignore */ int do_sync = 0; int num_dio_not_done = 0; int in_sect_sz, out_sect_sz; int n, flags; char ebuff[EBUFF_SZ]; char b[80]; int blocks_per; size_t psz; struct flags_t in_flags; struct flags_t out_flags; #ifdef SG_WANT_SHARED_MMAP_IO int mmap_shareable = 0; #endif int ret = 0; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif inf[0] = '\0'; outf[0] = '\0'; memset(&in_flags, 0, sizeof(in_flags)); memset(&out_flags, 0, sizeof(out_flags)); for (k = 1; k < argc; k++) { if (argv[k]) strncpy(str, argv[k], STR_SZ); else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (0 == strcmp(key,"bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { fprintf(stderr, ME "bad argument to 'bpt'\n"); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key,"bs")) { blk_sz = sg_get_num(buf); if (-1 == blk_sz) { fprintf(stderr, ME "bad argument to 'bs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { scsi_cdbsz_in = sg_get_num(buf); scsi_cdbsz_out = scsi_cdbsz_in; cdbsz_given = 1; } else if (0 == strcmp(key,"coe")) { do_coe = sg_get_num(buf); /* dummy, just accept + ignore */ if (do_coe) { ; } /* unused, dummy to suppress warning */ } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if (-1LL == dd_count) { fprintf(stderr, ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key,"dio")) out_flags.dio = sg_get_num(buf); else if (0 == strcmp(key,"fua")) { n = sg_get_num(buf); if (n & 1) out_flags.fua = 1; if (n & 2) in_flags.fua = 1; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if (-1 == ibs) { fprintf(stderr, ME "bad argument to 'ibs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { if ('\0' != inf[0]) { fprintf(stderr, "Second 'if=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(inf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &in_flags)) { fprintf(stderr, ME "bad argument to 'iflag'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { if ('\0' != outf[0]) { fprintf(stderr, "Second 'of=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(outf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &out_flags)) { fprintf(stderr, ME "bad argument to 'oflag'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if (-1 == obs) { fprintf(stderr, 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) { fprintf(stderr, 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) { fprintf(stderr, ME "bad argument to 'skip'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"sync")) do_sync = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "verb", 4)) verbose = sg_get_num(buf); else if ((0 == strncmp(key, "--help", 7)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if ((0 == strncmp(key, "--vers", 6)) || (0 == strcmp(key, "-V"))) { fprintf(stderr, ME ": %s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized option '%s'\n", key); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (blk_sz <= 0) { blk_sz = DEF_BLOCK_SIZE; fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", blk_sz); } if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) { fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { fprintf(stderr, "skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if ((out_flags.append > 0) && (seek > 0)) { fprintf(stderr, "Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (bpt < 1) { fprintf(stderr, "bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } /* defaulting transfer size to 128*2048 for CD/DVDs is too large for the block layer in lk 2.6 and results in an EIO on the SG_IO ioctl. So reduce it in that case. */ if ((blk_sz >= 2048) && (0 == bpt_given)) bpt = DEF_BLOCKS_PER_2048TRANSFER; #ifdef SG_DEBUG fprintf(stderr, ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", inf, skip, outf, seek, dd_count); #endif install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); infd = STDIN_FILENO; outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { in_type = dd_filetype(inf); if (verbose) fprintf(stderr, " >> Input file type: %s\n", dd_filetype_str(in_type, ebuff)); if (FT_ERROR == in_type) { fprintf(stderr, ME "unable to access %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_ST == in_type) { fprintf(stderr, ME "unable to use scsi tape device %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_SG == in_type) { flags = O_RDWR | O_NONBLOCK; if (in_flags.direct) flags |= O_DIRECT; if (in_flags.excl) flags |= O_EXCL; if (in_flags.dsync) flags |= O_SYNC; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { fprintf(stderr, ME "sg driver prior to 3.1.22\n"); return SG_LIB_FILE_ERROR; } in_res_sz = blk_sz * bpt; if (0 != (in_res_sz % psz)) /* round up to next page */ in_res_sz = ((in_res_sz / psz) + 1) * psz; if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) < 0) { perror(ME "SG_GET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } if (t < MIN_RESERVED_SIZE) t = MIN_RESERVED_SIZE; if (in_res_sz > t) { if (ioctl(infd, SG_SET_RESERVED_SIZE, &in_res_sz) < 0) { perror(ME "SG_SET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } } wrkMmap = (unsigned char *)mmap(NULL, in_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); if (MAP_FAILED == wrkMmap) { snprintf(ebuff, EBUFF_SZ, ME "error using mmap() on file: %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } #ifdef SG_WANT_SHARED_MMAP_IO mmap_shareable = 1; #endif } else { flags = O_RDONLY; if (in_flags.direct) flags |= O_DIRECT; if (in_flags.excl) flags |= O_EXCL; if (in_flags.dsync) flags |= O_SYNC; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } else if (skip > 0) { off64_t offset = skip; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, " >> skip: lseek64 SEEK_SET, " "byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if (outf[0] && ('-' != outf[0])) { out_type = dd_filetype(outf); if (verbose) fprintf(stderr, " >> Output file type: %s\n", dd_filetype_str(out_type, ebuff)); if (FT_ST == out_type) { fprintf(stderr, ME "unable to use scsi tape device %s\n", outf); return SG_LIB_FILE_ERROR; } else if (FT_SG == out_type) { flags = O_RDWR | O_NONBLOCK; if (out_flags.direct) flags |= O_DIRECT; if (out_flags.excl) flags |= O_EXCL; if (out_flags.dsync) flags |= O_SYNC; if ((outfd = open(outf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for " "sg writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } res = ioctl(outfd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30122)) { fprintf(stderr, ME "sg driver prior to 3.1.22\n"); return SG_LIB_FILE_ERROR; } if (ioctl(outfd, SG_GET_RESERVED_SIZE, &t) < 0) { perror(ME "SG_GET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } if (t < MIN_RESERVED_SIZE) t = MIN_RESERVED_SIZE; out_res_sz = blk_sz * bpt; if (out_res_sz > t) { if (ioctl(outfd, SG_SET_RESERVED_SIZE, &out_res_sz) < 0) { perror(ME "SG_SET_RESERVED_SIZE error"); return SG_LIB_FILE_ERROR; } } if (NULL == wrkMmap) { wrkMmap = (unsigned char *)mmap(NULL, out_res_sz, PROT_READ | PROT_WRITE, MAP_SHARED, outfd, 0); if (MAP_FAILED == wrkMmap) { snprintf(ebuff, EBUFF_SZ, ME "error using mmap() on file: %s", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } } else if (FT_DEV_NULL == out_type) outfd = -1; /* don't bother opening */ else { if (FT_RAW != out_type) { flags = O_WRONLY | O_CREAT; if (out_flags.direct) flags |= O_DIRECT; if (out_flags.excl) flags |= O_EXCL; if (out_flags.dsync) flags |= O_SYNC; if (out_flags.append) flags |= O_APPEND; if ((outfd = open(outf, flags, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } else { if ((outfd = open(outf, O_WRONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s " "for raw writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } if (seek > 0) { off64_t offset = seek; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to " "required position on %s", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, " >> seek: lseek64 SEEK_SET, " "byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } } if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { fprintf(stderr, "Won't default both IFILE to stdin _and_ OFILE " "to as stdout\n"); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if (dd_count < 0) { in_num_sect = -1; if (FT_SG == in_type) { res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention(in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "Aborted command(in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read capacity (if=%s): %s\n", inf, b); in_num_sect = -1; } } else if (FT_BLOCK == in_type) { if (0 != read_blkdev_capacity(infd, &in_num_sect, &in_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (blk_sz != in_sect_sz) { fprintf(stderr, "block size on %s confusion; bs=%d, from " "device=%d\n", inf, blk_sz, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > skip) in_num_sect -= skip; out_num_sect = -1; if (FT_SG == out_type) { res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention(out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "Aborted command(out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read capacity (of=%s): %s\n", inf, b); out_num_sect = -1; } } else if (FT_BLOCK == out_type) { if (0 != read_blkdev_capacity(outfd, &out_num_sect, &out_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (blk_sz != out_sect_sz) { fprintf(stderr, "block size on %s confusion: bs=%d, from " "device=%d\n", outf, blk_sz, out_sect_sz); out_num_sect = -1; } } if (out_num_sect > seek) out_num_sect -= seek; #ifdef SG_DEBUG fprintf(stderr, "Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect, out_num_sect); #endif if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } if (dd_count < 0) { fprintf(stderr, "Couldn't calculate count, please give one\n"); return SG_LIB_SYNTAX_ERROR; } if (! cdbsz_given) { if ((FT_SG == in_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_in) && (((dd_count + skip) > UINT_MAX) || (bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'if')\n"); scsi_cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == out_type) && (MAX_SCSI_CDBSZ != scsi_cdbsz_out) && (((dd_count + seek) > UINT_MAX) || (bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'of')\n"); scsi_cdbsz_out = MAX_SCSI_CDBSZ; } } if (out_flags.dio && (FT_SG != in_type)) { out_flags.dio = 0; fprintf(stderr, ">>> dio only performed on 'of' side when 'if' is" " an sg device\n"); } if (out_flags.dio) { int fd; char c; if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (wrkMmap) { wrkPos = wrkMmap; #ifdef SG_WANT_SHARED_MMAP_IO if (! (mmap_shareable && out_flags.smmap && (FT_SG == out_type))) mmap_shareable = 0; #endif } else { if ((FT_RAW == in_type) || (FT_RAW == out_type)) { wrkBuff = (unsigned char *)malloc(blk_sz * bpt + psz); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory for raw\n"); return SG_LIB_FILE_ERROR; } /* perhaps use posix_memalign() instead */ wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & (~(psz - 1))); } else { wrkBuff = (unsigned char *)malloc(blk_sz * bpt); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory\n"); return SG_LIB_FILE_ERROR; } wrkPos = wrkBuff; } } blocks_per = bpt; #ifdef SG_DEBUG fprintf(stderr, "Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count, blocks_per); #endif if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = 1; } req_count = dd_count; #ifdef SG_WANT_SHARED_MMAP_IO if (verbose && (dd_count > 0) && (0 == out_flags.dio) && (FT_SG == in_type) && (FT_SG == out_type) && (! mmap_shareable)) #else if (verbose && (dd_count > 0) && (0 == out_flags.dio) && (FT_SG == in_type) && (FT_SG == out_type)) #endif fprintf(stderr, "Since both 'if' and 'of' are sg devices, only do " "mmap-ed transfers on 'if'\n"); while (dd_count > 0) { blocks = (dd_count > blocks_per) ? blocks_per : dd_count; if (FT_SG == in_type) { ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { fprintf(stderr, "Unit attention or aborted command, " "continuing (r)\n"); ret = sg_read(infd, wrkPos, blocks, skip, blk_sz, scsi_cdbsz_in, in_flags.fua, in_flags.dpo, 1); } if (0 != ret) { fprintf(stderr, "sg_read failed, skip=%" PRId64 "\n", skip); break; } else in_full += blocks; } else { while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "read(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (ret < 0) { snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ", skip); perror(ebuff); ret = -1; break; } else if (res < blocks * blk_sz) { dd_count = 0; blocks = res / blk_sz; if ((res % blk_sz) > 0) { blocks++; in_partial++; } } in_full += blocks; } if (0 == blocks) break; /* read nothing so leave loop */ if (FT_SG == out_type) { int do_mmap = (FT_SG == in_type) ? 0 : 1; int dio_res = out_flags.dio; ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out, out_flags.fua, out_flags.dpo, do_mmap, #ifdef SG_WANT_SHARED_MMAP_IO mmap_shareable, #endif &dio_res); if ((SG_LIB_CAT_UNIT_ATTENTION == ret) || (SG_LIB_CAT_ABORTED_COMMAND == ret)) { fprintf(stderr, "Unit attention or aborted command, " "continuing (w)\n"); dio_res = out_flags.dio; ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, scsi_cdbsz_out, out_flags.fua, out_flags.dpo, do_mmap, #ifdef SG_WANT_SHARED_MMAP_IO mmap_shareable, #endif &dio_res); } if (0 != ret) { fprintf(stderr, "sg_write failed, seek=%" PRId64 "\n", seek); break; } else { out_full += blocks; if (out_flags.dio && (0 == dio_res)) num_dio_not_done++; } } else if (FT_DEV_NULL == out_type) out_full += blocks; /* act as if written out without error */ else { while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "write(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%" PRId64 " ", seek); perror(ebuff); break; } else if (res < blocks * blk_sz) { fprintf(stderr, "output file probably full, seek=%" PRId64 " ", seek); blocks = res / blk_sz; out_full += blocks; if ((res % blk_sz) > 0) out_partial++; break; } else out_full += blocks; } if (dd_count > 0) dd_count -= blocks; skip += blocks; seek += blocks; } if (do_time) calc_duration_throughput(0); if (do_sync) { if (FT_SG == out_type) { fprintf(stderr, ">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0); } if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Synchronize cache(out): %s\n", b); } } } if (wrkBuff) free(wrkBuff); if (STDIN_FILENO != infd) close(infd); if ((STDOUT_FILENO != outfd) && (FT_DEV_NULL != out_type)) close(outfd); if (0 != dd_count) { fprintf(stderr, "Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(); if (sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", sum_of_resids); if (num_dio_not_done) fprintf(stderr, ">> dio requested but _not_ done %d times\n", num_dio_not_done); #ifdef SG_WANT_SHARED_MMAP_IO if ((verbose > 0) && out_flags.smmap && (shared_mm_req > 0)) { fprintf(stderr, ">> shared_mm_req=%d, shared_mm_done=%d\n", shared_mm_req, shared_mm_done); } #endif return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/Makefile.am0000664000175000017500000002407712430315266015207 0ustar douggdougg if OS_LINUX # sg_dd, sg_emc_trespass(?), sginfo, sg_map26, sg_map, sgm_dd, sgp_dd, # sg_rbuf, sg_read, sg_reset, sg_test_rwbuf # are Linux only utilities # # sg_scan is shared by Linux and Win32 bin_PROGRAMS = \ sg_compare_and_write sg_copy_results sg_dd sg_decode_sense \ sg_emc_trespass sg_format sg_get_config sg_get_lba_status \ sg_ident sginfo sg_inq sg_logs sg_luns sg_map26 sg_map sgm_dd \ sg_modes sg_opcodes sgp_dd sg_persist sg_prevent sg_raw sg_rbuf \ sg_rdac sg_read sg_readcap sg_read_block_limits sg_read_buffer \ sg_read_long sg_reassign sg_referrals sg_rep_zones sg_requests \ sg_reset sg_reset_wp sg_rmsn sg_rtpg sg_safte sg_sanitize \ sg_sat_identify sg_sat_phy_event sg_sat_read_gplog \ sg_sat_set_features sg_scan sg_senddiag sg_ses sg_ses_microcode \ sg_start sg_stpg sg_sync sg_test_rwbuf sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode sg_xcopy distclean-local: rm -f sg_scan.c sg_scan.c : sg_scan.c.linux cp sg_scan.c.linux sg_scan.c endif if OS_WIN32_MINGW bin_PROGRAMS = \ sg_compare_and_write sg_decode_sense sg_format sg_get_config \ sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \ sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \ sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \ sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \ sg_sat_read_gplog sg_sat_set_features sg_scan sg_senddiag sg_ses \ sg_ses_microcode sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode distclean-local: rm -f sg_scan.c sg_scan.c : sg_scan.c.win32 cp sg_scan.c.win32 sg_scan.c endif if OS_WIN32_CYGWIN bin_PROGRAMS = \ sg_compare_and_write sg_decode_sense sg_format sg_get_config \ sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \ sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \ sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \ sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \ sg_sat_read_gplog sg_sat_set_features sg_scan sg_senddiag sg_ses \ sg_ses_microcode sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode distclean-local: rm -f sg_scan.c sg_scan.c : sg_scan.c.win32 cp sg_scan.c.win32 sg_scan.c endif if OS_FREEBSD bin_PROGRAMS = \ sg_compare_and_write sg_decode_sense sg_format sg_get_config \ sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \ sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \ sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \ sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \ sg_sat_read_gplog sg_sat_set_features sg_senddiag sg_ses \ sg_ses_microcode sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode endif if OS_SOLARIS bin_PROGRAMS = \ sg_compare_and_write sg_decode_sense sg_format sg_get_config \ sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \ sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \ sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn \ sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \ sg_sat_read_gplog sg_sat_set_features sg_senddiag sg_ses \ sg_ses_microcode sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode endif if OS_OSF bin_PROGRAMS = \ sg_compare_and_write sg_decode_sense sg_format sg_get_config \ sg_get_lba_status sg_ident sg_inq sg_logs sg_luns sg_modes \ sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_readcap \ sg_read_block_limits sg_read_buffer sg_read_long sg_reassign \ sg_referrals sg_rep_zones sg_requests sg_reset_wp sg_rmsn sg_rtpg \ sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event \ sg_sat_read_gplog sg_sat_set_features sg_senddiag sg_ses \ sg_ses_microcode sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify \ sg_vpd sg_write_buffer sg_write_long sg_write_same sg_write_verify \ sg_wr_mode endif # For C++/clang testing ## CC = gcc ## CC = g++ ## CC = clang ## CC = clang++ # -std= can be c99, c11, gnu11, etc. Default is gnu89 (gnu90 is the same) # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ -pedantic -std=c11 # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ -pedantic -std=c++11 sg_dd_SOURCES = sg_dd.c sg_dd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_decode_sense_SOURCES = sg_decode_sense.c sg_decode_sense_LDADD = ../lib/libsgutils2.la @os_libs@ sg_emc_trespass_SOURCES = sg_emc_trespass.c sg_emc_trespass_LDADD = ../lib/libsgutils2.la @os_libs@ sg_format_SOURCES = sg_format.c sg_format_LDADD = ../lib/libsgutils2.la @os_libs@ sg_get_config_SOURCES = sg_get_config.c sg_get_config_LDADD = ../lib/libsgutils2.la @os_libs@ sg_get_lba_status_SOURCES = sg_get_lba_status.c sg_get_lba_status_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ident_SOURCES = sg_ident.c sg_ident_LDADD = ../lib/libsgutils2.la @os_libs@ sginfo_SOURCES = sginfo.c sginfo_LDADD = ../lib/libsgutils2.la @os_libs@ sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_inq_LDADD = ../lib/libsgutils2.la @os_libs@ sg_logs_SOURCES = sg_logs.c sg_logs_LDADD = ../lib/libsgutils2.la @os_libs@ sg_luns_SOURCES = sg_luns.c sg_luns_LDADD = ../lib/libsgutils2.la @os_libs@ sg_map26_SOURCES = sg_map26.c sg_map26_LDADD = @os_libs@ sg_map_SOURCES = sg_map.c sg_map_LDADD = ../lib/libsgutils2.la @os_libs@ sgm_dd_SOURCES = sgm_dd.c sgm_dd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_modes_SOURCES = sg_modes.c sg_modes_LDADD = ../lib/libsgutils2.la @os_libs@ sg_opcodes_SOURCES = sg_opcodes.c sg_opcodes_LDADD = ../lib/libsgutils2.la @os_libs@ sgp_dd_SOURCES = sgp_dd.c sgp_dd_LDADD = ../lib/libsgutils2.la @os_libs@ -lpthread sg_persist_SOURCES = sg_persist.c sg_persist_LDADD = ../lib/libsgutils2.la @os_libs@ sg_prevent_SOURCES = sg_prevent.c sg_prevent_LDADD = ../lib/libsgutils2.la @os_libs@ sg_raw_SOURCES = sg_raw.c sg_raw_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rbuf_SOURCES = sg_rbuf.c sg_rbuf_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rdac_SOURCES = sg_rdac.c sg_rdac_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_SOURCES = sg_read.c sg_read_LDADD = ../lib/libsgutils2.la @os_libs@ sg_readcap_SOURCES = sg_readcap.c sg_readcap_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_block_limits_SOURCES = sg_read_block_limits.c sg_read_block_limits_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_buffer_SOURCES = sg_read_buffer.c sg_read_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_long_SOURCES = sg_read_long.c sg_read_long_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reassign_SOURCES = sg_reassign.c sg_reassign_LDADD = ../lib/libsgutils2.la @os_libs@ sg_requests_SOURCES = sg_requests.c sg_requests_LDADD = ../lib/libsgutils2.la @os_libs@ sg_referrals_SOURCES = sg_referrals.c sg_referrals_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reset_SOURCES = sg_reset.c sg_reset_LDADD = @os_libs@ sg_rmsn_SOURCES = sg_rmsn.c sg_rmsn_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rtpg_SOURCES = sg_rtpg.c sg_rtpg_LDADD = ../lib/libsgutils2.la @os_libs@ sg_safte_SOURCES = sg_safte.c sg_safte_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sanitize_SOURCES = sg_sanitize.c sg_sanitize_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_identify_SOURCES = sg_sat_identify.c sg_sat_identify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_phy_event_SOURCES = sg_sat_phy_event.c sg_sat_phy_event_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_set_features_SOURCES = sg_sat_set_features.c sg_sat_set_features_LDADD = ../lib/libsgutils2.la @os_libs@ sg_scan_SOURCES = sg_scan.c sg_scan_LDADD = ../lib/libsgutils2.la @os_libs@ sg_senddiag_SOURCES = sg_senddiag.c sg_senddiag_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ses_SOURCES = sg_ses.c sg_ses_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ses_microcode_SOURCES = sg_ses_microcode.c sg_ses_microcode_LDADD = ../lib/libsgutils2.la @os_libs@ sg_start_SOURCES = sg_start.c sg_start_LDADD = ../lib/libsgutils2.la @os_libs@ sg_stpg_SOURCES = sg_stpg.c sg_stpg_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sync_SOURCES = sg_sync.c sg_sync_LDADD = ../lib/libsgutils2.la @os_libs@ sg_test_rwbuf_SOURCES = sg_test_rwbuf.c sg_test_rwbuf_LDADD = ../lib/libsgutils2.la @os_libs@ sg_turs_SOURCES = sg_turs.c sg_turs_LDADD = ../lib/libsgutils2.la @os_libs@ sg_unmap_SOURCES = sg_unmap.c sg_unmap_LDADD = ../lib/libsgutils2.la @os_libs@ sg_verify_SOURCES = sg_verify.c sg_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_buffer_SOURCES = sg_write_buffer.c sg_write_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_long_SOURCES = sg_write_long.c sg_write_long_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_same_SOURCES = sg_write_same.c sg_write_same_LDADD = ../lib/libsgutils2.la @os_libs@ sg_wr_mode_SOURCES = sg_wr_mode.c sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ sg_xcopy_SOURCES = sg_xcopy.c sg_xcopy_LDADD = ../lib/libsgutils2.la @os_libs@ sg_copy_results_SOURCES = sg_copy_results.c sg_copy_results_LDADD = ../lib/libsgutils2.la @os_libs@ sg_compare_and_write_SOURCES = sg_compare_and_write.c sg_compare_and_write_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rep_zones_SOURCES = sg_rep_zones.c sg_rep_zones_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reset_wp_SOURCES = sg_reset_wp.c sg_reset_wp_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_verify_SOURCES = sg_write_verify.c sg_write_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_read_gplog_SOURCES = sg_sat_read_gplog.c sg_sat_read_gplog_LDADD = ../lib/libsgutils2.la @os_libs@ sg3_utils-1.40/src/sg_read.c0000664000175000017500000007452112335513125014720 0ustar douggdougg/* A utility program for the Linux OS SCSI generic ("sg") device driver. * Copyright (C) 2001 - 2014 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. This program reads data from the given SCSI device (typically a disk or cdrom) and discards that data. Its primary goal is to time multiple reads all starting from the same logical address. Its interface is a subset of another member of this package: sg_dd which is a "dd" variant. The input file can be a scsi generic device, a block device, a raw device or a seekable file. Streams such as stdin are not acceptable. The block size ('bs') is assumed to be 512 if not given. This version should compile with Linux sg drivers with version numbers >= 30000 . For mmap-ed IO the sg version number >= 30122 . */ #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_io_linux.h" static const char * version_str = "1.21 20140516"; #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define DEF_SCSI_CDBSZ 10 #define MAX_SCSI_CDBSZ 16 #define ME "sg_read: " #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_TIMEOUT 40000 /* 40,000 millisecs == 40 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikey value */ #endif #define FT_OTHER 1 /* filetype other than sg or raw device */ #define FT_SG 2 /* filetype is sg char device */ #define FT_RAW 4 /* filetype is raw char device */ #define FT_BLOCK 8 /* filetype is block device */ #define FT_ERROR 64 /* couldn't "stat" file */ #define MIN_RESERVED_SIZE 8192 static int sum_of_resids = 0; static int64_t dd_count = -1; static int64_t orig_count = 0; static int64_t in_full = 0; static int in_partial = 0; static int pack_id_count = 0; static int verbose = 0; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; static void install_handler (int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } static void print_stats(int iters, const char * str) { if (orig_count > 0) { if (0 != dd_count) fprintf(stderr, " remaining block count=%" PRId64 "\n", dd_count); fprintf(stderr, "%" PRId64 "+%d records in", in_full - in_partial, in_partial); if (iters > 0) fprintf(stderr, ", %s commands issued: %d\n", (str ? str : ""), iters); else fprintf(stderr, "\n"); } else if (iters > 0) fprintf(stderr, "%s commands issued: %d\n", (str ? str : ""), iters); } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig, &sigact, NULL); fprintf(stderr, "Interrupted by signal,"); print_stats(0, NULL); kill (getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ fprintf(stderr, "Progress report, continuing ...\n"); print_stats(0, NULL); } static int dd_filetype(const char * filename) { struct stat st; if (stat(filename, &st) < 0) return FT_ERROR; if (S_ISCHR(st.st_mode)) { if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; else if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; return FT_OTHER; } static void usage() { fprintf(stderr, "Usage: " "sg_read [blk_sgio=0|1] [bpt=BPT] [bs=BS] " "[cdbsz=6|10|12|16]\n" " count=COUNT [dio=0|1] [dpo=0|1] [fua=0|1] " "if=IFILE\n" " [mmap=0|1] [no_dfxer=0|1] [odir=0|1] " "[skip=SKIP]\n" " [time=TI] [verbose=VERB] [--help] " "[--version]\n" " where:\n" " blk_sgio 0->normal IO for block devices, 1->SCSI commands " "via SG_IO\n" " bpt is blocks_per_transfer (default is 128, or 64 KiB " "for default BS)\n" " setting 'bpt=0' will do COUNT zero block SCSI " "READs\n" " bs must match sector size if IFILE accessed via SCSI " "commands\n" " (def=512)\n" " cdbsz size of SCSI READ command (default is 10)\n" " count total bytes read will be BS*COUNT (if no " "error)\n" " (if negative, do |COUNT| zero block SCSI READs)\n" " dio 1-> attempt direct IO on sg device, 0->indirect IO " "(def)\n"); fprintf(stderr, " dpo 1-> set disable page out (DPO) in SCSI READs\n" " fua 1-> set force unit access (FUA) in SCSI READs\n" " if an sg, block or raw device, or a seekable file (not " "stdin)\n" " mmap 1->perform mmaped IO on sg device, 0->indirect IO " "(def)\n" " no_dxfer 1->DMA to kernel buffers only, not user space, " "0->normal(def)\n" " odir 1->open block device O_DIRECT, 0->don't (def)\n" " skip each transfer starts at this logical address " "(def=0)\n" " time 0->do nothing(def), 1->time from 1st cmd, 2->time " "from 2nd, ...\n" " verbose increase level of verbosity (def: 0)\n" " --help print this usage message then exit\n" " --version print version number then exit\n\n" "Issue SCSI READ commands, each starting from the same logical " "block address\n"); } static int sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, int write_true, int fua, int dpo) { int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f); cdbp[2] = (unsigned char)((start_block >> 8) & 0xff); cdbp[3] = (unsigned char)(start_block & 0xff); cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks; if (blocks > 256) { fprintf(stderr, ME "for 6 byte commands, maximum number of " "blocks is 256\n"); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { fprintf(stderr, ME "for 6 byte commands, can't address blocks" " beyond %d\n", 0x1fffff); return 1; } if (dpo || fua) { fprintf(stderr, ME "for 6 byte commands, neither dpo nor fua" " bits supported\n"); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[7] = (unsigned char)((blocks >> 8) & 0xff); cdbp[8] = (unsigned char)(blocks & 0xff); if (blocks & (~0xffff)) { fprintf(stderr, ME "for 10 byte commands, maximum number of " "blocks is %d\n", 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[6] = (unsigned char)((blocks >> 24) & 0xff); cdbp[7] = (unsigned char)((blocks >> 16) & 0xff); cdbp[8] = (unsigned char)((blocks >> 8) & 0xff); cdbp[9] = (unsigned char)(blocks & 0xff); break; case 16: sz_ind = 3; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 56) & 0xff); cdbp[3] = (unsigned char)((start_block >> 48) & 0xff); cdbp[4] = (unsigned char)((start_block >> 40) & 0xff); cdbp[5] = (unsigned char)((start_block >> 32) & 0xff); cdbp[6] = (unsigned char)((start_block >> 24) & 0xff); cdbp[7] = (unsigned char)((start_block >> 16) & 0xff); cdbp[8] = (unsigned char)((start_block >> 8) & 0xff); cdbp[9] = (unsigned char)(start_block & 0xff); cdbp[10] = (unsigned char)((blocks >> 24) & 0xff); cdbp[11] = (unsigned char)((blocks >> 16) & 0xff); cdbp[12] = (unsigned char)((blocks >> 8) & 0xff); cdbp[13] = (unsigned char)(blocks & 0xff); break; default: fprintf(stderr, ME "expected cdb size of 6, 10, 12, or 16 but got" " %d\n", cdb_sz); return 1; } return 0; } /* -3 medium/hardware error, -2 -> not ready, 0 -> successful, 1 -> recoverable (ENOMEM), 2 -> try again (e.g. unit attention), 3 -> try again (e.g. aborted command), -1 -> other unrecoverable error */ static int sg_bread(int sg_fd, unsigned char * buff, int blocks, int64_t from_block, int bs, int cdbsz, int fua, int dpo, int * diop, int do_mmap, int no_dxfer) { int k; unsigned char rdCmd[MAX_SCSI_CDBSZ]; unsigned char senseBuff[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; if (sg_build_scsi_cdb(rdCmd, cdbsz, blocks, from_block, 0, fua, dpo)) { fprintf(stderr, ME "bad cdb build, from_block=%" PRId64 ", blocks=%d\n", from_block, blocks); return -1; } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = cdbsz; io_hdr.cmdp = rdCmd; if (blocks > 0) { io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = bs * blocks; /* next: shows dxferp unused during mmap-ed IO */ if (! do_mmap) io_hdr.dxferp = buff; if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; else if (do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; else if (no_dxfer) io_hdr.flags |= SG_FLAG_NO_DXFER; } else io_hdr.dxfer_direction = SG_DXFER_NONE; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = pack_id_count++; if (verbose > 1) { fprintf(stderr, " read cdb: "); for (k = 0; k < cdbsz; ++k) fprintf(stderr, "%02x ", rdCmd[k]); fprintf(stderr, "\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { if (ENOMEM == errno) return 1; perror("reading (SG_IO) on sg device, error"); return -1; } if (verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: if (verbose > 1) sg_chk_n_print3("reading, continue", &io_hdr, 1); break; case SG_LIB_CAT_UNIT_ATTENTION: if (verbose) sg_chk_n_print3("reading", &io_hdr, verbose - 1); return 2; case SG_LIB_CAT_ABORTED_COMMAND: if (verbose) sg_chk_n_print3("reading", &io_hdr, verbose - 1); return 3; case SG_LIB_CAT_NOT_READY: if (verbose) sg_chk_n_print3("reading", &io_hdr, verbose - 1); return -2; case SG_LIB_CAT_MEDIUM_HARD: if (verbose) sg_chk_n_print3("reading", &io_hdr, verbose - 1); return -3; default: sg_chk_n_print3("reading", &io_hdr, verbose); return -1; } if (blocks > 0) { if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = 0; /* flag that dio not done (completely) */ sum_of_resids += io_hdr.resid; } return 0; } #define STR_SZ 1024 #define INF_SZ 512 #define EBUFF_SZ 512 int main(int argc, char * argv[]) { int64_t skip = 0; int bs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; char str[STR_SZ]; char * key; char * buf; char inf[INF_SZ]; char outf[INF_SZ]; int in_type = FT_OTHER; int do_dio = 0; int do_odir = 0; int do_blk_sgio = 0; int do_mmap = 0; int no_dxfer = 0; int do_time = 0; int fua = 0; int dpo = 0; int scsi_cdbsz = DEF_SCSI_CDBSZ; int dio_incomplete = 0; int count_given = 0; int res, k, t, buf_sz, dio_tmp, iters; int infd, blocks, flags, blocks_per; unsigned char * wrkBuff = NULL; unsigned char * wrkPos = NULL; char ebuff[EBUFF_SZ]; struct timeval start_tm, end_tm; const char * read_str; int ret = 0; size_t psz; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif inf[0] = '\0'; for (k = 1; k < argc; k++) { if (argv[k]) { strncpy(str, argv[k], STR_SZ); str[STR_SZ - 1] = '\0'; } else continue; for (key = str, buf = key; (*buf && (*buf != '=')); ) buf++; if (*buf) *buf++ = '\0'; if (0 == strcmp(key,"blk_sgio")) do_blk_sgio = sg_get_num(buf); else if (0 == strcmp(key,"bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { fprintf(stderr, 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) { fprintf(stderr, ME "bad argument to 'bs'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) scsi_cdbsz = sg_get_num(buf); else if (0 == strcmp(key,"count")) { count_given = 1; if ('-' == *buf) { dd_count = sg_get_llnum(buf + 1); if (-1 == dd_count) { fprintf(stderr, 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) { fprintf(stderr, ME "bad argument to 'count'\n"); return SG_LIB_SYNTAX_ERROR; } } } else if (0 == strcmp(key,"dio")) do_dio = sg_get_num(buf); else if (0 == strcmp(key,"dpo")) dpo = sg_get_num(buf); else if (0 == strcmp(key,"fua")) fua = sg_get_num(buf); else if (strcmp(key,"if") == 0) strncpy(inf, buf, INF_SZ); else if (0 == strcmp(key,"mmap")) do_mmap = sg_get_num(buf); else if (0 == strcmp(key,"no_dxfer")) no_dxfer = sg_get_num(buf); else if (0 == strcmp(key,"odir")) do_odir = sg_get_num(buf); else if (strcmp(key,"of") == 0) strncpy(outf, buf, INF_SZ); else if (0 == strcmp(key,"skip")) { skip = sg_get_llnum(buf); if (-1 == skip) { fprintf(stderr, ME "bad argument to 'skip'\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "verb", 4)) verbose = sg_get_num(buf); else if (0 == strncmp(key, "--help", 6)) { usage(); return 0; } else if (0 == strncmp(key, "--vers", 6)) { fprintf(stderr, ME ": %s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized argument '%s'\n", key); usage(); return SG_LIB_SYNTAX_ERROR; } } if (bs <= 0) { bs = DEF_BLOCK_SIZE; if ((dd_count > 0) && (bpt > 0)) fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", bs); } if (! count_given) { fprintf(stderr, "'count' must be given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (skip < 0) { fprintf(stderr, "skip cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if (bpt < 1) { if (0 == bpt) { if (dd_count > 0) dd_count = - dd_count; } else { fprintf(stderr, "bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } } if (do_dio && do_mmap) { fprintf(stderr, "cannot select both dio and mmap\n"); return SG_LIB_SYNTAX_ERROR; } if (no_dxfer && (do_dio || do_mmap)) { fprintf(stderr, "cannot select no_dxfer with dio or mmap\n"); return SG_LIB_SYNTAX_ERROR; } install_handler (SIGINT, interrupt_handler); install_handler (SIGQUIT, interrupt_handler); install_handler (SIGPIPE, interrupt_handler); install_handler (SIGUSR1, siginfo_handler); if (! inf[0]) { fprintf(stderr, "must provide 'if='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (0 == strcmp("-", inf)) { fprintf(stderr, "'-' (stdin) invalid as \n"); usage(); return SG_LIB_SYNTAX_ERROR; } in_type = dd_filetype(inf); if (FT_ERROR == in_type) { fprintf(stderr, "Unable to access: %s\n", inf); return SG_LIB_FILE_ERROR; } else if ((FT_BLOCK & in_type) && do_blk_sgio) in_type |= FT_SG; if (FT_SG & in_type) { if ((dd_count < 0) && (6 == scsi_cdbsz)) { fprintf(stderr, ME "SCSI READ (6) can't do zero block " "reads\n"); return SG_LIB_SYNTAX_ERROR; } flags = O_RDWR; if (do_odir) flags |= O_DIRECT; if ((infd = open(inf, flags)) < 0) { flags = O_RDONLY; if (do_odir) flags |= O_DIRECT; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } } if (verbose) fprintf(stderr, "Opened %s for SG_IO with flags=0x%x\n", inf, flags); if ((dd_count > 0) && (! (FT_BLOCK & in_type))) { if (verbose > 2) { if (ioctl(infd, SG_GET_RESERVED_SIZE, &t) >= 0) fprintf(stderr, " SG_GET_RESERVED_SIZE yields: %d\n", t); } t = bs * bpt; if ((do_mmap) && (0 != (t % psz))) t = ((t / psz) + 1) * psz; /* round up to next pagesize */ res = ioctl(infd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror(ME "SG_SET_RESERVED_SIZE error"); res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { fprintf(stderr, ME "sg driver prior to 3.x.y\n"); return SG_LIB_CAT_OTHER; } if (do_mmap && (t < 30122)) { fprintf(stderr, ME "mmap-ed IO needs a sg driver version " ">= 3.1.22\n"); return SG_LIB_CAT_OTHER; } } } else { if (do_mmap) { fprintf(stderr, ME "mmap-ed IO only support on sg " "devices\n"); return SG_LIB_CAT_OTHER; } if (dd_count < 0) { fprintf(stderr, ME "negative 'count' only supported with " "SCSI READs\n"); return SG_LIB_CAT_OTHER; } flags = O_RDONLY; if (do_odir) flags |= O_DIRECT; if ((infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, "Opened %s for Unix reads with flags=0x%x\n", inf, flags); if (skip > 0) { off64_t offset = skip; offset *= bs; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to required position on %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } } } if (0 == dd_count) return 0; orig_count = dd_count; if (dd_count > 0) { if (do_dio || do_odir || (FT_RAW & in_type)) { wrkBuff = (unsigned char *)malloc(bs * bpt + psz); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory for aligned " "storage\n"); return SG_LIB_CAT_OTHER; } /* perhaps use posix_memalign() instead */ wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & (~(psz - 1))); } else if (do_mmap) { wrkPos = (unsigned char *)mmap(NULL, bs * bpt, PROT_READ | PROT_WRITE, MAP_SHARED, infd, 0); if (MAP_FAILED == wrkPos) { perror(ME "error from mmap()"); return SG_LIB_CAT_OTHER; } } else { wrkBuff = (unsigned char *)malloc(bs * bpt); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory\n"); return SG_LIB_CAT_OTHER; } wrkPos = wrkBuff; } } blocks_per = bpt; start_tm.tv_sec = 0; /* just in case start set condition not met */ start_tm.tv_usec = 0; if (verbose && (dd_count < 0)) fprintf(stderr, "About to issue %" PRId64 " zero block SCSI READs\n", 0 - dd_count); /* main loop */ for (iters = 0; dd_count != 0; ++iters) { if ((do_time > 0) && (iters == (do_time - 1))) gettimeofday(&start_tm, NULL); if (dd_count < 0) blocks = 0; else blocks = (dd_count > blocks_per) ? blocks_per : dd_count; if (FT_SG & in_type) { dio_tmp = do_dio; res = sg_bread(infd, wrkPos, blocks, skip, bs, scsi_cdbsz, fua, dpo, &dio_tmp, do_mmap, no_dxfer); if (1 == res) { /* ENOMEM, find what's available+try that */ if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { perror("RESERVED_SIZE ioctls failed"); break; } if (buf_sz < MIN_RESERVED_SIZE) buf_sz = MIN_RESERVED_SIZE; blocks_per = (buf_sz + bs - 1) / bs; blocks = blocks_per; fprintf(stderr, "Reducing read to %d blocks per loop\n", blocks_per); res = sg_bread(infd, wrkPos, blocks, skip, bs, scsi_cdbsz, fua, dpo, &dio_tmp, do_mmap, no_dxfer); } else if (2 == res) { fprintf(stderr, "Unit attention, try again (r)\n"); res = sg_bread(infd, wrkPos, blocks, skip, bs, scsi_cdbsz, fua, dpo, &dio_tmp, do_mmap, no_dxfer); } if (0 != res) { switch (res) { case -3: ret = SG_LIB_CAT_MEDIUM_HARD; fprintf(stderr, ME "SCSI READ medium/hardware error\n"); break; case -2: ret = SG_LIB_CAT_NOT_READY; fprintf(stderr, ME "device not ready\n"); break; case 2: ret = SG_LIB_CAT_UNIT_ATTENTION; fprintf(stderr, ME "SCSI READ unit attention\n"); break; case 3: ret = SG_LIB_CAT_ABORTED_COMMAND; fprintf(stderr, ME "SCSI READ aborted command\n"); break; default: ret = SG_LIB_CAT_OTHER; fprintf(stderr, ME "SCSI READ failed\n"); break; } break; } else { in_full += blocks; if (do_dio && (0 == dio_tmp)) dio_incomplete++; } } else { if (iters > 0) { /* subsequent iteration reset skip position */ off64_t offset = skip; offset *= bs; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { perror(ME "could not reset skip position"); break; } } while (((res = read(infd, wrkPos, blocks * bs)) < 0) && (EINTR == errno)) ; if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ", skip); perror(ebuff); break; } else if (res < blocks * bs) { fprintf(stderr, ME "short read: wanted/got=%d/%d bytes" ", stop\n", blocks * bs, res); blocks = res / bs; if ((res % bs) > 0) { blocks++; in_partial++; } dd_count -= blocks; in_full += blocks; break; } in_full += blocks; } if (dd_count > 0) dd_count -= blocks; else if (dd_count < 0) ++dd_count; } read_str = (FT_SG & in_type) ? "SCSI READ" : "read"; if (do_time > 0) { gettimeofday(&end_tm, NULL); if (start_tm.tv_sec || start_tm.tv_usec) { struct timeval res_tm; double a, b, c; 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); if (orig_count > 0) { b = (double)bs * (orig_count - dd_count); if (do_time > 1) c = b - ((double)bs * ((do_time - 1.0) * bpt)); else c = 0.0; } else { b = 0.0; c = 0.0; } if (1 == do_time) { fprintf(stderr, "Time for all %s commands was " "%d.%06d secs", read_str, (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((orig_count > 0) && (a > 0.00001) && (b > 511)) fprintf(stderr, ", %.2f MB/sec\n", b / (a * 1000000.0)); else fprintf(stderr, "\n"); } else if (2 == do_time) { fprintf(stderr, "Time from second %s command to end " "was %d.%06d secs", read_str, (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((orig_count > 0) && (a > 0.00001) && (c > 511)) fprintf(stderr, ", %.2f MB/sec\n", c / (a * 1000000.0)); else fprintf(stderr, "\n"); } else { fprintf(stderr, "Time from start of %s command " "#%d to end was %d.%06d secs", read_str, do_time, (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((orig_count > 0) && (a > 0.00001) && (c > 511)) fprintf(stderr, ", %.2f MB/sec\n", c / (a * 1000000.0)); else fprintf(stderr, "\n"); } if ((iters > 0) && (a > 0.00001)) fprintf(stderr, "Average number of %s commands per " "second was %.2f\n", read_str, (double)iters / a); } } if (wrkBuff) free(wrkBuff); close(infd); res = 0; if (0 != dd_count) { fprintf(stderr, "Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(iters, read_str); if (dio_incomplete) { int fd; char c; fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", dio_incomplete); if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", sum_of_resids); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_ses_microcode.c0000664000175000017500000006522512424673250016631 0ustar douggdougg/* * Copyright (c) 2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #endif #endif #include "sg_unaligned.h" /* * This utility issues the SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC * RESULTS commands in order to send microcode to the given SES device. */ static const char * version_str = "1.02 20141029"; /* ses3r07 */ #define ME "sg_ses_microcode: " #define MAX_XFER_LEN (128 * 1024 * 1024) #define DEF_XFER_LEN (8 * 1024 * 1024) #define DEF_DI_LEN (8 * 1024) #define EBUFF_SZ 256 #define DPC_DOWNLOAD_MICROCODE 0xe struct opts_t { int bpw; int bpw_then_activate; int mc_id; int mc_len; int mc_len_given; int mc_mode; int mc_non; int mc_offset; int mc_skip; int mc_subenc; int mc_tlen; int verbose; }; static struct option long_options[] = { {"bpw", required_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"id", required_argument, 0, 'i'}, {"in", required_argument, 0, 'I'}, {"length", required_argument, 0, 'l'}, {"mode", required_argument, 0, 'm'}, {"non", no_argument, 0, 'N'}, {"offset", required_argument, 0, 'o'}, {"skip", required_argument, 0, 's'}, {"subenc", required_argument, 0, 'S'}, {"tlength", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_ses_microcode [--bpw=CS] [--help] [--id=ID] [--in=FILE]\n" " [--length=LEN] [--mode=MO] " "[--non]\n" " [--offset=OFF] [--skip=SKIP] " "[--subenc=SEID]\n" " [--tlength=TLEN] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --bpw=CS|-b CS CS is chunk size: bytes per send " "diagnostic\n" " command (def: 0 -> as many as " "possible)\n" " --help|-h print out usage message then exit\n" " --id=ID|-i ID buffer identifier (0 (default) to " "255)\n" " --in=FILE|-I FILE read from FILE ('-I -' read " "from stdin)\n" " --length=LEN|-l LEN length in bytes to send; may be " "deduced from\n" " FILE\n" " --mode=MO|-m MO download microcode mode, MO is " "number or\n" " acronym (def: 0 -> 'dmc_status')\n" " --non|-N non-standard: bypass all receive " "diagnostic\n" " results commands except after check " "condition\n" " --offset=OFF|-o OFF buffer offset (unit: bytes, def: " "0);\n" " ignored if --bpw=CS given\n" " --skip=SKIP|-s SKIP bytes in file FILE to skip before " "reading\n" " --subenc=SEID|-S SEID subenclosure identifier (def: 0 " "(primary))\n" " --tlength=TLEN|-t TLEN total length of firmware in " "bytes\n" " (def: 0). Only needed if " "TLEN>LEN\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Does one or more SCSI SEND DIAGNOSTIC followed by RECEIVE " "DIAGNOSTIC\nRESULTS command sequences in order to download " "microcode. Use '-m xxx'\nto list available modes. With only " "DEVICE given, the Download Microcode\nStatus dpage is output.\n" ); } #define MODE_DNLD_STATUS 0 #define MODE_DNLD_MC_OFFS 6 #define MODE_DNLD_MC_OFFS_SAVE 7 #define MODE_DNLD_MC_OFFS_DEFER 0x0E #define MODE_ACTIVATE_MC 0x0F struct mode_s { const char *mode_string; int mode; const char *comment; }; static struct mode_s mode_arr[] = { {"dmc_status", MODE_DNLD_STATUS, "report status of microcode " "download"}, {"dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets " "and activate"}, {"dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with " "offsets, save and\n\t\t\t\tactivate"}, {"dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode " "with offsets, save and\n\t\t\t\tdefer activation"}, {"activate_mc", MODE_ACTIVATE_MC, "activate deferred microcode"}, {NULL, 0, NULL}, }; static void print_modes(void) { const struct mode_s * mp; pr2serr("The modes parameter argument can be numeric (hex or decimal)\n" "or symbolic:\n"); for (mp = mode_arr; mp->mode_string; ++mp) { pr2serr(" %2d (0x%02x) %-18s%s\n", mp->mode, mp->mode, mp->mode_string, mp->comment); } pr2serr("\nAdditionally '--bpw=,act' does a activate deferred " "microcode after a\nsuccessful multipart dmc_offs_defer mode " "download.\n"); } struct diag_page_code { int page_code; const char * desc; }; /* An array of Download microcode status field values and descriptions */ static struct diag_page_code mc_status_arr[] = { {0x0, "No download microcode operation in progress"}, {0x1, "Download in progress, awaiting more"}, {0x2, "Download complete, updating storage"}, {0x3, "Updating storage with deferred microcode"}, {0x10, "Complete, no error, starting now"}, {0x11, "Complete, no error, start after hard reset or power cycle"}, {0x12, "Complete, no error, start after power cycle"}, {0x13, "Complete, no error, start after activate_mc, hard reset or " "power cycle"}, {0x80, "Error, discarded, see additional status"}, {0x81, "Error, discarded, image error"}, {0x82, "Timeout, discarded"}, {0x83, "Internal error, need new microcode before reset"}, {0x84, "Internal error, need new microcode, reset safe"}, {0x85, "Unexpected activate_mc received"}, {0x1000, NULL}, }; static const char * get_mc_status_str(unsigned char status_val) { const struct diag_page_code * mcsp; for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) { if (status_val == mcsp->page_code) return mcsp->desc; } return ""; } /* DPC_DOWNLOAD_MICROCODE [0xe] */ static void ses_download_code_sdg(const unsigned char * resp, int resp_len, uint32_t gen_code) { int k, num_subs, num; const unsigned char * ucp; const char * cp; printf("Download microcode status diagnostic page:\n"); if (resp_len < 8) goto truncated; num_subs = resp[1]; /* primary is additional one) */ num = (resp_len - 8) / 16; if ((resp_len - 8) % 16) pr2serr("Found %d Download microcode status descriptors, but there " "is residual\n", num); printf(" number of secondary subenclosures: %d\n", num_subs); printf(" generation code: 0x%" PRIx32 "\n", gen_code); ucp = resp + 8; for (k = 0; k < num; ++k, ucp += 16) { cp = (0 == ucp[1]) ? " [primary]" : ""; printf(" subenclosure identifier: %d%s\n", ucp[1], cp); cp = get_mc_status_str(ucp[2]); if (strlen(cp) > 0) { printf(" download microcode status: %s [0x%x]\n", cp, ucp[2]); printf(" download microcode additional status: 0x%x\n", ucp[3]); } else printf(" download microcode status: 0x%x [additional " "status: 0x%x]\n", ucp[2], ucp[3]); printf(" download microcode maximum size: %" PRIu32 " bytes\n", sg_get_unaligned_be32(ucp + 4)); printf(" download microcode expected buffer id: 0x%x\n", ucp[11]); printf(" download microcode expected buffer id offset: %" PRIu32 "\n", sg_get_unaligned_be32(ucp + 12)); } return; truncated: pr2serr(" <<>>\n"); return; } struct dout_buff_t { unsigned char * doutp; int dout_len; }; static int send_then_receive(int sg_fd, uint32_t gen_code, int off_off, const unsigned char * dmp, int dmp_len, struct dout_buff_t * wp, unsigned char * dip, int last, const struct opts_t * op) { int do_len, rem, res, rsp_len, k, num, mc_status, verb; int send_data = 0; int ret = 0; uint32_t rec_gen_code; const unsigned char * ucp; const char * cp; verb = (op->verbose > 1) ? op->verbose - 1 : 0; switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: case MODE_DNLD_MC_OFFS_DEFER: send_data = 1; do_len = 24 + dmp_len; rem = do_len % 4; if (rem) do_len += (4 - rem); break; case MODE_ACTIVATE_MC: do_len = 24; break; default: pr2serr("send_then_receive: unexpected mc_mode=0x%x\n", op->mc_mode); return SG_LIB_SYNTAX_ERROR; } if (do_len > wp->dout_len) { if (wp->doutp) free(wp->doutp); wp->doutp = (unsigned char *)malloc(do_len); if (! wp->doutp) { pr2serr("send_then_receive: unable to malloc %d bytes\n", do_len); return SG_LIB_CAT_OTHER; } wp->dout_len = do_len; } memset(wp->doutp, 0, do_len); wp->doutp[0] = DPC_DOWNLOAD_MICROCODE; wp->doutp[1] = op->mc_subenc; sg_put_unaligned_be16(do_len - 4, wp->doutp + 2); sg_put_unaligned_be32(gen_code, wp->doutp + 4); wp->doutp[8] = op->mc_mode; wp->doutp[11] = op->mc_id; if (send_data) sg_put_unaligned_be32(op->mc_offset + off_off, wp->doutp + 12); sg_put_unaligned_be32(op->mc_tlen, wp->doutp + 16); sg_put_unaligned_be32(dmp_len, wp->doutp + 20); if (send_data && (dmp_len > 0)) memcpy(wp->doutp + 24, dmp, dmp_len); /* select long duration timeout (7200 seconds) */ res = sg_ll_send_diag(sg_fd, 0 /* sf_code */, 1 /* pf */, 0 /* sf */, 0 /* devofl */, 0 /* unitofl */, 1 /* long_duration */, wp->doutp, do_len, 1 /* noisy */, verb); if (op->mc_non) { /* If non-standard, only call RDR after failed SD */ if (0 == res) return 0; /* If RDR error after SD error, prefer reporting SD error */ ret = res; } else { switch (op->mc_mode) { case MODE_DNLD_MC_OFFS: case MODE_DNLD_MC_OFFS_SAVE: if (res) return res; else if (last) return 0; /* RDR after last may hit a device reset */ break; case MODE_DNLD_MC_OFFS_DEFER: if (res) return res; break; case MODE_ACTIVATE_MC: if (0 == res) return 0; /* RDR after ACTIVATE_MC may hit a device reset */ /* SD has failed, so do a RDR but return SD's error */ ret = res; break; default: pr2serr("send_then_receive: mc_mode=0x%x\n", op->mc_mode); return SG_LIB_SYNTAX_ERROR; } } res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, DEF_DI_LEN, 1, verb); if (res) return ret ? ret : res; rsp_len = sg_get_unaligned_be16(dip + 2) + 4; if (rsp_len > DEF_DI_LEN) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", DEF_DI_LEN, rsp_len); rsp_len = DEF_DI_LEN; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); return ret ? ret : SG_LIB_CAT_OTHER; } rec_gen_code = sg_get_unaligned_be32(dip + 4); if (rec_gen_code != gen_code) pr2serr("gen_code changed from %" PRIu32 " to %" PRIu32 ", continuing but may fail\n", gen_code, rec_gen_code); num = (rsp_len - 8) / 16; if ((rsp_len - 8) % 16) pr2serr("Found %d Download microcode status descriptors, but there " "is residual\n", num); ucp = dip + 8; for (k = 0; k < num; ++k, ucp += 16) { if ((unsigned int)op->mc_subenc == (unsigned int)ucp[1]) { mc_status = ucp[2]; cp = get_mc_status_str(mc_status); if ((mc_status >= 0x80) || op->verbose) pr2serr("mc offset=%d: status: %s [0x%x, additional=0x%x]\n", off_off, cp, mc_status, ucp[3]); if (op->verbose > 1) pr2serr(" subenc_id=%d, expected_buffer_id=%d, " "expected_offset=0x%" PRIx32 "\n", ucp[1], ucp[11], sg_get_unaligned_be32(ucp + 12)); if (mc_status >= 0x80) ret = ret ? ret : SG_LIB_CAT_OTHER; } } return ret; } int main(int argc, char * argv[]) { int sg_fd, res, c, len, k, n, got_stdin, is_reg, rsp_len, verb, last; int infd = -1; int do_help = 0; const char * device_name = NULL; const char * file_name = NULL; unsigned char * dmp = NULL; unsigned char * dip = NULL; char * cp; char ebuff[EBUFF_SZ]; struct stat a_stat; struct dout_buff_t dout; struct opts_t opts; struct opts_t * op; const struct mode_s * mp; uint32_t gen_code = 0; int ret = 0; op = &opts; memset(op, 0, sizeof(opts)); memset(&dout, 0, sizeof(dout)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:hi:I:l:m:No:s:S:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': op->bpw = sg_get_num(optarg); if (op->bpw < 0) { pr2serr("argument to '--bpw' should be in a positive " "number\n"); return SG_LIB_SYNTAX_ERROR; } if ((cp = strchr(optarg, ','))) { if (0 == strncmp("act", cp + 1, 3)) ++op->bpw_then_activate; } break; case 'h': case '?': ++do_help; break; case 'i': op->mc_id = sg_get_num(optarg); if ((op->mc_id < 0) || (op->mc_id > 255)) { pr2serr("argument to '--id' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': file_name = optarg; break; case 'l': op->mc_len = sg_get_num(optarg); if (op->mc_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } op->mc_len_given = 1; break; case 'm': if (isdigit(*optarg)) { op->mc_mode = sg_get_num(optarg); if ((op->mc_mode < 0) || (op->mc_mode > 255)) { pr2serr("argument to '--mode' should be in the range 0 " "to 255\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = mode_arr; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { op->mc_mode = mp->mode; break; } } if (! mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'N': ++op->mc_non; break; case 'o': op->mc_offset = sg_get_num(optarg); if (op->mc_offset < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 != (op->mc_offset % 4)) { pr2serr("'--offset' value needs to be a multiple of 4\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': op->mc_skip = sg_get_num(optarg); if (op->mc_skip < 0) { pr2serr("bad argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': op->mc_subenc = sg_get_num(optarg); if ((op->mc_subenc < 0) || (op->mc_subenc > 255)) { pr2serr("expected argument to '--subenc' to be 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': op->mc_tlen = sg_get_num(optarg); if (op->mc_tlen < 0) { pr2serr("bad argument to '--tlength'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++op->verbose; break; case 'V': pr2serr(ME "version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); pr2serr("\n"); print_modes(); } else usage(); return 0; } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((op->mc_len > 0) && (op->bpw > op->mc_len)) { pr2serr("trim chunk size (CS) to be the same as LEN\n"); op->bpw = op->mc_len; } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->verbose > 4) pr2serr("Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, op->verbose); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (file_name && ((MODE_DNLD_STATUS == op->mc_mode) || (MODE_ACTIVATE_MC == op->mc_mode))) pr2serr("ignoring --in=FILE option\n"); else if (file_name) { got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0; if (got_stdin) infd = STDIN_FILENO; else { if ((infd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } if ((0 == fstat(infd, &a_stat)) && S_ISREG(a_stat.st_mode)) { is_reg = 1; if (0 == op->mc_len) { if (op->mc_skip >= a_stat.st_size) { pr2serr("skip exceeds file size of %d bytes\n", (int)a_stat.st_size); ret = SG_LIB_FILE_ERROR; goto fini; } op->mc_len = (int)(a_stat.st_size) - op->mc_skip; } } else { is_reg = 0; if (0 == op->mc_len) op->mc_len = DEF_XFER_LEN; } if (op->mc_len > MAX_XFER_LEN) { pr2serr("file size or requested length (%d) exceeds " "MAX_XFER_LEN of %d bytes\n", op->mc_len, MAX_XFER_LEN); ret = SG_LIB_FILE_ERROR; goto fini; } if (NULL == (dmp = (unsigned char *)malloc(op->mc_len))) { pr2serr(ME "out of memory (to hold microcode)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } /* Don't remember why this is preset to 0xff, from write_buffer */ memset(dmp, 0xff, op->mc_len); if (op->mc_skip > 0) { if (! is_reg) { if (got_stdin) pr2serr("Can't skip on stdin\n"); else pr2serr(ME "not a 'regular' file so can't apply skip\n"); ret = SG_LIB_FILE_ERROR; goto fini; } if (lseek(infd, op->mc_skip, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } } res = read(infd, dmp, op->mc_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto fini; } if (res < op->mc_len) { if (op->mc_len_given) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", op->mc_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } else { if (op->verbose) { pr2serr("tried to read %d bytes from %s, got %d " "bytes\n", op->mc_len, file_name, res); pr2serr("will send %d bytes", res); if ((op->bpw > 0) && (op->bpw < op->mc_len)) pr2serr(", %d bytes per WRITE BUFFER command\n", op->bpw); else pr2serr("\n"); } op->mc_len = res; } } if (! got_stdin) close(infd); infd = -1; } else if (! ((MODE_DNLD_STATUS == op->mc_mode) || (MODE_ACTIVATE_MC == op->mc_mode))) { pr2serr("need --in=FILE option with given mode\n"); ret = SG_LIB_SYNTAX_ERROR; goto fini; } if (op->mc_tlen < op->mc_len) op->mc_tlen = op->mc_len; if (op->mc_non && (MODE_DNLD_STATUS == op->mc_mode)) { pr2serr("Do nothing because '--non' given so fetching the Download " "microcode status\ndpage might be dangerous\n"); goto fini; } if (NULL == (dip = (unsigned char *)malloc(DEF_DI_LEN))) { pr2serr(ME "out of memory (data-in buffer)\n"); ret = SG_LIB_CAT_OTHER; goto fini; } memset(dip, 0, DEF_DI_LEN); verb = (op->verbose > 1) ? op->verbose - 1 : 0; /* Fetch Download microcode status dpage for generation code ++ */ res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, DPC_DOWNLOAD_MICROCODE, dip, DEF_DI_LEN, 1, verb); if (0 == res) { rsp_len = sg_get_unaligned_be16(dip + 2) + 4; if (rsp_len > DEF_DI_LEN) { pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", DEF_DI_LEN, rsp_len); rsp_len = DEF_DI_LEN; } if (rsp_len < 8) { pr2serr("Download microcode status dpage too short\n"); ret = SG_LIB_CAT_OTHER; goto fini; } } else { ret = res; goto fini; } gen_code = sg_get_unaligned_be32(dip + 4); if (MODE_DNLD_STATUS == op->mc_mode) { ses_download_code_sdg(dip, rsp_len, gen_code); goto fini; } else if (MODE_ACTIVATE_MC == op->mc_mode) { res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1, op); ret = res; goto fini; } res = 0; if (op->bpw > 0) { for (k = 0, last = 0; k < op->mc_len; k += n) { n = op->mc_len - k; if (n > op->bpw) n = op->bpw; else last = 1; if (op->verbose) pr2serr("bpw loop: mode=0x%x, id=%d, off_off=%d, len=%d, " "last=%d\n", op->mc_mode, op->mc_id, k, n, last); res = send_then_receive(sg_fd, gen_code, k, dmp + k, n, &dout, dip, last, op); if (res) break; } if (op->bpw_then_activate && (0 == res)) { op->mc_mode = MODE_ACTIVATE_MC; if (op->verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); res = send_then_receive(sg_fd, gen_code, 0, NULL, 0, &dout, dip, 1, op); } } else { if (op->verbose) pr2serr("single: mode=0x%x, id=%d, offset=%d, len=%d\n", op->mc_mode, op->mc_id, op->mc_offset, op->mc_len); res = send_then_receive(sg_fd, gen_code, 0, dmp, op->mc_len, &dout, dip, 1, op); } if (res) ret = res; fini: if ((infd >= 0) && (! got_stdin)) close(infd); if (dmp) free(dmp); if (dout.doutp) free(dout.doutp); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } if (ret && (0 == op->verbose)) { if (SG_LIB_CAT_INVALID_OP == ret) pr2serr("%sRECEIVE DIAGNOSTIC RESULTS command not supported\n", ((MODE_DNLD_STATUS == op->mc_mode) ? "" : "SEND DIAGNOSTIC or ")); else if (ret > 0) fprintf(stderr, "Failed, exit status %d\n", ret); else if (ret < 0) fprintf(stderr, "Some error occurred\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sginfo.c0000664000175000017500000040366412317661702014612 0ustar douggdougg/* * This program reads various mode pages and bits of other * information from a scsi device and interprets the raw data for you * with a report written to stdout. Usage: * * ./sginfo [options] /dev/sg2 [replace parameters] * * Options are: * -6 do 6 byte mode sense + select (deafult: 10 byte) * -a display all mode pages reported by the device: equivalent to '-t 63'. * -A display all mode pages and subpages reported by the device: equivalent * to '-t 63,255'. * -c access Cache control page. * -C access Control Page. * -d display defect lists (default format: index). * -D access disconnect-reconnect page. * -e access Read-Write error recovery page. * -E access Control Extension page. * -f access Format Device Page. * -Farg defect list format (-Flogical, -flba64, -Fphysical, -Findex, -Fhead) * -g access rigid disk geometry page. * -G display only "grown" defect list (default format: index) * -i display information from Inquiry command. * -I access Informational Exceptions page. * -l list known scsi devices on the system [deprecated] * -n access notch parameters page. * -N Negate (stop) storing to saved page (active with -R) * -P access Power Condition Page. * -r list known raw scsi devices on the system * -s display serial number (from INQUIRY VPD page) * -t access page number [and subpage ], try to decode * -u access page number [and subpage ], output in hex * -v show this program's version number * -V access Verify Error Recovery Page. * -T trace commands (for debugging, double for more debug) * -z do a single fetch for mode pages (rather than double fetch) * * Only one of the following three options can be specified. * None of these three implies the current values are returned. * -m Display modifiable fields instead of current values * -M Display manufacturer defaults instead of current values * -S Display saved defaults instead of current values * * -X Display output values in a list. * -R Replace parameters - best used with -X * * Eric Youngdale - 11/1/93. Version 1.0. * * Version 1.1: Ability to change parameters on cache page, support for * X front end. * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Michael Weller (eowmob at exp-math dot uni-essen dot de) * 11/23/94 massive extensions from 1.4a * 08/23/97 fix problems with defect lists * * Douglas Gilbert (dgilbert at interlog dot com) * 990628 port to sg .... (version 1.81) * up 4KB limit on defect list to 32KB * 'sginfo -l' also shows sg devices and mapping to other * scsi devices * 'sginfo' commands can take either an sd, sr (scd), st * or an sg device (all non-sg devices converted to a * sg device) * * 001208 Add Kurt Garloff's "-uno" flag for displaying info * from a page number. [version 1.90] * * Kurt Garloff * 20000715 allow displaying and modification of vendor specific pages * (unformatted - @ hexdatafield) * accept vendor lengths for those pages * enabled page saving * cleaned parameter parsing a bit (it's still a terrible mess!) * Use sr (instead of scd) and sg%d (instead of sga,b,...) in -l * and support much more devs in -l (incl. nosst) * Fix segfault in defect list (len=0xffff) and adapt formatting * to large disks. Support up to 256kB defect lists with * 0xB7 (12byte) command if necessary and fallback to 0x37 * (10byte) in case of failure. Report truncation. * sizeof(buffer) (which is sizeof(char*) == 4 or 32 bit archs) * was used incorrectly all over the place. Fixed. * [version 1.95] * Douglas Gilbert (dgilbert at interlog dot com) * 20020113 snprintf() type cleanup [version 1.96] * 20021211 correct sginfo MODE_SELECT, protect against block devices * that answer sg's ioctls. [version 1.97] * 20021228 scan for some "scd" as well as "sr" device names [1.98] * 20021020 Update control page [1.99] * * Thomas Steudten (thomas at steudten dot com) * 20040521 add -Fhead feature [version 2.04] * * Tim Hunt (tim at timhunt dot net) * 20050427 increase number of mapped SCSI disks devices * * Dave Johnson (djj at ccv dot brown dot edu) * 20051218 improve disk defect list handling */ /* * N.B. This utility is in maintenance mode only. This means that serious * bugs will be fixed but no new features or mode page changes will be * added. Please use the sdparm utility. D. Gilbert 20090316 */ #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif static const char * version_str = "2.35 [20140403]"; #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_io_linux.h" static int glob_fd; static char *device_name; #define MAX_SG_DEVS 8192 #define MAX_RESP6_SIZE 252 #define MAX_RESP10_SIZE (4*1024) #define MAX_BUFFER_SIZE MAX_RESP10_SIZE #define INQUIRY_RESP_INITIAL_LEN 36 #define MAX_INQFIELD_LEN 17 #define MAX_HEADS 127 #define HEAD_SORT_TOKEN 0x55 #define SIZEOF_BUFFER (16*1024) #define SIZEOF_BUFFER1 (16*1024) static unsigned char cbuffer[SIZEOF_BUFFER]; static unsigned char cbuffer1[SIZEOF_BUFFER1]; static unsigned char cbuffer2[SIZEOF_BUFFER1]; static char defect = 0; static char defectformat = 0x4; static char grown_defect = 0; static char negate_sp_bit = 0; static char replace = 0; static char serial_number = 0; static char x_interface = 0; static char single_fetch = 0; static char mode6byte = 0; /* defaults to 10 byte mode sense + select */ static char trace_cmd = 0; struct mpage_info { int page; int subpage; int page_control; int peri_type; int inq_byte6; /* EncServ and MChngr bits of interest */ int resp_len; }; /* declarations of functions decoding known mode pages */ static int common_disconnect_reconnect(struct mpage_info * mpi, const char * prefix); static int common_control(struct mpage_info * mpi, const char * prefix); static int common_control_extension(struct mpage_info * mpi, const char * prefix); static int common_proto_spec_lu(struct mpage_info * mpi, const char * prefix); static int common_proto_spec_port(struct mpage_info * mpi, const char * prefix); static int common_proto_spec_port_sp1(struct mpage_info * mpi, const char * prefix); static int common_proto_spec_port_sp2(struct mpage_info * mpi, const char * prefix); static int common_power_condition(struct mpage_info * mpi, const char * prefix); static int common_informational(struct mpage_info * mpi, const char * prefix); static int disk_error_recovery(struct mpage_info * mpi, const char * prefix); static int disk_format(struct mpage_info * mpi, const char * prefix); static int disk_verify_error_recovery(struct mpage_info * mpi, const char * prefix); static int disk_geometry(struct mpage_info * mpi, const char * prefix); static int disk_notch_parameters(struct mpage_info * mpi, const char * prefix); static int disk_cache(struct mpage_info * mpi, const char * prefix); static int disk_xor_control(struct mpage_info * mpi, const char * prefix); static int disk_background(struct mpage_info * mpi, const char * prefix); static int optical_memory(struct mpage_info * mpi, const char * prefix); static int cdvd_error_recovery(struct mpage_info * mpi, const char * prefix); static int cdvd_mrw(struct mpage_info * mpi, const char * prefix); static int cdvd_write_param(struct mpage_info * mpi, const char * prefix); static int cdvd_audio_control(struct mpage_info * mpi, const char * prefix); static int cdvd_timeout(struct mpage_info * mpi, const char * prefix); static int cdvd_device_param(struct mpage_info * mpi, const char * prefix); static int cdvd_cache(struct mpage_info * mpi, const char * prefix); static int cdvd_mm_capab(struct mpage_info * mpi, const char * prefix); static int cdvd_feature(struct mpage_info * mpi, const char * prefix); static int tape_data_compression(struct mpage_info * mpi, const char * prefix); static int tape_dev_config(struct mpage_info * mpi, const char * prefix); static int tape_medium_part1(struct mpage_info * mpi, const char * prefix); static int tape_medium_part2_4(struct mpage_info * mpi, const char * prefix); static int ses_services_manag(struct mpage_info * mpi, const char * prefix); static int spi4_training_config(struct mpage_info * mpi, const char * prefix); static int spi4_negotiated(struct mpage_info * mpi, const char * prefix); static int spi4_report_xfer(struct mpage_info * mpi, const char * prefix); enum page_class {PC_COMMON, PC_DISK, PC_TAPE, PC_CDVD, PC_SES, PC_SMC}; struct mpage_name_func { int page; int subpage; enum page_class pg_class; const char * name; int (*func)(struct mpage_info *, const char *); }; #define MP_LIST_PAGES 0x3f #define MP_LIST_SUBPAGES 0xff static struct mpage_name_func mpage_common[] = { { 0, 0, PC_COMMON, "Vendor (non-page format)", NULL}, { 2, 0, PC_COMMON, "Disconnect-Reconnect", common_disconnect_reconnect}, { 9, 0, PC_COMMON, "Peripheral device (obsolete)", NULL}, { 0xa, 0, PC_COMMON, "Control", common_control}, { 0xa, 1, PC_COMMON, "Control Extension", common_control_extension}, { 0x15, 0, PC_COMMON, "Extended", NULL}, { 0x16, 0, PC_COMMON, "Extended, device-type specific", NULL}, { 0x18, 0, PC_COMMON, "Protocol specific lu", common_proto_spec_lu}, { 0x19, 0, PC_COMMON, "Protocol specific port", common_proto_spec_port}, { 0x19, 1, PC_COMMON, "Protocol specific port, subpage 1 overload", common_proto_spec_port_sp1}, { 0x19, 2, PC_COMMON, "Protocol specific port, subpage 2 overload", common_proto_spec_port_sp2}, /* { 0x19, 2, PC_COMMON, "SPI-4 Saved Training configuration", spi4_training_config}, */ { 0x19, 3, PC_COMMON, "SPI-4 Negotiated Settings", spi4_negotiated}, { 0x19, 4, PC_COMMON, "SPI-4 Report transfer capabilities", spi4_report_xfer}, { 0x1a, 0, PC_COMMON, "Power Condition", common_power_condition}, { 0x1c, 0, PC_COMMON, "Informational Exceptions", common_informational}, { MP_LIST_PAGES, 0, PC_COMMON, "Return all pages", NULL}, }; static const int mpage_common_len = sizeof(mpage_common) / sizeof(mpage_common[0]); static struct mpage_name_func mpage_disk[] = { { 1, 0, PC_DISK, "Read-Write Error Recovery", disk_error_recovery}, { 3, 0, PC_DISK, "Format Device", disk_format}, { 4, 0, PC_DISK, "Rigid Disk Geometry", disk_geometry}, { 5, 0, PC_DISK, "Flexible Disk", NULL}, { 6, 0, PC_DISK, "Optical memory", optical_memory}, { 7, 0, PC_DISK, "Verify Error Recovery", disk_verify_error_recovery}, { 8, 0, PC_DISK, "Caching", disk_cache}, { 0xa, 0xf1, PC_DISK, "Parallel ATA control (SAT)", NULL}, { 0xb, 0, PC_DISK, "Medium Types Supported", NULL}, { 0xc, 0, PC_DISK, "Notch and Partition", disk_notch_parameters}, { 0x10, 0, PC_DISK, "XOR control", disk_xor_control}, { 0x1c, 1, PC_DISK, "Background control", disk_background}, }; static const int mpage_disk_len = sizeof(mpage_disk) / sizeof(mpage_disk[0]); static struct mpage_name_func mpage_cdvd[] = { { 1, 0, PC_CDVD, "Read-Write Error Recovery (cdvd)", cdvd_error_recovery}, { 3, 0, PC_CDVD, "MRW", cdvd_mrw}, { 5, 0, PC_CDVD, "Write parameters", cdvd_write_param}, { 8, 0, PC_CDVD, "Caching", cdvd_cache}, { 0xd, 0, PC_CDVD, "CD device parameters", cdvd_device_param}, { 0xe, 0, PC_CDVD, "CD audio control", cdvd_audio_control}, { 0x18, 0, PC_CDVD, "Feature set support & version", cdvd_feature}, { 0x1a, 0, PC_CDVD, "Power Condition", common_power_condition}, { 0x1c, 0, PC_CDVD, "Fault/failure reporting control", common_informational}, { 0x1d, 0, PC_CDVD, "Time-out & protect", cdvd_timeout}, { 0x2a, 0, PC_CDVD, "MM capabilities & mechanical status", cdvd_mm_capab}, }; static const int mpage_cdvd_len = sizeof(mpage_cdvd) / sizeof(mpage_cdvd[0]); static struct mpage_name_func mpage_tape[] = { { 1, 0, PC_TAPE, "Read-Write Error Recovery", disk_error_recovery}, { 0xf, 0, PC_TAPE, "Data compression", tape_data_compression}, { 0x10, 0, PC_TAPE, "Device configuration", tape_dev_config}, { 0x10, 1, PC_TAPE, "Device configuration extension", NULL}, { 0x11, 0, PC_TAPE, "Medium partition(1)", tape_medium_part1}, { 0x12, 0, PC_TAPE, "Medium partition(2)", tape_medium_part2_4}, { 0x13, 0, PC_TAPE, "Medium partition(3)", tape_medium_part2_4}, { 0x14, 0, PC_TAPE, "Medium partition(4)", tape_medium_part2_4}, { 0x1c, 0, PC_TAPE, "Informational Exceptions", common_informational}, { 0x1d, 0, PC_TAPE, "Medium configuration", NULL}, }; static const int mpage_tape_len = sizeof(mpage_tape) / sizeof(mpage_tape[0]); static struct mpage_name_func mpage_ses[] = { { 0x14, 0, PC_SES, "Enclosure services management", ses_services_manag}, }; static const int mpage_ses_len = sizeof(mpage_ses) / sizeof(mpage_ses[0]); static struct mpage_name_func mpage_smc[] = { { 0x1d, 0, PC_SMC, "Element address assignment", NULL}, { 0x1e, 0, PC_SMC, "Transport geometry parameters", NULL}, { 0x1f, 0, PC_SMC, "Device capabilities", NULL}, { 0x1f, 1, PC_SMC, "Extended device capabilities", NULL}, }; static const int mpage_smc_len = sizeof(mpage_smc) / sizeof(mpage_smc[0]); #define MAXPARM 64 static int next_parameter; static int n_replacement_values; static uint64_t replacement_values[MAXPARM]; static char is_hex[MAXPARM]; #define SMODE_SENSE 0x1a #define SMODE_SENSE_10 0x5a #define SMODE_SELECT 0x15 #define SMODE_SELECT_10 0x55 #define MPHEADER6_LEN 4 #define MPHEADER10_LEN 8 /* forward declarations */ static void usage(const char *); static void dump(void *buffer, unsigned int length); #define DXFER_NONE 0 #define DXFER_FROM_DEVICE 1 #define DXFER_TO_DEVICE 2 struct scsi_cmnd_io { unsigned char * cmnd; /* ptr to SCSI command block (cdb) */ size_t cmnd_len; /* number of bytes in SCSI command */ int dxfer_dir; /* DXFER_NONE, DXFER_FROM_DEVICE, or DXFER_TO_DEVICE */ unsigned char * dxferp; /* ptr to outgoing/incoming data */ size_t dxfer_len; /* bytes to be transferred to/from dxferp */ }; #define SENSE_BUFF_LEN 64 #define CMD_TIMEOUT 60000 /* 60,000 milliseconds (60 seconds) */ #define EBUFF_SZ 256 #define GENERAL_ERROR 1 #define UNKNOWN_OPCODE 2 #define BAD_CDB_FIELD 3 #define UNSUPPORTED_PARAM 4 #define DEVICE_ATTENTION 5 #define DEVICE_NOT_READY 6 #define DECODE_FAILED_TRY_HEX 9999 /* Returns 0 -> ok, 1 -> general error, 2 -> unknown opcode, 3 -> unsupported field in cdb, 4 -> unsupported param in data-in */ static int do_scsi_io(struct scsi_cmnd_io * sio) { unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; struct sg_scsi_sense_hdr ssh; int res; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sio->cmnd_len; io_hdr.mx_sb_len = sizeof(sense_b); if (DXFER_NONE == sio->dxfer_dir) io_hdr.dxfer_direction = SG_DXFER_NONE; else io_hdr.dxfer_direction = (DXFER_TO_DEVICE == sio->dxfer_dir) ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; io_hdr.dxfer_len = sio->dxfer_len; io_hdr.dxferp = sio->dxferp; io_hdr.cmdp = sio->cmnd; io_hdr.sbp = sense_b; io_hdr.timeout = CMD_TIMEOUT; if (trace_cmd) { printf(" cdb:"); dump(sio->cmnd, sio->cmnd_len); } if ((trace_cmd > 1) && (DXFER_TO_DEVICE == sio->dxfer_dir)) { printf(" additional data:\n"); dump(sio->dxferp, sio->dxfer_len); } if (ioctl(glob_fd, SG_IO, &io_hdr) < 0) { perror("do_scsi_cmd: SG_IO error"); return GENERAL_ERROR; } res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("do_scsi_cmd, continuing", &io_hdr, 1); /* fall through */ case SG_LIB_CAT_CLEAN: return 0; default: if (trace_cmd) { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "do_scsi_io: opcode=0x%x", sio->cmnd[0]); sg_chk_n_print3(ebuff, &io_hdr, 1); } if (sg_normalize_sense(&io_hdr, &ssh)) { if (ILLEGAL_REQUEST == ssh.sense_key) { if (0x20 == ssh.asc) return UNKNOWN_OPCODE; else if (0x24 == ssh.asc) return BAD_CDB_FIELD; else if (0x26 == ssh.asc) return UNSUPPORTED_PARAM; } else if (UNIT_ATTENTION == ssh.sense_key) return DEVICE_ATTENTION; else if (NOT_READY == ssh.sense_key) return DEVICE_NOT_READY; } return GENERAL_ERROR; } } struct mpage_name_func * get_mpage_info(int page_no, int subpage_no, struct mpage_name_func * mpp, int elems) { int k; for (k = 0; k < elems; ++k, ++mpp) { if ((mpp->page == page_no) && (mpp->subpage == subpage_no)) return mpp; if (mpp->page > page_no) break; } return NULL; } enum page_class get_page_class(struct mpage_info * mpi) { switch (mpi->peri_type) { case 0: case 4: case 7: case 0xe: /* should be RBC */ return PC_DISK; case 1: case 2: return PC_TAPE; case 8: return PC_SMC; case 5: return PC_CDVD; case 0xd: return PC_SES; default: return PC_COMMON; } } struct mpage_name_func * get_mpage_name_func(struct mpage_info * mpi) { struct mpage_name_func * mpf = NULL; switch (get_page_class(mpi)) { case PC_DISK: mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_disk, mpage_disk_len); break; case PC_CDVD: mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_cdvd, mpage_cdvd_len); break; case PC_TAPE: mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_tape, mpage_tape_len); break; case PC_SES: mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_ses, mpage_ses_len); break; case PC_SMC: mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_smc, mpage_smc_len); break; case PC_COMMON: /* picked up it catch all next */ break; } if (NULL == mpf) { if ((PC_SES != get_page_class(mpi)) && (mpi->inq_byte6 & 0x40)) { /* check for attached enclosure services processor */ mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_ses, mpage_ses_len); } if ((PC_SMC != get_page_class(mpi)) && (mpi->inq_byte6 & 0x8)) { /* check for attached medium changer device */ mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_smc, mpage_smc_len); } } if (NULL == mpf) mpf = get_mpage_info(mpi->page, mpi->subpage, mpage_common, mpage_common_len); return mpf; } static char unkn_page_str[64]; static const char * get_page_name(struct mpage_info * mpi) { struct mpage_name_func * mpf; if (MP_LIST_PAGES == mpi->page) { if (MP_LIST_SUBPAGES == mpi->subpage) return "List supported pages and subpages"; else return "List supported pages"; } mpf = get_mpage_name_func(mpi); if ((NULL == mpf) || (NULL == mpf->name)) { if (mpi->subpage) snprintf(unkn_page_str, sizeof(unkn_page_str), "page number=0x%x, subpage number=0x%x", mpi->page, mpi->subpage); else snprintf(unkn_page_str, sizeof(unkn_page_str), "page number=0x%x", mpi->page); return unkn_page_str; } return mpf->name; } static void dump(void *buffer, unsigned int length) { unsigned int i; printf(" "); for (i = 0; i < length; i++) { #if 0 if (((unsigned char *) buffer)[i] > 0x20) printf(" %c ", (unsigned int) ((unsigned char *) buffer)[i]); else #endif printf("%02x ", (unsigned int) ((unsigned char *) buffer)[i]); if ((i % 16 == 15) && (i < (length - 1))) { printf("\n "); } } printf("\n"); } static int getnbyte(const unsigned char *pnt, int nbyte) { unsigned int result; int i; if (nbyte > 4) fprintf(stderr, "getnbyte() limited to 32 bits, nbyte=%d\n", nbyte); result = 0; for (i = 0; i < nbyte; i++) result = (result << 8) | (pnt[i] & 0xff); return result; } static int64_t getnbyte_ll(const unsigned char *pnt, int nbyte) { int64_t result; int i; if (nbyte > 8) fprintf(stderr, "getnbyte_ll() limited to 64 bits, nbyte=%d\n", nbyte); result = 0; for (i = 0; i < nbyte; i++) result = (result << 8) + (pnt[i] & 0xff); return result; } static int putnbyte(unsigned char *pnt, unsigned int value, unsigned int nbyte) { int i; for (i = nbyte - 1; i >= 0; i--) { pnt[i] = value & 0xff; value = value >> 8; } return 0; } #define REASON_SZ 128 static void check_parm_type(int i) { char reason[REASON_SZ]; if (i == 1 && is_hex[next_parameter] != 1) { snprintf(reason, REASON_SZ, "simple number (pos %i) instead of @ hexdatafield: %" PRIu64 , next_parameter, replacement_values[next_parameter]); usage(reason); } if (i != 1 && is_hex[next_parameter]) { snprintf(reason, REASON_SZ, "@ hexdatafield (pos %i) instead of a simple number: %" PRIu64 , next_parameter, replacement_values[next_parameter]); usage(reason); } } static void bitfield(unsigned char *pageaddr, const char * text, int mask, int shift) { if (x_interface && replace) { check_parm_type(0); *pageaddr = (*pageaddr & ~(mask << shift)) | ((replacement_values[next_parameter++] & mask) << shift); } else if (x_interface) printf("%d ", (*pageaddr >> shift) & mask); else printf("%-35s%d\n", text, (*pageaddr >> shift) & mask); } #if 0 static void notbitfield(unsigned char *pageaddr, char * text, int mask, int shift) { if (modifiable) { bitfield(pageaddr, text, mask, shift); return; } if (x_interface && replace) { check_parm_type(0); *pageaddr = (*pageaddr & ~(mask << shift)) | (((!replacement_values[next_parameter++]) & mask) << shift); } else if (x_interface) printf("%d ", !((*pageaddr >> shift) & mask)); else printf("%-35s%d\n", text, !((*pageaddr >> shift) & mask)); } #endif static void intfield(unsigned char * pageaddr, int nbytes, const char * text) { if (x_interface && replace) { check_parm_type(0); putnbyte(pageaddr, replacement_values[next_parameter++], nbytes); } else if (x_interface) printf("%d ", getnbyte(pageaddr, nbytes)); else printf("%-35s%d\n", text, getnbyte(pageaddr, nbytes)); } static void hexfield(unsigned char * pageaddr, int nbytes, const char * text) { if (x_interface && replace) { check_parm_type(0); putnbyte(pageaddr, replacement_values[next_parameter++], nbytes); } else if (x_interface) printf("%d ", getnbyte(pageaddr, nbytes)); else printf("%-35s0x%x\n", text, getnbyte(pageaddr, nbytes)); } static void hexdatafield(unsigned char * pageaddr, int nbytes, const char * text) { if (x_interface && replace) { unsigned char *ptr; unsigned tmp; /* Though in main we ensured that a @string has the right format, we have to check that we are working on a @ hexdata field */ check_parm_type(1); ptr = (unsigned char *) (unsigned long) (replacement_values[next_parameter++]); ptr++; /* Skip @ */ while (*ptr) { if (!nbytes) goto illegal; tmp = (*ptr >= 'a') ? (*ptr - 'a' + 'A') : *ptr; tmp -= (tmp >= 'A') ? 'A' - 10 : '0'; *pageaddr = tmp << 4; ptr++; tmp = (*ptr >= 'a') ? (*ptr - 'a' + 'A') : *ptr; tmp -= (tmp >= 'A') ? 'A' - 10 : '0'; *pageaddr++ += tmp; ptr++; nbytes--; } if (nbytes) { illegal: fputs("sginfo: incorrect number of bytes in @hexdatafield.\n", stdout); exit(2); } } else if (x_interface) { putchar('@'); while (nbytes-- > 0) printf("%02x", *pageaddr++); putchar(' '); } else { printf("%-35s0x", text); while (nbytes-- > 0) printf("%02x", *pageaddr++); putchar('\n'); } } /* Offset into mode sense (6 or 10 byte) response that actual mode page * starts at (relative to resp[0]). Returns -1 if problem */ static int modePageOffset(const unsigned char * resp, int len, int modese_6) { int bd_len; int resp_len = 0; int offset = -1; if (resp) { if (modese_6) { resp_len = resp[0] + 1; bd_len = resp[3]; offset = bd_len + MPHEADER6_LEN; } else { resp_len = (resp[0] << 8) + resp[1] + 2; bd_len = (resp[6] << 8) + resp[7]; /* LongLBA doesn't change this calculation */ offset = bd_len + MPHEADER10_LEN; } if ((offset + 2) > len) { printf("modePageOffset: raw_curr too small, offset=%d " "resp_len=%d bd_len=%d\n", offset, resp_len, bd_len); offset = -1; } else if ((offset + 2) > resp_len) { printf("modePageOffset: response length too short, resp_len=%d" " offset=%d bd_len=%d\n", resp_len, offset, bd_len); offset = -1; } } return offset; } /* Reads mode (sub-)page via 6 byte MODE SENSE, returns 0 if ok */ static int get_mode_page6(struct mpage_info * mpi, int dbd, unsigned char * resp, int sngl_fetch) { int status, off; unsigned char cmd[6]; struct scsi_cmnd_io sci; int initial_len = (sngl_fetch ? MAX_RESP6_SIZE : 4); memset(resp, 0, 4); cmd[0] = SMODE_SENSE; /* MODE SENSE (6) */ cmd[1] = 0x00 | (dbd ? 0x8 : 0); /* disable block descriptors bit */ cmd[2] = (mpi->page_control << 6) | mpi->page; cmd[3] = mpi->subpage; /* subpage code */ cmd[4] = initial_len; cmd[5] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = initial_len; sci.dxferp = resp; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage " "0x%x [mode_sense_6]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to read %s mode page (0x%x) " "[mode_sense_6]\n", get_page_name(mpi), mpi->page); return status; } mpi->resp_len = resp[0] + 1; if (sngl_fetch) { if (trace_cmd > 1) { off = modePageOffset(resp, mpi->resp_len, 1); if (off >= 0) { printf(" cdb response:\n"); dump(resp, mpi->resp_len); } } return status; } cmd[4] = mpi->resp_len; sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = mpi->resp_len; sci.dxferp = resp; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage " "0x%x [mode_sense_6]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to read %s mode page (0x%x) " "[mode_sense_6]\n", get_page_name(mpi), mpi->page); } else if (trace_cmd > 1) { off = modePageOffset(resp, mpi->resp_len, 1); if (off >= 0) { printf(" cdb response:\n"); dump(resp, mpi->resp_len); } } return status; } /* Reads mode (sub-)page via 10 byte MODE SENSE, returns 0 if ok */ static int get_mode_page10(struct mpage_info * mpi, int llbaa, int dbd, unsigned char * resp, int sngl_fetch) { int status, off; unsigned char cmd[10]; struct scsi_cmnd_io sci; int initial_len = (sngl_fetch ? MAX_RESP10_SIZE : 4); memset(resp, 0, 4); cmd[0] = SMODE_SENSE_10; /* MODE SENSE (10) */ cmd[1] = 0x00 | (llbaa ? 0x10 : 0) | (dbd ? 0x8 : 0); cmd[2] = (mpi->page_control << 6) | mpi->page; cmd[3] = mpi->subpage; cmd[4] = 0x00; /* (reserved) */ cmd[5] = 0x00; /* (reserved) */ cmd[6] = 0x00; /* (reserved) */ cmd[7] = (initial_len >> 8) & 0xff; cmd[8] = initial_len & 0xff; cmd[9] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = initial_len; sci.dxferp = resp; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage " "0x%x [mode_sense_10]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to read %s mode page (0x%x) " "[mode_sense_10]\n", get_page_name(mpi), mpi->page); return status; } mpi->resp_len = (resp[0] << 8) + resp[1] + 2; if (sngl_fetch) { if (trace_cmd > 1) { off = modePageOffset(resp, mpi->resp_len, 0); if (off >= 0) { printf(" cdb response:\n"); dump(resp, mpi->resp_len); } } return status; } cmd[7] = (mpi->resp_len >> 8) & 0xff; cmd[8] = (mpi->resp_len & 0xff); sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = mpi->resp_len; sci.dxferp = resp; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to read %s mode page 0x%x, subpage " "0x%x [mode_sense_10]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to read %s mode page (0x%x) " "[mode_sense_10]\n", get_page_name(mpi), mpi->page); } else if (trace_cmd > 1) { off = modePageOffset(resp, mpi->resp_len, 0); if (off >= 0) { printf(" cdb response:\n"); dump(resp, mpi->resp_len); } } return status; } static int get_mode_page(struct mpage_info * mpi, int dbd, unsigned char * resp) { int res; if (mode6byte) res = get_mode_page6(mpi, dbd, resp, single_fetch); else res = get_mode_page10(mpi, 0, dbd, resp, single_fetch); if (UNKNOWN_OPCODE == res) fprintf(stdout, ">>>>> Try command again with%s '-6' " "argument\n", (mode6byte ? "out the" : " a")); else if (mpi->subpage && (BAD_CDB_FIELD == res)) fprintf(stdout, ">>>>> device doesn't seem to support " "subpages\n"); else if (DEVICE_ATTENTION == res) fprintf(stdout, ">>>>> device reports UNIT ATTENTION, check it or" " just try again\n"); else if (DEVICE_NOT_READY == res) fprintf(stdout, ">>>>> device NOT READY, does it need media?\n"); return res; } /* Contents should point to the mode parameter header that we obtained in a prior read operation. This way we do not have to work out the format of the beast. Assume 0 or 1 block descriptors. */ static int put_mode_page6(struct mpage_info * mpi, const unsigned char * msense6_resp, int sp_bit) { int status; int bdlen, resplen; unsigned char cmd[6]; struct scsi_cmnd_io sci; bdlen = msense6_resp[3]; resplen = msense6_resp[0] + 1; cmd[0] = SMODE_SELECT; cmd[1] = 0x10 | (sp_bit ? 1 : 0); /* always set PF bit */ cmd[2] = 0x00; cmd[3] = 0x00; /* (reserved) */ cmd[4] = resplen; /* parameter list length */ cmd[5] = 0x00; /* (reserved) */ memcpy(cbuffer1, msense6_resp, resplen); cbuffer1[0] = 0; /* Mask off the mode data length - reserved field */ cbuffer1[2] = 0; /* device-specific parameter is not defined and/or reserved for mode select */ #if 0 /* leave block descriptor alone */ if (bdlen > 0) { memset(cbuffer1 + MPHEADER6_LEN, 0, 4); /* clear 'number of blocks' for DAD device */ cbuffer1[MPHEADER6_LEN + 4] = 0; /* clear DAD density code. Why? */ /* leave DAD block length */ } #endif cbuffer1[MPHEADER6_LEN + bdlen] &= 0x7f; /* Mask PS bit */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_TO_DEVICE; sci.dxfer_len = resplen; sci.dxferp = cbuffer1; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to store %s mode page 0x%x," " subpage 0x%x [msel_6]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to store %s mode page 0x%x [msel_6]\n", get_page_name(mpi), mpi->page); } return status; } /* Contents should point to the mode parameter header that we obtained in a prior read operation. This way we do not have to work out the format of the beast. Assume 0 or 1 block descriptors. */ static int put_mode_page10(struct mpage_info * mpi, const unsigned char * msense10_resp, int sp_bit) { int status; int bdlen, resplen; unsigned char cmd[10]; struct scsi_cmnd_io sci; bdlen = (msense10_resp[6] << 8) + msense10_resp[7]; resplen = (msense10_resp[0] << 8) + msense10_resp[1] + 2; cmd[0] = SMODE_SELECT_10; cmd[1] = 0x10 | (sp_bit ? 1 : 0); /* always set PF bit */ cmd[2] = 0x00; /* (reserved) */ cmd[3] = 0x00; /* (reserved) */ cmd[4] = 0x00; /* (reserved) */ cmd[5] = 0x00; /* (reserved) */ cmd[6] = 0x00; /* (reserved) */ cmd[7] = (resplen >> 8) & 0xff; cmd[8] = resplen & 0xff; cmd[9] = 0x00; /* (reserved) */ memcpy(cbuffer1, msense10_resp, resplen); cbuffer1[0] = 0; /* Mask off the mode data length */ cbuffer1[1] = 0; /* Mask off the mode data length */ cbuffer1[3] = 0; /* device-specific parameter is not defined and/or reserved for mode select */ #if 0 /* leave block descriptor alone */ if (bdlen > 0) { memset(cbuffer1 + MPHEADER10_LEN, 0, 4); /* clear 'number of blocks' for DAD device */ cbuffer1[MPHEADER10_LEN + 4] = 0; /* clear DAD density code. Why? */ /* leave DAD block length */ } #endif cbuffer1[MPHEADER10_LEN + bdlen] &= 0x7f; /* Mask PS bit */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_TO_DEVICE; sci.dxfer_len = resplen; sci.dxferp = cbuffer1; status = do_scsi_io(&sci); if (status) { if (mpi->subpage) fprintf(stdout, ">>> Unable to store %s mode page 0x%x," " subpage 0x%x [msel_10]\n", get_page_name(mpi), mpi->page, mpi->subpage); else fprintf(stdout, ">>> Unable to store %s mode page 0x%x " "[msel_10]\n", get_page_name(mpi), mpi->page); } return status; } static int put_mode_page(struct mpage_info * mpi, const unsigned char * msense_resp) { if (mode6byte) return put_mode_page6(mpi, msense_resp, ! negate_sp_bit); else return put_mode_page10(mpi, msense_resp, ! negate_sp_bit); } static int setup_mode_page(struct mpage_info * mpi, int nparam, unsigned char * buff, unsigned char ** o_pagestart) { int status, offset, rem_pglen; unsigned char * pgp; status = get_mode_page(mpi, 0, buff); if (status) { printf("\n"); return status; } offset = modePageOffset(buff, mpi->resp_len, mode6byte); if (offset < 0) { fprintf(stdout, "mode page=0x%x has bad page format\n", mpi->page); fprintf(stdout, " perhaps '-z' switch may help\n"); return -1; } pgp = buff + offset; *o_pagestart = pgp; rem_pglen = (0x40 & pgp[0]) ? ((pgp[2] << 8) + pgp[3]) : pgp[1]; if (x_interface && replace) { if ((nparam && (n_replacement_values != nparam)) || ((! nparam) && (n_replacement_values != rem_pglen))) { fprintf(stdout, "Wrong number of replacement values (%i instead " "of %i)\n", n_replacement_values, nparam ? nparam : rem_pglen); return 1; } next_parameter = 1; } return 0; } static int get_protocol_id(int port_not_lu, unsigned char * buff, int * proto_idp, int * offp) { int status, off, proto_id, spf; struct mpage_info mp_i; char b[64]; memset(&mp_i, 0, sizeof(mp_i)); mp_i.page = (port_not_lu ? 0x19 : 0x18); /* N.B. getting port or lu specific mode page (not subpage) */ status = get_mode_page(&mp_i, 0, buff); if (status) return status; off = modePageOffset(buff, mp_i.resp_len, mode6byte); if (off < 0) return off; spf = (buff[off] & 0x40) ? 1 : 0; /* subpages won't happen here */ proto_id = buff[off + (spf ? 5 : 2)] & 0xf; if (trace_cmd > 0) printf("Protocol specific %s, protocol_id=%s\n", (port_not_lu ? "port" : "lu"), sg_get_trans_proto_str(proto_id, sizeof(b), b)); if (proto_idp) *proto_idp = proto_id; if (offp) *offp = off; return 0; } static int disk_geometry(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 9, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------------\n"); }; intfield(pagestart + 2, 3, "Number of cylinders"); intfield(pagestart + 5, 1, "Number of heads"); intfield(pagestart + 6, 3, "Starting cyl. write precomp"); intfield(pagestart + 9, 3, "Starting cyl. reduced current"); intfield(pagestart + 12, 2, "Device step rate"); intfield(pagestart + 14, 3, "Landing Zone Cylinder"); bitfield(pagestart + 17, "RPL", 3, 0); intfield(pagestart + 18, 1, "Rotational Offset"); intfield(pagestart + 20, 2, "Rotational Rate"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_disconnect_reconnect(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 11, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("------------------------------------\n"); }; intfield(pagestart + 2, 1, "Buffer full ratio"); intfield(pagestart + 3, 1, "Buffer empty ratio"); intfield(pagestart + 4, 2, "Bus Inactivity Limit (SAS: 100us)"); intfield(pagestart + 6, 2, "Disconnect Time Limit"); intfield(pagestart + 8, 2, "Connect Time Limit (SAS: 100us)"); intfield(pagestart + 10, 2, "Maximum Burst Size"); bitfield(pagestart + 12, "EMDP", 1, 7); bitfield(pagestart + 12, "Fair Arbitration (fcp:faa,fab,fac)", 0x7, 4); bitfield(pagestart + 12, "DIMM", 1, 3); bitfield(pagestart + 12, "DTDC", 0x7, 0); intfield(pagestart + 14, 2, "First Burst Size"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_control(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 21, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------\n"); } bitfield(pagestart + 2, "TST", 0x7, 5); bitfield(pagestart + 2, "TMF_ONLY", 1, 4); bitfield(pagestart + 2, "D_SENSE", 1, 2); bitfield(pagestart + 2, "GLTSD", 1, 1); bitfield(pagestart + 2, "RLEC", 1, 0); bitfield(pagestart + 3, "Queue Algorithm Modifier", 0xf, 4); bitfield(pagestart + 3, "QErr", 0x3, 1); bitfield(pagestart + 3, "DQue [obsolete]", 1, 0); bitfield(pagestart + 4, "TAS", 1, 7); bitfield(pagestart + 4, "RAC", 1, 6); bitfield(pagestart + 4, "UA_INTLCK_CTRL", 0x3, 4); bitfield(pagestart + 4, "SWP", 1, 3); bitfield(pagestart + 4, "RAERP [obs.]", 1, 2); bitfield(pagestart + 4, "UAAERP [obs.]", 1, 1); bitfield(pagestart + 4, "EAERP [obs.]", 1, 0); bitfield(pagestart + 5, "ATO", 1, 7); bitfield(pagestart + 5, "TAS", 1, 6); bitfield(pagestart + 5, "AUTOLOAD MODE", 0x7, 0); intfield(pagestart + 6, 2, "Ready AER Holdoff Period [obs.]"); intfield(pagestart + 8, 2, "Busy Timeout Period"); intfield(pagestart + 10, 2, "Extended self-test completion time"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_control_extension(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 4, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } bitfield(pagestart + 4, "TCMOS", 1, 2); bitfield(pagestart + 4, "SCSIP", 1, 1); bitfield(pagestart + 4, "IALUAE", 1, 0); bitfield(pagestart + 5, "Initial Priority", 0xf, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_informational(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 10, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------------------\n"); } bitfield(pagestart + 2, "PERF", 1, 7); bitfield(pagestart + 2, "EBF", 1, 5); bitfield(pagestart + 2, "EWASC", 1, 4); bitfield(pagestart + 2, "DEXCPT", 1, 3); bitfield(pagestart + 2, "TEST", 1, 2); bitfield(pagestart + 2, "EBACKERR", 1, 1); bitfield(pagestart + 2, "LOGERR", 1, 0); bitfield(pagestart + 3, "MRIE", 0xf, 0); intfield(pagestart + 4, 4, "Interval Timer"); intfield(pagestart + 8, 4, "Report Count"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_error_recovery(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 14, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------------------\n"); } bitfield(pagestart + 2, "AWRE", 1, 7); bitfield(pagestart + 2, "ARRE", 1, 6); bitfield(pagestart + 2, "TB", 1, 5); bitfield(pagestart + 2, "RC", 1, 4); bitfield(pagestart + 2, "EER", 1, 3); bitfield(pagestart + 2, "PER", 1, 2); bitfield(pagestart + 2, "DTE", 1, 1); bitfield(pagestart + 2, "DCR", 1, 0); intfield(pagestart + 3, 1, "Read Retry Count"); intfield(pagestart + 4, 1, "Correction Span"); intfield(pagestart + 5, 1, "Head Offset Count"); intfield(pagestart + 6, 1, "Data Strobe Offset Count"); intfield(pagestart + 8, 1, "Write Retry Count"); intfield(pagestart + 10, 2, "Recovery Time Limit (ms)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_error_recovery(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 10, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("------------------------------------------------\n"); } bitfield(pagestart + 2, "AWRE", 1, 7); bitfield(pagestart + 2, "ARRE", 1, 6); bitfield(pagestart + 2, "TB", 1, 5); bitfield(pagestart + 2, "RC", 1, 4); bitfield(pagestart + 2, "PER", 1, 2); bitfield(pagestart + 2, "DTE", 1, 1); bitfield(pagestart + 2, "DCR", 1, 0); intfield(pagestart + 3, 1, "Read Retry Count"); bitfield(pagestart + 7, "EMCDR", 3, 0); intfield(pagestart + 8, 1, "Write Retry Count"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_mrw(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("------------------------------------------------\n"); } bitfield(pagestart + 3, "LBA space", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_notch_parameters(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 6, cbuffer, &pagestart); if (status) { fprintf(stdout, "Special case: only give 6 fields to '-XR' since" " 'Pages Notched' is unchangeable\n"); return status; } if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------------\n"); }; bitfield(pagestart + 2, "Notched Drive", 1, 7); bitfield(pagestart + 2, "Logical or Physical Notch", 1, 6); intfield(pagestart + 4, 2, "Max # of notches"); intfield(pagestart + 6, 2, "Active Notch"); if (pagestart[2] & 0x40) { intfield(pagestart + 8, 4, "Starting Boundary"); intfield(pagestart + 12, 4, "Ending Boundary"); } else { /* Hex is more meaningful for physical notches */ hexfield(pagestart + 8, 4, "Starting Boundary"); hexfield(pagestart + 12, 4, "Ending Boundary"); } if (x_interface && !replace) { #if 1 ; /* do nothing, skip this field */ #else if (1 == mpi->page_control) /* modifiable */ printf("0"); else printf("0x%8.8x%8.8x", getnbyte(pagestart + 16, 4), getnbyte(pagestart + 20, 4)); #endif }; if (!x_interface) printf("Pages Notched %8.8x %8.8x\n", getnbyte(pagestart + 16, 4), getnbyte(pagestart + 20, 4)); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static const char * formatname(int format) { switch(format) { case 0x0: return "logical block addresses (32 bit)"; case 0x3: return "logical block addresses (64 bit)"; case 0x4: return "bytes from index [Cyl:Head:Off]\n" "Offset -1 marks whole track as bad.\n"; case 0x5: return "physical blocks [Cyl:Head:Sect]\n" "Sector -1 marks whole track as bad.\n"; } return "Weird, unknown format"; } static int read_defect_list(int grown_only) { int i, len, reallen, table, k, defect_format; int status = 0; int header = 1; int sorthead = 0; unsigned char cmd[10]; unsigned char cmd12[12]; unsigned char *df = NULL; unsigned char *bp = NULL; unsigned char *heapp = NULL; unsigned int *headsp = NULL; int trunc; struct scsi_cmnd_io sci; if (defectformat == HEAD_SORT_TOKEN) { defectformat = 0x04; sorthead = 1; headsp = (unsigned int *)malloc(sizeof(unsigned int) * MAX_HEADS); if (headsp == NULL) { perror("malloc failed"); return status; } memset(headsp,0,sizeof(unsigned int) * MAX_HEADS); } for (table = grown_only; table < 2; table++) { if (heapp) { free(heapp); heapp = NULL; } bp = cbuffer; memset(bp, 0, 4); trunc = 0; reallen = -1; cmd[0] = 0x37; /* READ DEFECT DATA (10) */ cmd[1] = 0x00; cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ cmd[3] = 0x00; /* (reserved) */ cmd[4] = 0x00; /* (reserved) */ cmd[5] = 0x00; /* (reserved) */ cmd[6] = 0x00; /* (reserved) */ cmd[7] = 0x00; /* Alloc len */ cmd[8] = 0x04; /* Alloc len (size finder) */ cmd[9] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = 4; sci.dxferp = bp; i = do_scsi_io(&sci); if (i) { fprintf(stdout, ">>> Unable to read %s defect data.\n", (table ? "grown (GLIST)" : "primary (PLIST)")); status |= i; continue; } if (trace_cmd > 1) { printf(" cdb response:\n"); dump(bp, 4); } /* * Check validity of response: * bp[0] reserved, must be zero * bp[1] bits 7-5 reserved, must be zero * bp[1] bits 4-3 should match table requested */ if (0 != bp[0] || (table ? 0x08 : 0x10) != (bp[1] & 0xf8)) { fprintf(stdout, ">>> Invalid header for %s defect list.\n", (table ? "grown (GLIST)" : "primary (PLIST)")); status |= 1; continue; } if (header) { printf("Defect Lists\n" "------------\n"); header = 0; } len = (bp[2] << 8) + bp[3]; if (len < 0xfff8) reallen = len; else { /* * List length is at or over capacity of READ DEFECT DATA (10) * Try to get actual length with READ DEFECT DATA (12) */ bp = cbuffer; memset(bp, 0, 8); cmd12[0] = 0xB7; /* READ DEFECT DATA (12) */ cmd12[1] = (table ? 0x08 : 0x10) | defectformat;/* List, Format */ cmd12[2] = 0x00; /* (reserved) */ cmd12[3] = 0x00; /* (reserved) */ cmd12[4] = 0x00; /* (reserved) */ cmd12[5] = 0x00; /* (reserved) */ cmd12[6] = 0x00; /* Alloc len */ cmd12[7] = 0x00; /* Alloc len */ cmd12[8] = 0x00; /* Alloc len */ cmd12[9] = 0x08; /* Alloc len (size finder) */ cmd12[10] = 0x00; /* reserved */ cmd12[11] = 0x00; /* control */ sci.cmnd = cmd12; sci.cmnd_len = sizeof(cmd12); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = 8; sci.dxferp = bp; i = do_scsi_io(&sci); if (i) { if (trace_cmd) { fprintf(stdout, ">>> No 12 byte command support, " "but list is too long for 10 byte version.\n" "List will be truncated at 8191 elements\n"); } goto trytenbyte; } if (trace_cmd > 1) { printf(" cdb response:\n"); dump(bp, 8); } /* * Check validity of response: * bp[0], bp[2] and bp[3] reserved, must be zero * bp[1] bits 7-5 reserved, must be zero * bp[1] bits 4-3 should match table we requested */ if (0 != bp[0] || 0 != bp[2] || 0 != bp[3] || ((table ? 0x08 : 0x10) != (bp[1] & 0xf8))) { if (trace_cmd) fprintf(stdout, ">>> Invalid header for %s defect list.\n", (table ? "grown (GLIST)" : "primary (PLIST)")); goto trytenbyte; } len = (bp[4] << 24) + (bp[5] << 16) + (bp[6] << 8) + bp[7]; reallen = len; } if (len > 0) { k = len + 8; /* length of defect list + header */ if (k > (int)sizeof(cbuffer)) { heapp = (unsigned char *)malloc(k); if (len > 0x80000 && NULL == heapp) { len = 0x80000; /* go large: 512 KB */ k = len + 8; heapp = (unsigned char *)malloc(k); } if (heapp != NULL) bp = heapp; } if (len > 0xfff0 && heapp != NULL) { cmd12[0] = 0xB7; /* READ DEFECT DATA (12) */ cmd12[1] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ cmd12[2] = 0x00; /* (reserved) */ cmd12[3] = 0x00; /* (reserved) */ cmd12[4] = 0x00; /* (reserved) */ cmd12[5] = 0x00; /* (reserved) */ cmd12[6] = 0x00; /* Alloc len */ cmd12[7] = (k >> 16) & 0xff; /* Alloc len */ cmd12[8] = (k >> 8) & 0xff; /* Alloc len */ cmd12[9] = (k & 0xff); /* Alloc len */ cmd12[10] = 0x00; /* reserved */ cmd12[11] = 0x00; /* control */ sci.cmnd = cmd12; sci.cmnd_len = sizeof(cmd12); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = k; sci.dxferp = bp; i = do_scsi_io(&sci); if (i) goto trytenbyte; if (trace_cmd > 1) { printf(" cdb response:\n"); dump(bp, 8); } reallen = (bp[4] << 24) + (bp[5] << 16) + (bp[6] << 8) + bp[7]; if (reallen > len) { trunc = 1; } df = (unsigned char *) (bp + 8); } else { trytenbyte: if (len > 0xfff8) { len = 0xfff8; trunc = 1; } k = len + 4; /* length of defect list + header */ if (k > (int)sizeof(cbuffer) && NULL == heapp) { heapp = (unsigned char *)malloc(k); if (heapp != NULL) bp = heapp; } if (k > (int)sizeof(cbuffer) && NULL == heapp) { bp = cbuffer; k = sizeof(cbuffer); len = k - 4; trunc = 1; } cmd[0] = 0x37; /* READ DEFECT DATA (10) */ cmd[1] = 0x00; cmd[2] = (table ? 0x08 : 0x10) | defectformat; /* List, Format */ cmd[3] = 0x00; /* (reserved) */ cmd[4] = 0x00; /* (reserved) */ cmd[5] = 0x00; /* (reserved) */ cmd[6] = 0x00; /* (reserved) */ cmd[7] = (k >> 8); /* Alloc len */ cmd[8] = (k & 0xff); /* Alloc len */ cmd[9] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = k; sci.dxferp = bp; i = do_scsi_io(&sci); df = (unsigned char *) (bp + 4); } } if (i) { fprintf(stdout, ">>> Unable to read %s defect data.\n", (table ? "grown (GLIST)" : "primary (PLIST)")); status |= i; continue; } else { if (table && !status && !sorthead) printf("\n"); defect_format = (bp[1] & 0x7); if (-1 == reallen) { printf("at least "); reallen = len; } printf("%d entries (%d bytes) in %s table.\n", reallen / ((0 == defect_format) ? 4 : 8), reallen, table ? "grown (GLIST)" : "primary (PLIST)"); if (!sorthead) printf("Format (%x) is: %s\n", defect_format, formatname(defect_format)); i = 0; switch (defect_format) { case 4: /* bytes from index */ while (len > 0) { snprintf((char *)cbuffer1, 40, "%6d:%3u:%8d", getnbyte(df, 3), df[3], getnbyte(df + 4, 4)); if (sorthead == 0) printf("%19s", (char *)cbuffer1); else if (df[3] < MAX_HEADS) headsp[df[3]]++; len -= 8; df += 8; i++; if (i >= 4 && !sorthead) { printf("\n"); i = 0; } else if (!sorthead) printf("|"); } case 5: /* physical sector */ while (len > 0) { snprintf((char *)cbuffer1, 40, "%6d:%2u:%5d", getnbyte(df, 3), df[3], getnbyte(df + 4, 4)); if (sorthead == 0) printf("%15s", (char *)cbuffer1); else if (df[3] < MAX_HEADS) headsp[df[3]]++; len -= 8; df += 8; i++; if (i >= 5 && !sorthead) { printf("\n"); i = 0; } else if (!sorthead) printf("|"); } case 0: /* lba (32 bit) */ while (len > 0) { printf("%10d", getnbyte(df, 4)); len -= 4; df += 4; i++; if (i >= 7) { printf("\n"); i = 0; } else printf("|"); } case 3: /* lba (64 bit) */ while (len > 0) { printf("%15" PRId64 , getnbyte_ll(df, 8)); len -= 8; df += 8; i++; if (i >= 5) { printf("\n"); i = 0; } else printf("|"); } break; default: printf("unknown defect list format: %d\n", defect_format); break; } if (i && !sorthead) printf("\n"); } if (trunc) printf("[truncated]\n"); } if (heapp) { free(heapp); heapp = NULL; } if (sorthead) { printf("Format is: [head:# entries for this head in list]\n\n"); for (i=0; i 0) { printf("%3d: %u\n", i, headsp[i]); } } } printf("\n"); return status; } static int disk_cache(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 21, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------\n"); }; bitfield(pagestart + 2, "Initiator Control", 1, 7); bitfield(pagestart + 2, "ABPF", 1, 6); bitfield(pagestart + 2, "CAP", 1, 5); bitfield(pagestart + 2, "DISC", 1, 4); bitfield(pagestart + 2, "SIZE", 1, 3); bitfield(pagestart + 2, "Write Cache Enabled", 1, 2); bitfield(pagestart + 2, "MF", 1, 1); bitfield(pagestart + 2, "Read Cache Disabled", 1, 0); bitfield(pagestart + 3, "Demand Read Retention Priority", 0xf, 4); bitfield(pagestart + 3, "Demand Write Retention Priority", 0xf, 0); intfield(pagestart + 4, 2, "Disable Pre-fetch Transfer Length"); intfield(pagestart + 6, 2, "Minimum Pre-fetch"); intfield(pagestart + 8, 2, "Maximum Pre-fetch"); intfield(pagestart + 10, 2, "Maximum Pre-fetch Ceiling"); bitfield(pagestart + 12, "FSW", 1, 7); bitfield(pagestart + 12, "LBCSS", 1, 6); bitfield(pagestart + 12, "DRA", 1, 5); bitfield(pagestart + 12, "NV_DIS", 1, 0); intfield(pagestart + 13, 1, "Number of Cache Segments"); intfield(pagestart + 14, 2, "Cache Segment size"); intfield(pagestart + 17, 3, "Non-Cache Segment size"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_format(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 13, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------\n"); }; intfield(pagestart + 2, 2, "Tracks per Zone"); intfield(pagestart + 4, 2, "Alternate sectors per zone"); intfield(pagestart + 6, 2, "Alternate tracks per zone"); intfield(pagestart + 8, 2, "Alternate tracks per lu"); intfield(pagestart + 10, 2, "Sectors per track"); intfield(pagestart + 12, 2, "Data bytes per physical sector"); intfield(pagestart + 14, 2, "Interleave"); intfield(pagestart + 16, 2, "Track skew factor"); intfield(pagestart + 18, 2, "Cylinder skew factor"); bitfield(pagestart + 20, "Supports Soft Sectoring", 1, 7); bitfield(pagestart + 20, "Supports Hard Sectoring", 1, 6); bitfield(pagestart + 20, "Removable Medium", 1, 5); bitfield(pagestart + 20, "Surface", 1, 4); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_verify_error_recovery(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 7, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-------------------------------------\n"); } bitfield(pagestart + 2, "EER", 1, 3); bitfield(pagestart + 2, "PER", 1, 2); bitfield(pagestart + 2, "DTE", 1, 1); bitfield(pagestart + 2, "DCR", 1, 0); intfield(pagestart + 3, 1, "Verify Retry Count"); intfield(pagestart + 4, 1, "Verify Correction Span (bits)"); intfield(pagestart + 10, 2, "Verify Recovery Time Limit (ms)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } #if 0 static int peripheral_device_page(struct mpage_info * mpi, const char * prefix) { static char *idents[] = { "X3.131: Small Computer System Interface", "X3.91M-1987: Storage Module Interface", "X3.170: Enhanced Small Device Interface", "X3.130-1986; X3T9.3/87-002: IPI-2", "X3.132-1987; X3.147-1988: IPI-3" }; int status; unsigned ident; unsigned char *pagestart; char *name; status = setup_mode_page(mpi, 2, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("---------------------------------\n"); }; #if 0 dump(pagestart, 20); pagestart[1] += 2; /*TEST */ cbuffer[8] += 2; /*TEST */ #endif ident = getnbyte(pagestart + 2, 2); if (ident < (sizeof(idents) / sizeof(char *))) name = idents[ident]; else if (ident < 0x8000) name = "Reserved"; else name = "Vendor Specific"; #ifdef DPG_CHECK_THIS_OUT bdlen = pagestart[1] - 6; if (bdlen < 0) bdlen = 0; else { status = setup_mode_page(mpi, 2, cbuffer, &bdlen, &pagestart); if (status) return status; } hexfield(pagestart + 2, 2, "Interface Identifier"); if (!x_interface) { for (ident = 0; ident < 35; ident++) putchar(' '); puts(name); } hexdatafield(pagestart + 8, bdlen, "Vendor Specific Data"); #endif if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); if (x_interface) puts(name); return 0; } #endif static int common_power_condition(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 4, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("--------------------------------\n"); } bitfield(pagestart + 3, "Idle", 1, 1); bitfield(pagestart + 3, "Standby", 1, 0); intfield(pagestart + 4, 4, "Idle Condition counter (100ms)"); intfield(pagestart + 8, 4, "Standby Condition counter (100ms)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_xor_control(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 5, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("--------------------------------\n"); } bitfield(pagestart + 2, "XORDS", 1, 1); intfield(pagestart + 4, 4, "Maximum XOR write size"); intfield(pagestart + 12, 4, "Maximum regenerate size"); intfield(pagestart + 16, 4, "Maximum rebuild transfer size"); intfield(pagestart + 22, 2, "Rebuild delay"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int disk_background(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 4, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } bitfield(pagestart + 4, "Enable background medium scan", 1, 0); bitfield(pagestart + 5, "Enable pre-scan", 1, 0); intfield(pagestart + 6, 2, "BMS interval time (hour)"); intfield(pagestart + 8, 2, "Pre-scan timeout value (hour)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int optical_memory(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("--------------------------------\n"); } bitfield(pagestart + 2, "RUBR", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_write_param(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 20, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("--------------------------------\n"); } bitfield(pagestart + 2, "BUFE", 1, 6); bitfield(pagestart + 2, "LS_V", 1, 5); bitfield(pagestart + 2, "Test Write", 1, 4); bitfield(pagestart + 2, "Write Type", 0xf, 0); bitfield(pagestart + 3, "MultiSession", 3, 6); bitfield(pagestart + 3, "FP", 1, 5); bitfield(pagestart + 3, "Copy", 1, 4); bitfield(pagestart + 3, "Track Mode", 0xf, 0); bitfield(pagestart + 4, "Data Block type", 0xf, 0); intfield(pagestart + 5, 1, "Link size"); bitfield(pagestart + 7, "Initiator app. code", 0x3f, 0); intfield(pagestart + 8, 1, "Session Format"); intfield(pagestart + 10, 4, "Packet size"); intfield(pagestart + 14, 2, "Audio Pause Length"); hexdatafield(pagestart + 16, 16, "Media Catalog number"); hexdatafield(pagestart + 32, 16, "Int. standard recording code"); hexdatafield(pagestart + 48, 1, "Subheader byte 1"); hexdatafield(pagestart + 49, 1, "Subheader byte 2"); hexdatafield(pagestart + 50, 1, "Subheader byte 3"); hexdatafield(pagestart + 51, 1, "Subheader byte 4"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_audio_control(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 10, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("--------------------------------\n"); } bitfield(pagestart + 2, "IMMED", 1, 2); bitfield(pagestart + 2, "SOTC", 1, 1); bitfield(pagestart + 8, "CDDA out port 0, channel select", 0xf, 0); intfield(pagestart + 9, 1, "Channel port 0 volume"); bitfield(pagestart + 10, "CDDA out port 1, channel select", 0xf, 0); intfield(pagestart + 11, 1, "Channel port 1 volume"); bitfield(pagestart + 12, "CDDA out port 2, channel select", 0xf, 0); intfield(pagestart + 13, 1, "Channel port 2 volume"); bitfield(pagestart + 14, "CDDA out port 3, channel select", 0xf, 0); intfield(pagestart + 15, 1, "Channel port 3 volume"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_timeout(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 6, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------------------\n"); } bitfield(pagestart + 4, "G3Enable", 1, 3); bitfield(pagestart + 4, "TMOE", 1, 2); bitfield(pagestart + 4, "DISP", 1, 1); bitfield(pagestart + 4, "SWPP", 1, 0); intfield(pagestart + 6, 2, "Group 1 minimum time-out"); intfield(pagestart + 8, 2, "Group 2 minimum time-out"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_device_param(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 3, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("------------------------------------\n"); } bitfield(pagestart + 3, "Inactivity timer multiplier", 0xf, 0); intfield(pagestart + 4, 2, "MSF-S units per MSF_M unit"); intfield(pagestart + 6, 2, "MSF-F units per MSF_S unit"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } /* This is not a standard t10.org MMC mode page (it is now "protocol specific lu" mode page). This definition was found in Hitachi GF-2050/GF-2055 DVD-RAM drive SCSI reference manual. */ static int cdvd_feature(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 12, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------\n"); } intfield(pagestart + 2, 2, "DVD feature set"); intfield(pagestart + 4, 2, "CD audio"); intfield(pagestart + 6, 2, "Embedded changer"); intfield(pagestart + 8, 2, "Packet SMART"); intfield(pagestart + 10, 2, "Persistent prevent(MESN)"); intfield(pagestart + 12, 2, "Event status notification"); intfield(pagestart + 14, 2, "Digital output"); intfield(pagestart + 16, 2, "CD sequential recordable"); intfield(pagestart + 18, 2, "DVD sequential recordable"); intfield(pagestart + 20, 2, "Random recordable"); intfield(pagestart + 22, 2, "Key management"); intfield(pagestart + 24, 2, "Partial recorded CD media read"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_mm_capab(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 49, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 2, "DVD-RAM read", 1, 5); bitfield(pagestart + 2, "DVD-R read", 1, 4); bitfield(pagestart + 2, "DVD-ROM read", 1, 3); bitfield(pagestart + 2, "Method 2", 1, 2); bitfield(pagestart + 2, "CD-RW read", 1, 1); bitfield(pagestart + 2, "CD-R read", 1, 0); bitfield(pagestart + 3, "DVD-RAM write", 1, 5); bitfield(pagestart + 3, "DVD-R write", 1, 4); bitfield(pagestart + 3, "DVD-ROM write", 1, 3); bitfield(pagestart + 3, "Test Write", 1, 2); bitfield(pagestart + 3, "CD-RW write", 1, 1); bitfield(pagestart + 3, "CD-R write", 1, 0); bitfield(pagestart + 4, "BUF", 1, 7); bitfield(pagestart + 4, "MultiSession", 1, 6); bitfield(pagestart + 4, "Mode 2 Form 2", 1, 5); bitfield(pagestart + 4, "Mode 2 Form 1", 1, 4); bitfield(pagestart + 4, "Digital port (2)", 1, 3); bitfield(pagestart + 4, "Digital port (1)", 1, 2); bitfield(pagestart + 4, "Composite", 1, 1); bitfield(pagestart + 4, "Audio play", 1, 0); bitfield(pagestart + 5, "Read bar code", 1, 7); bitfield(pagestart + 5, "UPC", 1, 6); bitfield(pagestart + 5, "ISRC", 1, 5); bitfield(pagestart + 5, "C2 pointers supported", 1, 4); bitfield(pagestart + 5, "R-W de-interleaved & corrected", 1, 3); bitfield(pagestart + 5, "R-W supported", 1, 2); bitfield(pagestart + 5, "CD-DA stream is accurate", 1, 1); bitfield(pagestart + 5, "CD-DA commands supported", 1, 0); bitfield(pagestart + 6, "Loading mechanism type", 7, 5); bitfield(pagestart + 6, "Eject (individual or magazine)", 1, 3); bitfield(pagestart + 6, "Prevent jumper", 1, 2); bitfield(pagestart + 6, "Lock state", 1, 1); bitfield(pagestart + 6, "Lock", 1, 0); bitfield(pagestart + 7, "R-W in lead-in", 1, 5); bitfield(pagestart + 7, "Side change capable", 1, 4); bitfield(pagestart + 7, "S/W slot selection", 1, 3); bitfield(pagestart + 7, "Changer supports disc present", 1, 2); bitfield(pagestart + 7, "Separate channel mute", 1, 1); bitfield(pagestart + 7, "Separate volume levels", 1, 0); intfield(pagestart + 10, 2, "number of volume level supported"); intfield(pagestart + 12, 2, "Buffer size supported"); bitfield(pagestart + 17, "Length", 3, 4); bitfield(pagestart + 17, "LSBF", 1, 3); bitfield(pagestart + 17, "RCK", 1, 2); bitfield(pagestart + 17, "BCKF", 1, 1); intfield(pagestart + 22, 2, "Copy management revision supported"); bitfield(pagestart + 27, "Rotation control selected", 3, 0); intfield(pagestart + 28, 2, "Current write speed selected"); intfield(pagestart + 30, 2, "# of lu speed performance tables"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int cdvd_cache(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 2, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("-----------------------\n"); }; bitfield(pagestart + 2, "Write Cache Enabled", 1, 2); bitfield(pagestart + 2, "Read Cache Disabled", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int tape_data_compression(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 6, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 2, "DCE", 1, 7); bitfield(pagestart + 2, "DCC", 1, 6); bitfield(pagestart + 3, "DDE", 1, 7); bitfield(pagestart + 3, "RED", 3, 5); intfield(pagestart + 4, 4, "Compression algorithm"); intfield(pagestart + 8, 4, "Decompression algorithm"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int tape_dev_config(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 25, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 2, "CAF", 1, 5); bitfield(pagestart + 2, "Active format", 0x1f, 0); intfield(pagestart + 3, 1, "Active partition"); intfield(pagestart + 4, 1, "Write object cbuffer full ratio"); intfield(pagestart + 5, 1, "Read object cbuffer full ratio"); intfield(pagestart + 6, 2, "Wire delay time"); bitfield(pagestart + 8, "OBR", 1, 7); bitfield(pagestart + 8, "LOIS", 1, 6); bitfield(pagestart + 8, "RSMK", 1, 5); bitfield(pagestart + 8, "AVC", 1, 4); bitfield(pagestart + 8, "SOCF", 3, 2); bitfield(pagestart + 8, "ROBO", 1, 1); bitfield(pagestart + 8, "REW", 1, 0); intfield(pagestart + 9, 1, "Gap size"); bitfield(pagestart + 10, "EOD defined", 7, 5); bitfield(pagestart + 10, "EEG", 1, 4); bitfield(pagestart + 10, "SEW", 1, 3); bitfield(pagestart + 10, "SWP", 1, 2); bitfield(pagestart + 10, "BAML", 1, 1); bitfield(pagestart + 10, "BAM", 1, 0); intfield(pagestart + 11, 3, "Object cbuffer size at early warning"); intfield(pagestart + 14, 1, "Select data compression algorithm"); bitfield(pagestart + 15, "ASOCWP", 1, 2); bitfield(pagestart + 15, "PERSWO", 1, 1); bitfield(pagestart + 15, "PRMWP", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int tape_medium_part1(struct mpage_info * mpi, const char * prefix) { int status, off, len; unsigned char *pagestart; /* variable length mode page, need to know its response length */ status = get_mode_page(mpi, 0, cbuffer); if (status) return status; off = modePageOffset(cbuffer, mpi->resp_len, mode6byte); if (off < 0) return off; len = mpi->resp_len - off; status = setup_mode_page(mpi, 12 + ((len - 10) / 2), cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } intfield(pagestart + 2, 1, "Maximum additional partitions"); intfield(pagestart + 3, 1, "Additional partitions defined"); bitfield(pagestart + 4, "FDP", 1, 7); bitfield(pagestart + 4, "SDP", 1, 6); bitfield(pagestart + 4, "IDP", 1, 5); bitfield(pagestart + 4, "PSUM", 3, 3); bitfield(pagestart + 4, "POFM", 1, 2); bitfield(pagestart + 4, "CLEAR", 1, 1); bitfield(pagestart + 4, "ADDP", 1, 0); intfield(pagestart + 5, 1, "Medium format recognition"); bitfield(pagestart + 6, "Partition units", 0xf, 0); intfield(pagestart + 8, 2, "Partition size"); for (off = 10; off < len; off += 2) intfield(pagestart + off, 2, "Partition size"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int tape_medium_part2_4(struct mpage_info * mpi, const char * prefix) { int status, off, len; unsigned char *pagestart; /* variable length mode page, need to know its response length */ status = get_mode_page(mpi, 0, cbuffer); if (status) return status; off = modePageOffset(cbuffer, mpi->resp_len, mode6byte); if (off < 0) return off; len = mpi->resp_len - off; status = setup_mode_page(mpi, 1 + ((len - 4) / 2), cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } intfield(pagestart + 2, 2, "Partition size"); for (off = 4; off < len; off += 2) intfield(pagestart + off, 2, "Partition size"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int ses_services_manag(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 2, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", get_page_name(mpi), mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 5, "ENBLTC", 1, 0); intfield(pagestart + 6, 2, "Maximum time to completion (100 ms units)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int fcp_proto_spec_lu(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", "Fibre Channel logical unit", mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 3, "EPDC", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int sas_proto_spec_lu(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", "SAS logical unit", mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 2, "Transport Layer Retries", 1, 4); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_proto_spec_lu(struct mpage_info * mpi, const char * prefix) { int status, proto_id; status = get_protocol_id(0, cbuffer, &proto_id, NULL); if (status) return status; if (0 == proto_id) return fcp_proto_spec_lu(mpi, prefix); else if (6 == proto_id) return sas_proto_spec_lu(mpi, prefix); else return DECODE_FAILED_TRY_HEX; } static int fcp_proto_spec_port(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 10, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", "Fibre Channel port control", mpi->page); printf("----------------------------------------------------\n"); } bitfield(pagestart + 3, "DTFD", 1, 7); bitfield(pagestart + 3, "PLPB", 1, 6); bitfield(pagestart + 3, "DDIS", 1, 5); bitfield(pagestart + 3, "DLM", 1, 4); bitfield(pagestart + 3, "RHA", 1, 3); bitfield(pagestart + 3, "ALWI", 1, 2); bitfield(pagestart + 3, "DTIPE", 1, 1); bitfield(pagestart + 3, "DTOLI", 1, 0); bitfield(pagestart + 6, "RR_TOV units", 7, 0); intfield(pagestart + 7, 1, "Resource recovery time-out"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int spi4_proto_spec_port(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", "SPI-4 port control", mpi->page); printf("-----------------------------------\n"); } intfield(pagestart + 4, 2, "Synchronous transfer time-out"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } /* Protocol specific mode page for SAS, short format (subpage 0) */ static int sas_proto_spec_port(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 3, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode page (0x%x)\n", "SAS SSP port control", mpi->page); printf("-------------------------------------\n"); } bitfield(pagestart + 2, "Ready LED meaning", 0x1, 4); intfield(pagestart + 4, 2, "I_T Nexus Loss time"); intfield(pagestart + 6, 2, "Initiator response time-out"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_proto_spec_port(struct mpage_info * mpi, const char * prefix) { int status, proto_id; status = get_protocol_id(1, cbuffer, &proto_id, NULL); if (status) return status; if (0 == proto_id) return fcp_proto_spec_port(mpi, prefix); else if (1 == proto_id) return spi4_proto_spec_port(mpi, prefix); else if (6 == proto_id) return sas_proto_spec_port(mpi, prefix); else return DECODE_FAILED_TRY_HEX; } static int spi4_margin_control(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 5, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", "SPI-4 Margin control", mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } bitfield(pagestart + 5, "Protocol identifier", 0xf, 0); bitfield(pagestart + 7, "Driver Strength", 0xf, 4); bitfield(pagestart + 8, "Driver Asymmetry", 0xf, 4); bitfield(pagestart + 8, "Driver Precompensation", 0xf, 0); bitfield(pagestart + 9, "Driver Slew rate", 0xf, 4); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } /* Protocol specific mode page for SAS, phy control + discover (subpage 1) */ static int sas_phy_control_discover(struct mpage_info * mpi, const char * prefix) { int status, off, num_phys, k; unsigned char *pagestart; unsigned char *p; /* variable length mode page, need to know its response length */ status = get_mode_page(mpi, 0, cbuffer); if (status) return status; off = modePageOffset(cbuffer, mpi->resp_len, mode6byte); if (off < 0) return off; num_phys = cbuffer[off + 7]; status = setup_mode_page(mpi, 1 + (16 * num_phys), cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", "SAS Phy Control and " "Discover", mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } intfield(pagestart + 7, 1, "Number of phys"); for (k = 0, p = pagestart + 8; k < num_phys; ++k, p += 48) { intfield(p + 1, 1, "Phy Identifier"); bitfield(p + 4, "Attached Device type", 0x7, 4); bitfield(p + 5, "Negotiated Logical Link rate", 0xf, 0); bitfield(p + 6, "Attached SSP Initiator port", 0x1, 3); bitfield(p + 6, "Attached STP Initiator port", 0x1, 2); bitfield(p + 6, "Attached SMP Initiator port", 0x1, 1); bitfield(p + 7, "Attached SSP Target port", 0x1, 3); bitfield(p + 7, "Attached STP Target port", 0x1, 2); bitfield(p + 7, "Attached SMP Target port", 0x1, 1); hexdatafield(p + 8, 8, "SAS address"); hexdatafield(p + 16, 8, "Attached SAS address"); intfield(p + 24, 1, "Attached Phy identifier"); bitfield(p + 32, "Programmed Min Physical Link rate", 0xf, 4); bitfield(p + 32, "Hardware Min Physical Link rate", 0xf, 0); bitfield(p + 33, "Programmed Max Physical Link rate", 0xf, 4); bitfield(p + 33, "Hardware Max Physical Link rate", 0xf, 0); } if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_proto_spec_port_sp1(struct mpage_info * mpi, const char * prefix) { int status, proto_id; status = get_protocol_id(1, cbuffer, &proto_id, NULL); if (status) return status; if (1 == proto_id) return spi4_margin_control(mpi, prefix); else if (6 == proto_id) return sas_phy_control_discover(mpi, prefix); else return DECODE_FAILED_TRY_HEX; } static int spi4_training_config(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 27, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", "training configuration", mpi->page, mpi->subpage); printf("----------------------------------------------------------\n"); } hexdatafield(pagestart + 10, 4, "DB(0) value"); hexdatafield(pagestart + 14, 4, "DB(1) value"); hexdatafield(pagestart + 18, 4, "DB(2) value"); hexdatafield(pagestart + 22, 4, "DB(3) value"); hexdatafield(pagestart + 26, 4, "DB(4) value"); hexdatafield(pagestart + 30, 4, "DB(5) value"); hexdatafield(pagestart + 34, 4, "DB(6) value"); hexdatafield(pagestart + 38, 4, "DB(7) value"); hexdatafield(pagestart + 42, 4, "DB(8) value"); hexdatafield(pagestart + 46, 4, "DB(9) value"); hexdatafield(pagestart + 50, 4, "DB(10) value"); hexdatafield(pagestart + 54, 4, "DB(11) value"); hexdatafield(pagestart + 58, 4, "DB(12) value"); hexdatafield(pagestart + 62, 4, "DB(13) value"); hexdatafield(pagestart + 66, 4, "DB(14) value"); hexdatafield(pagestart + 70, 4, "DB(15) value"); hexdatafield(pagestart + 74, 4, "P_CRCA value"); hexdatafield(pagestart + 78, 4, "P1 value"); hexdatafield(pagestart + 82, 4, "BSY value"); hexdatafield(pagestart + 86, 4, "SEL value"); hexdatafield(pagestart + 90, 4, "RST value"); hexdatafield(pagestart + 94, 4, "REQ value"); hexdatafield(pagestart + 98, 4, "ACK value"); hexdatafield(pagestart + 102, 4, "ATN value"); hexdatafield(pagestart + 106, 4, "C/D value"); hexdatafield(pagestart + 110, 4, "I/O value"); hexdatafield(pagestart + 114, 4, "MSG value"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } /* SAS(2) SSP, shared protocol specific port mode subpage (subpage 2) */ static int sas_shared_spec_port(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 1, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", "SAS SSP shared protocol " "specific port", mpi->page, mpi->subpage); printf("-----------------------------------------------------\n"); } intfield(pagestart + 6, 2, "Power loss timeout(ms)"); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int common_proto_spec_port_sp2(struct mpage_info * mpi, const char * prefix) { int status, proto_id; status = get_protocol_id(1, cbuffer, &proto_id, NULL); if (status) return status; if (1 == proto_id) return spi4_training_config(mpi, prefix); else if (6 == proto_id) return sas_shared_spec_port(mpi, prefix); else return DECODE_FAILED_TRY_HEX; } static int spi4_negotiated(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 7, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } intfield(pagestart + 6, 1, "Transfer period"); intfield(pagestart + 8, 1, "REQ/ACK offset"); intfield(pagestart + 9, 1, "Transfer width exponent"); bitfield(pagestart + 10, "Protocol option bits", 0x7f, 0); bitfield(pagestart + 11, "Transceiver mode", 3, 2); bitfield(pagestart + 11, "Sent PCOMP_EN", 1, 1); bitfield(pagestart + 11, "Received PCOMP_EN", 1, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static int spi4_report_xfer(struct mpage_info * mpi, const char * prefix) { int status; unsigned char *pagestart; status = setup_mode_page(mpi, 4, cbuffer, &pagestart); if (status) return status; if (prefix[0]) printf("%s", prefix); if (!x_interface && !replace) { printf("%s mode subpage (0x%x,0x%x)\n", get_page_name(mpi), mpi->page, mpi->subpage); printf("--------------------------------------------\n"); } intfield(pagestart + 6, 1, "Mimimum transfer period factor"); intfield(pagestart + 8, 1, "Maximum REQ/ACK offset"); intfield(pagestart + 9, 1, "Maximum transfer width exponent"); bitfield(pagestart + 10, "Protocol option bits supported", 0xff, 0); if (x_interface && replace) return put_mode_page(mpi, cbuffer); else printf("\n"); return 0; } static void print_hex_page(struct mpage_info * mpi, const char * prefix, unsigned char *pagestart, int off, int len) { int k; const char * pg_name; if (prefix[0]) printf("%s", prefix); if (! x_interface) { pg_name = get_page_name(mpi); if (mpi->subpage) { if (pg_name && (unkn_page_str != pg_name)) printf("mode page: 0x%02x subpage: 0x%02x [%s]\n", mpi->page, mpi->subpage, pg_name); else printf("mode page: 0x%02x subpage: 0x%02x\n", mpi->page, mpi->subpage); printf("------------------------------\n"); } else { if (pg_name && (unkn_page_str != pg_name)) printf("mode page: 0x%02x [%s]\n", mpi->page, pg_name); else printf("mode page: 0x%02x\n", mpi->page); printf("---------------\n"); } } for (k = off; k < len; k++) { char nm[8]; snprintf(nm, sizeof(nm), "0x%02x", k); hexdatafield(pagestart + k, 1, nm); } printf("\n"); } static int do_user_page(struct mpage_info * mpi, int decode_in_hex) { int status = 0; int len, off, res, done; int offset = 0; unsigned char *pagestart; char prefix[96]; struct mpage_info local_mp_i; struct mpage_name_func * mpf; int multiple = ((MP_LIST_PAGES == mpi->page) || (MP_LIST_SUBPAGES == mpi->subpage)); if (replace && multiple) { printf("Can't list all (sub)pages and use replace (-R) together\n"); return 1; } status = get_mode_page(mpi, 0, cbuffer2); if (status) { printf("\n"); return status; } else { offset = modePageOffset(cbuffer2, mpi->resp_len, mode6byte); if (offset < 0) { fprintf(stdout, "mode page=0x%x has bad page format\n", mpi->page); fprintf(stdout, " perhaps '-z' switch may help\n"); return -1; } pagestart = cbuffer2 + offset; } memset(&local_mp_i, 0, sizeof(local_mp_i)); local_mp_i.page_control = mpi->page_control; local_mp_i.peri_type = mpi->peri_type; local_mp_i.inq_byte6 = mpi->inq_byte6; local_mp_i.resp_len = mpi->resp_len; do { local_mp_i.page = (pagestart[0] & 0x3f); local_mp_i.subpage = (pagestart[0] & 0x40) ? pagestart[1] : 0; if(0 == local_mp_i.page) { /* page==0 vendor (unknown) format */ off = 0; len = mpi->resp_len - offset; /* should be last listed page */ } else if (local_mp_i.subpage) { off = 4; len = (pagestart[2] << 8) + pagestart[3] + 4; } else { off = 2; len = pagestart[1] + 2; } prefix[0] = '\0'; done = 0; if ((! decode_in_hex) && ((mpf = get_mpage_name_func(&local_mp_i))) && mpf->func) { if (multiple && x_interface && !replace) { if (local_mp_i.subpage) snprintf(prefix, sizeof(prefix), "sginfo -t 0x%x,0x%x" " -XR %s ", local_mp_i.page, local_mp_i.subpage, device_name); else snprintf(prefix, sizeof(prefix), "sginfo -t 0x%x -XR %s ", local_mp_i.page, device_name); } res = mpf->func(&local_mp_i, prefix); if (DECODE_FAILED_TRY_HEX != res) { done = 1; status |= res; } } if (! done) { if (x_interface && replace) return put_mode_page(&local_mp_i, cbuffer2); else { if (multiple && x_interface && !replace) { if (local_mp_i.subpage) snprintf(prefix, sizeof(prefix), "sginfo -u 0x%x,0x%x" " -XR %s ", local_mp_i.page, local_mp_i.subpage, device_name); else snprintf(prefix, sizeof(prefix), "sginfo -u 0x%x -XR " "%s ", local_mp_i.page, device_name); } print_hex_page(&local_mp_i, prefix, pagestart, off, len); } } offset += len; pagestart = cbuffer2 + offset; } while (multiple && (offset < mpi->resp_len)); return status; } static void inqfieldname(unsigned char *deststr, const unsigned char *srcbuf, int maxlen) { int i; memset(deststr, '\0', MAX_INQFIELD_LEN); for (i = maxlen - 1; i >= 0 && isspace(srcbuf[i]); --i) ; memcpy(deststr, srcbuf, i + 1); } static int do_inquiry(int * peri_type, int * resp_byte6, int inquiry_verbosity) { int status; unsigned char cmd[6]; unsigned char fieldname[MAX_INQFIELD_LEN]; unsigned char *pagestart; struct scsi_cmnd_io sci; memset(cbuffer, 0, INQUIRY_RESP_INITIAL_LEN); cbuffer[0] = 0x7f; cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0x00; /* evpd=0 */ cmd[2] = 0x00; /* page code = 0 */ cmd[3] = 0x00; /* (reserved) */ cmd[4] = INQUIRY_RESP_INITIAL_LEN; /* allocation length */ cmd[5] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = INQUIRY_RESP_INITIAL_LEN; sci.dxferp = cbuffer; status = do_scsi_io(&sci); if (status) { printf("Error doing INQUIRY (1)\n"); return status; } if (trace_cmd > 1) { printf(" inquiry response:\n"); dump(cbuffer, INQUIRY_RESP_INITIAL_LEN); } pagestart = cbuffer; if (peri_type) *peri_type = pagestart[0] & 0x1f; if (resp_byte6) *resp_byte6 = pagestart[6]; if (0 == inquiry_verbosity) return 0; if ((pagestart[4] + 5) < INQUIRY_RESP_INITIAL_LEN) { printf("INQUIRY response too short: expected 36 bytes, got %d\n", pagestart[4] + 5); return -EINVAL; } if (!x_interface && !replace) { printf("INQUIRY response (cmd: 0x12)\n"); printf("----------------------------\n"); }; bitfield(pagestart + 0, "Device Type", 0x1f, 0); if (2 == inquiry_verbosity) { bitfield(pagestart + 0, "Peripheral Qualifier", 0x7, 5); bitfield(pagestart + 1, "Removable", 1, 7); bitfield(pagestart + 2, "Version", 0xff, 0); bitfield(pagestart + 3, "NormACA", 1, 5); bitfield(pagestart + 3, "HiSup", 1, 4); bitfield(pagestart + 3, "Response Data Format", 0xf, 0); bitfield(pagestart + 5, "SCCS", 1, 7); bitfield(pagestart + 5, "ACC", 1, 6); bitfield(pagestart + 5, "ALUA", 3, 4); bitfield(pagestart + 5, "3PC", 1, 3); bitfield(pagestart + 5, "Protect", 1, 0); bitfield(pagestart + 6, "BQue", 1, 7); bitfield(pagestart + 6, "EncServ", 1, 6); bitfield(pagestart + 6, "MultiP", 1, 4); bitfield(pagestart + 6, "MChngr", 1, 3); bitfield(pagestart + 6, "Addr16", 1, 0); bitfield(pagestart + 7, "Relative Address", 1, 7); bitfield(pagestart + 7, "Wide bus 16", 1, 5); bitfield(pagestart + 7, "Synchronous neg.", 1, 4); bitfield(pagestart + 7, "Linked Commands", 1, 3); bitfield(pagestart + 7, "Command Queueing", 1, 1); } if (x_interface) printf("\n"); inqfieldname(fieldname, pagestart + 8, 8); printf("%s%s\n", (!x_interface ? "Vendor: " : ""), fieldname); inqfieldname(fieldname, pagestart + 16, 16); printf("%s%s\n", (!x_interface ? "Product: " : ""), fieldname); inqfieldname(fieldname, pagestart + 32, 4); printf("%s%s\n", (!x_interface ? "Revision level: " : ""), fieldname); printf("\n"); return status; } static int do_serial_number(void) { int status, pagelen; unsigned char cmd[6]; unsigned char *pagestart; struct scsi_cmnd_io sci; const unsigned char serial_vpd = 0x80; const unsigned char supported_vpd = 0x0; /* check supported VPD pages + unit serial number well formed */ cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0x01; /* evpd=1 */ cmd[2] = supported_vpd; cmd[3] = 0x00; /* (reserved) */ cmd[4] = 0x04; /* allocation length */ cmd[5] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = 4; sci.dxferp = cbuffer; status = do_scsi_io(&sci); if (status) { printf("No serial number (error doing INQUIRY, supported VPDs)\n\n"); return status; } if (! ((supported_vpd == cbuffer[1]) && (0 == cbuffer[2]))) { printf("No serial number (bad format for supported VPDs)\n\n"); return -1; } cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0x01; /* evpd=1 */ cmd[2] = serial_vpd; cmd[3] = 0x00; /* (reserved) */ cmd[4] = 0x04; /* allocation length */ cmd[5] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = 4; sci.dxferp = cbuffer; status = do_scsi_io(&sci); if (status) { printf("No serial number (error doing INQUIRY, serial number)\n\n"); return status; } if (! ((serial_vpd == cbuffer[1]) && (0 == cbuffer[2]))) { printf("No serial number (bad format for serial number)\n\n"); return -1; } pagestart = cbuffer; pagelen = 4 + pagestart[3]; cmd[0] = 0x12; /* INQUIRY */ cmd[1] = 0x01; /* evpd=1 */ cmd[2] = serial_vpd; cmd[3] = 0x00; /* (reserved) */ cmd[4] = (unsigned char)pagelen; /* allocation length */ cmd[5] = 0x00; /* control */ sci.cmnd = cmd; sci.cmnd_len = sizeof(cmd); sci.dxfer_dir = DXFER_FROM_DEVICE; sci.dxfer_len = pagelen; sci.dxferp = cbuffer; status = do_scsi_io(&sci); if (status) { printf("No serial number (error doing INQUIRY, serial number)\n\n"); return status; } if (trace_cmd > 1) { printf(" inquiry (vpd page 0x80) response:\n"); dump(cbuffer, pagelen); } pagestart[pagestart[3] + 4] = '\0'; printf("Serial Number '%s'\n\n", pagestart + 4); return status; } typedef struct sg_map { int bus; int channel; int target_id; int lun; char * dev_name; } Sg_map; typedef struct my_scsi_idlun { int mux4; int host_unique_id; } My_scsi_idlun; #define MDEV_NAME_SZ 256 static void make_dev_name(char * fname, int k, int do_numeric) { char buff[MDEV_NAME_SZ]; size_t len; strncpy(fname, "/dev/sg", MDEV_NAME_SZ); fname[MDEV_NAME_SZ - 1] = '\0'; len = strlen(fname); if (do_numeric) snprintf(fname + len, MDEV_NAME_SZ - len, "%d", k); else { if (k <= 26) { buff[0] = 'a' + (char)k; buff[1] = '\0'; strcat(fname, buff); } else strcat(fname, "xxxx"); } } static Sg_map sg_map_arr[MAX_SG_DEVS + 1]; #define MAX_HOLES 4 /* Print out a list of the known devices on the system */ static void show_devices(int raw) { int k, j, fd, err, bus; My_scsi_idlun m_idlun; char name[MDEV_NAME_SZ]; char dev_name[MDEV_NAME_SZ]; char ebuff[EBUFF_SZ]; int do_numeric = 1; int max_holes = MAX_HOLES; DIR *dir_ptr; struct dirent *entry; char *tmpptr; dir_ptr=opendir("/dev"); if ( dir_ptr == NULL ) { perror("/dev"); exit(1); } j=0; while ( (entry=readdir(dir_ptr)) != NULL ) { switch(entry->d_type) { case DT_LNK: case DT_CHR: case DT_BLK: break; default: continue; } switch(entry->d_name[0]) { case 's': case 'n': break; default: continue; } if ( strncmp("sg",entry->d_name,2) == 0 ) { continue; } if ( strncmp("sd",entry->d_name,2) == 0 ) { continue; } if ( isdigit(entry->d_name[strlen(entry->d_name)-1]) ) { continue; } snprintf(dev_name, sizeof(dev_name),"/dev/%s",entry->d_name); fd = open(dev_name, O_RDONLY | O_NONBLOCK); if (fd < 0) continue; err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &(sg_map_arr[j].bus)); if (err < 0) { #if 0 snprintf(ebuff, EBUFF_SZ, "SCSI(1) ioctl on %s failed", dev_name); perror(ebuff); #endif close(fd); continue; } err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); if (err < 0) { snprintf(ebuff, EBUFF_SZ, "SCSI(2) ioctl on %s failed", dev_name); perror(ebuff); close(fd); continue; } sg_map_arr[j].channel = (m_idlun.mux4 >> 16) & 0xff; sg_map_arr[j].lun = (m_idlun.mux4 >> 8) & 0xff; sg_map_arr[j].target_id = m_idlun.mux4 & 0xff; tmpptr=(char *)malloc(strlen(dev_name)+1); strncpy(tmpptr,dev_name,strlen(dev_name)+1); sg_map_arr[j].dev_name = tmpptr; #if 0 printf("[scsi%d ch=%d id=%d lun=%d %s] ", sg_map_arr[j].bus, sg_map_arr[j].channel, sg_map_arr[j].target_id, sg_map_arr[j].lun, sg_map_arr[j].dev_name); #endif printf("%s ", dev_name); close(fd); if (++j >= MAX_SG_DEVS) break; } closedir(dir_ptr); printf("\n"); /* <<<<<<<<<<<<<<<<<<<<< */ for (k = 0; k < MAX_SG_DEVS; k++) { if ( raw ) { sprintf(name,"/dev/raw/raw%d",k); fd = open(name, O_RDWR | O_NONBLOCK); if (fd < 0) { continue; } } else { make_dev_name(name, k, do_numeric); fd = open(name, O_RDWR | O_NONBLOCK); if (fd < 0) { if ((ENOENT == errno) && (0 == k)) { do_numeric = 0; make_dev_name(name, k, do_numeric); fd = open(name, O_RDWR | O_NONBLOCK); } if (fd < 0) { if (EBUSY == errno) continue; /* step over if O_EXCL already on it */ else { #if 0 snprintf(ebuff, EBUFF_SZ, "open on %s failed (%d)", name, errno); perror(ebuff); #endif if (max_holes-- > 0) continue; else break; } } } } max_holes = MAX_HOLES; err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus); if (err < 0) { if ( ! raw ) { snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", name); perror(ebuff); } close(fd); continue; } err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); if (err < 0) { if ( ! raw ) { snprintf(ebuff, EBUFF_SZ, "SCSI(3) ioctl on %s failed", name); perror(ebuff); } close(fd); continue; } #if 0 printf("[scsi%d ch=%d id=%d lun=%d %s]", bus, (m_idlun.mux4 >> 16) & 0xff, m_idlun.mux4 & 0xff, (m_idlun.mux4 >> 8) & 0xff, name); #endif for (j = 0; sg_map_arr[j].dev_name; ++j) { if ((bus == sg_map_arr[j].bus) && ((m_idlun.mux4 & 0xff) == sg_map_arr[j].target_id) && (((m_idlun.mux4 >> 16) & 0xff) == sg_map_arr[j].channel) && (((m_idlun.mux4 >> 8) & 0xff) == sg_map_arr[j].lun)) { printf("%s [=%s scsi%d ch=%d id=%d lun=%d]\n", name, sg_map_arr[j].dev_name, bus, ((m_idlun.mux4 >> 16) & 0xff), m_idlun.mux4 & 0xff, ((m_idlun.mux4 >> 8) & 0xff)); break; } } if (NULL == sg_map_arr[j].dev_name) printf("%s [scsi%d ch=%d id=%d lun=%d]\n", name, bus, ((m_idlun.mux4 >> 16) & 0xff), m_idlun.mux4 & 0xff, ((m_idlun.mux4 >> 8) & 0xff)); close(fd); } printf("\n"); } #define DEVNAME_SZ 256 static int open_sg_io_dev(char * devname) { int fd, fdrw, err, bus, bbus, k, v; My_scsi_idlun m_idlun, mm_idlun; int do_numeric = 1; char name[DEVNAME_SZ]; struct stat a_st; int block_dev = 0; strncpy(name, devname, DEVNAME_SZ); name[DEVNAME_SZ - 1] = '\0'; fd = open(name, O_RDONLY | O_NONBLOCK); if (fd < 0) return fd; if ((ioctl(fd, SG_GET_VERSION_NUM, &v) >= 0) && (v >= 30000)) { fdrw = open(name, O_RDWR | O_NONBLOCK); if (fdrw >= 0) { close(fd); return fdrw; } return fd; } if (fstat(fd, &a_st) < 0) { fprintf(stderr, "could do fstat() on fd ??\n"); close(fd); return -9999; } if (S_ISBLK(a_st.st_mode)) block_dev = 1; if (block_dev || (ioctl(fd, SG_GET_TIMEOUT, 0) < 0)) { err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bus); if (err < 0) { fprintf(stderr, "A device name that understands SCSI commands " "is required\n"); close(fd); return -9999; } err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &m_idlun); if (err < 0) { fprintf(stderr, "A SCSI device name is required(2)\n"); close(fd); return -9999; } close(fd); for (k = 0; k < MAX_SG_DEVS; k++) { make_dev_name(name, k, do_numeric); fd = open(name, O_RDWR | O_NONBLOCK); if (fd < 0) { if ((ENOENT == errno) && (0 == k)) { do_numeric = 0; make_dev_name(name, k, do_numeric); fd = open(name, O_RDWR | O_NONBLOCK); } if (fd < 0) { if (EBUSY == errno) continue; /* step over if O_EXCL already on it */ else break; } } err = ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, &bbus); if (err < 0) { perror("sg ioctl failed"); close(fd); fd = -9999; } err = ioctl(fd, SCSI_IOCTL_GET_IDLUN, &mm_idlun); if (err < 0) { perror("sg ioctl failed"); close(fd); fd = -9999; } if ((bus == bbus) && ((m_idlun.mux4 & 0xff) == (mm_idlun.mux4 & 0xff)) && (((m_idlun.mux4 >> 8) & 0xff) == ((mm_idlun.mux4 >> 8) & 0xff)) && (((m_idlun.mux4 >> 16) & 0xff) == ((mm_idlun.mux4 >> 16) & 0xff))) break; else { close(fd); fd = -9999; } } } if (fd >= 0) { if ((ioctl(fd, SG_GET_VERSION_NUM, &v) < 0) || (v < 30000)) { fprintf(stderr, "requires lk 2.4 (sg driver), lk 2.6 or lk 3 " "series\n"); close(fd); return -9999; } close(fd); return open(name, O_RDWR | O_NONBLOCK); } else return fd; } static void usage(const char *errtext) { if (errtext) fprintf(stderr, "Error: sginfo: %s\n", errtext); fprintf(stderr, "Usage: sginfo [-options] [device] " "[replacement_values]\n"); fputs("\tAllowed options are:\n" "\t-6 Do 6 byte mode sense and select commands (def: 10 " "bytes).\n" "\t-a Display inquiry info, serial # and all mode pages.\n" "\t-A Similar to '-a' but displays all subpages as well.\n" "\t-c Access Caching Page.\n" "\t-C Access Control Mode Page.\n" "\t-d Display defect lists (default format: index).\n" "\t-D Access Disconnect-Reconnect Page.\n" "\t-e Access Read-Write Error Recovery page.\n" "\t-E Access Control Extension page.\n" "\t-f Access Format Device Page.\n" "\t-Farg Format of the defect list:\n" "\t\t-Flogical - logical block addresses (32 bit)\n" "\t\t-Flba64 - logical block addresses (64 bit)\n" "\t\t-Fphysical - physical blocks\n" "\t\t-Findex - defect bytes from index\n" "\t\t-Fhead - sort by head\n", stdout); fputs("\t-g Access Rigid Disk Drive Geometry Page.\n" "\t-G Display 'grown' defect list (default format: index).\n" "\t-i Display information from INQUIRY command.\n" "\t-I Access Informational Exception page.\n" "\t-l List known scsi devices on the system [DEPRECATED]\n" "\t-n Access Notch and Partition Page.\n" "\t-N Negate (stop) storing to saved page (active with -R).\n" "\t-P Access Power Condition Page.\n" "\t-r List known raw scsi devices on the system\n" "\t-s Display serial number (from INQUIRY VPD page).\n" "\t-t Access mode page [subpage ] and decode.\n" "\t-T Trace commands (for debugging, double for more)\n" "\t-u Access mode page [subpage ], output in hex\n" "\t-v Show version number\n" "\t-V Access Verify Error Recovery Page.\n" "\t-z single fetch mode pages (rather than double fetch)\n" "\n", stdout); fputs("\tOnly one of the following three options can be specified.\n" "\tNone of these three implies the current values are returned.\n", stdout); fputs("\t-m Access modifiable fields instead of current values\n" "\t-M Access manufacturer defaults instead of current values\n" "\t-S Access saved defaults instead of current values\n\n" "\t-X Use list (space separated values) rather than table.\n" "\t-R Replace parameters - best used with -X (expert use only)\n" "\t [replacement parameters placed after device on command line]\n\n", stdout); printf("\t sginfo version: %s; See man page for more details.\n", version_str); exit(2); } int main(int argc, char *argv[]) { int k, j, n; unsigned int unum, unum2; int decode_in_hex = 0; char c; char * cp; int status = 0; long tmp; struct mpage_info mp_i; int inquiry_verbosity = 0; int show_devs = 0, show_raw = 0; int found = 0; if (argc < 2) usage(NULL); memset(&mp_i, 0, sizeof(mp_i)); while ((k = getopt(argc, argv, "6aAcCdDeEfgGiIlmMnNPrRsSTvVXzF:t:u:")) != EOF) { c = (char)k; switch (c) { case '6': mode6byte = 1; break; case 'a': inquiry_verbosity = 1; serial_number = 1; mp_i.page = MP_LIST_PAGES; break; case 'A': inquiry_verbosity = 1; serial_number = 1; mp_i.page = MP_LIST_PAGES; mp_i.subpage = MP_LIST_SUBPAGES; break; case 'c': mp_i.page = 0x8; break; case 'C': mp_i.page = 0xa; break; case 'd': defect = 1; break; case 'D': mp_i.page = 0x2; break; case 'e': mp_i.page = 0x1; break; case 'E': mp_i.page = 0xa; mp_i.subpage = 0x1; break; case 'f': mp_i.page = 0x3; break; case 'F': if (!strcasecmp(optarg, "logical")) defectformat = 0x0; else if (!strcasecmp(optarg, "lba64")) defectformat = 0x3; else if (!strcasecmp(optarg, "physical")) defectformat = 0x5; else if (!strcasecmp(optarg, "index")) defectformat = 0x4; else if (!strcasecmp(optarg, "head")) defectformat = HEAD_SORT_TOKEN; else usage("Illegal -F parameter, must be one of logical, " "physical, index or head"); break; case 'g': mp_i.page = 0x4; break; case 'G': grown_defect = 1; break; case 'i': /* just vendor, product and revision for '-i -i' */ inquiry_verbosity = (2 == inquiry_verbosity) ? 1 : 2; break; case 'I': mp_i.page = 0x1c; break; case 'l': show_devs = 1; break; case 'm': /* modifiable page control */ if (0 == mp_i.page_control) mp_i.page_control = 1; else usage("can only have one of 'm', 'M' and 'S'"); break; case 'M': /* manufacturer's==default page control */ if (0 == mp_i.page_control) mp_i.page_control = 2; else usage("can only have one of 'M', 'm' and 'S'"); break; case 'n': mp_i.page = 0xc; break; case 'N': negate_sp_bit = 1; break; case 'P': mp_i.page = 0x1a; break; case 'r': show_raw = 1; break; case 'R': replace = 1; break; case 's': serial_number = 1; break; case 'S': /* saved page control */ if (0 == mp_i.page_control) mp_i.page_control = 3; else usage("can only have one of 'S', 'm' and 'M'"); break; case 'T': trace_cmd++; break; case 't': case 'u': if ('u' == c) decode_in_hex = 1; while (' ' == *optarg) optarg++; if ('0' == *optarg) { unum = 0; unum2 = 0; j = sscanf(optarg, "0x%x,0x%x", &unum, &unum2); mp_i.page = unum; if (1 == j) { cp = strchr(optarg, ','); if (cp && (1 == sscanf(cp, ",%d", &mp_i.subpage))) j = 2; } else mp_i.subpage = unum2; } else j = sscanf(optarg, "%d,%d", &mp_i.page, &mp_i.subpage); if (1 == j) mp_i.subpage = 0; else if (j < 1) usage("argument following '-u' should be of form " "[,]"); if ((mp_i.page < 0) || (mp_i.page > MP_LIST_PAGES) || (mp_i.subpage < 0) || (mp_i.subpage > MP_LIST_SUBPAGES)) usage("mode pages range from 0 .. 63, subpages from " "1 .. 255"); found = 1; break; case 'v': fprintf(stdout, "sginfo version: %s\n", version_str); return 0; case 'V': mp_i.page = 0x7; break; case 'X': x_interface = 1; break; case 'z': single_fetch = 1; break; case '?': usage("Unknown option"); break; default: fprintf(stdout, "Unknown option '-%c' (ascii 0x%02x)\n", c, c); usage("bad option"); } } if (replace && !x_interface) usage("-R requires -X"); if (replace && mp_i.page_control) usage("-R not allowed for -m, -M or -S"); if (x_interface && replace && ((MP_LIST_PAGES == mp_i.page) || (MP_LIST_SUBPAGES == mp_i.subpage))) usage("-XR can be used only with exactly one page."); if (replace && (3 != mp_i.page_control)) { memset (is_hex, 0, 32); for (j = 1; j < argc - optind; j++) { if (strncmp(argv[optind + j], "0x", 2) == 0) { char *pnt = argv[optind + j] + 2; replacement_values[j] = 0; /* This is a kluge, but we can handle 64 bit quantities this way. */ while (*pnt) { if (*pnt >= 'a' && *pnt <= 'f') *pnt -= 32; replacement_values[j] = (replacement_values[j] << 4) | (*pnt > '9' ? (*pnt - 'A' + 10) : (*pnt - '0')); pnt++; } continue; } if (argv[optind + j][0] == '@') { /*Ensure that this string contains an even number of hex-digits */ int len = strlen(argv[optind + j] + 1); if ((len & 1) || (len != (int)strspn(argv[optind + j] + 1, "0123456789ABCDEFabcdef"))) usage("Odd number of chars or non-hex digit in " "@hexdatafield"); replacement_values[j] = (unsigned long) argv[optind + j]; is_hex[j] = 1; continue; } /* Using a tmp here is silly but the most clean approach */ n = sscanf(argv[optind + j], "%ld", &tmp); replacement_values[j] = ((1 == n) ? tmp : 0); } n_replacement_values = argc - optind - 1; } if (show_devs) { show_devices(0); exit(0); } if (show_raw) { show_devices(1); exit(0); } if (optind >= argc) usage("no device name given"); glob_fd = open_sg_io_dev(device_name = argv[optind]); if (glob_fd < 0) { if (-9999 == glob_fd) fprintf(stderr, "Couldn't find sg device corresponding to %s\n", device_name); else { perror("sginfo(open)"); fprintf(stderr, "file=%s, or no corresponding sg device found\n", device_name); fprintf(stderr, "Is sg driver loaded?\n"); } exit(1); } #if 0 if (!x_interface) printf("\n"); #endif if (! (found || mp_i.page || mp_i.subpage || inquiry_verbosity || serial_number)) { if (trace_cmd > 0) fprintf(stdout, "nothing selected so do a short INQUIRY\n"); inquiry_verbosity = 1; } status |= do_inquiry(&mp_i.peri_type, &mp_i.inq_byte6, inquiry_verbosity); if (serial_number) do_serial_number(); /* ignore error */ if (mp_i.page > 0) status |= do_user_page(&mp_i, decode_in_hex); if (defect) status |= read_defect_list(0); if (grown_defect) status |= read_defect_list(1); return status ? 1 : 0; } sg3_utils-1.40/src/Makefile.in0000664000175000017500000023027612430315266015220 0ustar douggdougg# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_decode_sense$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_format$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_get_lba_status$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ident$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_inq$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_logs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_luns$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_modes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_opcodes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_persist$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_prevent$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_raw$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_rdac$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_readcap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_read_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_read_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_reassign$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_referrals$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_rep_zones$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_requests$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_reset_wp$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_rmsn$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_rtpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_safte$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sanitize$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_scan$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_senddiag$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ses$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_ses_microcode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_start$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_stpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_sync$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_turs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_unmap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_vpd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_same$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_write_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_TRUE@ sg_wr_mode$(EXEEXT) @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_decode_sense$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_format$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_get_lba_status$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ident$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_inq$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_logs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_luns$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_modes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_opcodes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_persist$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_prevent$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_raw$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_rdac$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_readcap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_read_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_read_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_reassign$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_referrals$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_rep_zones$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_requests$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_reset_wp$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_rmsn$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_rtpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_safte$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sanitize$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_scan$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_senddiag$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ses$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_ses_microcode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_start$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_stpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_sync$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_turs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_unmap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_vpd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_same$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_write_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_FALSE@@OS_WIN32_CYGWIN_TRUE@ sg_wr_mode$(EXEEXT) @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_decode_sense$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_format$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_get_lba_status$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ident$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_inq$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_logs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_luns$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_modes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_opcodes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_persist$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_prevent$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_raw$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_rdac$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_readcap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_read_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_read_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_reassign$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_referrals$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_rep_zones$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_requests$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_reset_wp$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_rmsn$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_rtpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_safte$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sanitize$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_senddiag$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ses$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_ses_microcode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_start$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_stpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_sync$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_turs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_unmap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_vpd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_same$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_write_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_FALSE@@OS_SOLARIS_TRUE@ sg_wr_mode$(EXEEXT) @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_decode_sense$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_format$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_get_lba_status$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ident$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_inq$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_logs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_luns$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_modes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_opcodes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_persist$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_prevent$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_raw$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_rdac$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_readcap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_read_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_read_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_reassign$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_referrals$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_rep_zones$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_requests$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_reset_wp$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_rmsn$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_rtpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_safte$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sanitize$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_senddiag$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ses$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_ses_microcode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_start$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_stpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_sync$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_turs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_unmap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_vpd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_write_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_write_same$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_write_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_FALSE@@OS_OSF_TRUE@ sg_wr_mode$(EXEEXT) @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_copy_results$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_dd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_decode_sense$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_emc_trespass$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_format$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_get_lba_status$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_ident$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sginfo$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_inq$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_logs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_luns$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_map26$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_map$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sgm_dd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_modes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_opcodes$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sgp_dd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_persist$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_prevent$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_raw$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_rbuf$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_rdac$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_read$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_readcap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_read_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_read_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_reassign$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_referrals$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_rep_zones$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_requests$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_reset$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_reset_wp$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_rmsn$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_rtpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_safte$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sanitize$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_scan$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_senddiag$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_ses$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_ses_microcode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_start$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_stpg$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_sync$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_test_rwbuf$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_turs$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_unmap$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_vpd$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_long$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_same$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_write_verify$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_wr_mode$(EXEEXT) \ @OS_FREEBSD_FALSE@@OS_LINUX_TRUE@ sg_xcopy$(EXEEXT) @OS_FREEBSD_TRUE@bin_PROGRAMS = sg_compare_and_write$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_decode_sense$(EXEEXT) sg_format$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_get_config$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_get_lba_status$(EXEEXT) sg_ident$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_inq$(EXEEXT) sg_logs$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_luns$(EXEEXT) sg_modes$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_opcodes$(EXEEXT) sg_persist$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_prevent$(EXEEXT) sg_raw$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_rdac$(EXEEXT) sg_readcap$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_read_block_limits$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_read_buffer$(EXEEXT) sg_read_long$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_reassign$(EXEEXT) sg_referrals$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_rep_zones$(EXEEXT) sg_requests$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_reset_wp$(EXEEXT) sg_rmsn$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_rtpg$(EXEEXT) sg_safte$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_sanitize$(EXEEXT) sg_sat_identify$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_sat_phy_event$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_sat_read_gplog$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_sat_set_features$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_senddiag$(EXEEXT) sg_ses$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_ses_microcode$(EXEEXT) sg_start$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_stpg$(EXEEXT) sg_sync$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_turs$(EXEEXT) sg_unmap$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_verify$(EXEEXT) sg_vpd$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_write_buffer$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_write_long$(EXEEXT) sg_write_same$(EXEEXT) \ @OS_FREEBSD_TRUE@ sg_write_verify$(EXEEXT) sg_wr_mode$(EXEEXT) subdir = src DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/config.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) am_sg_compare_and_write_OBJECTS = sg_compare_and_write.$(OBJEXT) sg_compare_and_write_OBJECTS = $(am_sg_compare_and_write_OBJECTS) sg_compare_and_write_DEPENDENCIES = ../lib/libsgutils2.la AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent am__v_lt_1 = am_sg_copy_results_OBJECTS = sg_copy_results.$(OBJEXT) sg_copy_results_OBJECTS = $(am_sg_copy_results_OBJECTS) sg_copy_results_DEPENDENCIES = ../lib/libsgutils2.la am_sg_dd_OBJECTS = sg_dd.$(OBJEXT) sg_dd_OBJECTS = $(am_sg_dd_OBJECTS) sg_dd_DEPENDENCIES = ../lib/libsgutils2.la am_sg_decode_sense_OBJECTS = sg_decode_sense.$(OBJEXT) sg_decode_sense_OBJECTS = $(am_sg_decode_sense_OBJECTS) sg_decode_sense_DEPENDENCIES = ../lib/libsgutils2.la am_sg_emc_trespass_OBJECTS = sg_emc_trespass.$(OBJEXT) sg_emc_trespass_OBJECTS = $(am_sg_emc_trespass_OBJECTS) sg_emc_trespass_DEPENDENCIES = ../lib/libsgutils2.la am_sg_format_OBJECTS = sg_format.$(OBJEXT) sg_format_OBJECTS = $(am_sg_format_OBJECTS) sg_format_DEPENDENCIES = ../lib/libsgutils2.la am_sg_get_config_OBJECTS = sg_get_config.$(OBJEXT) sg_get_config_OBJECTS = $(am_sg_get_config_OBJECTS) sg_get_config_DEPENDENCIES = ../lib/libsgutils2.la am_sg_get_lba_status_OBJECTS = sg_get_lba_status.$(OBJEXT) sg_get_lba_status_OBJECTS = $(am_sg_get_lba_status_OBJECTS) sg_get_lba_status_DEPENDENCIES = ../lib/libsgutils2.la am_sg_ident_OBJECTS = sg_ident.$(OBJEXT) sg_ident_OBJECTS = $(am_sg_ident_OBJECTS) sg_ident_DEPENDENCIES = ../lib/libsgutils2.la am_sg_inq_OBJECTS = sg_inq.$(OBJEXT) sg_inq_data.$(OBJEXT) sg_inq_OBJECTS = $(am_sg_inq_OBJECTS) sg_inq_DEPENDENCIES = ../lib/libsgutils2.la am_sg_logs_OBJECTS = sg_logs.$(OBJEXT) sg_logs_OBJECTS = $(am_sg_logs_OBJECTS) sg_logs_DEPENDENCIES = ../lib/libsgutils2.la am_sg_luns_OBJECTS = sg_luns.$(OBJEXT) sg_luns_OBJECTS = $(am_sg_luns_OBJECTS) sg_luns_DEPENDENCIES = ../lib/libsgutils2.la am_sg_map_OBJECTS = sg_map.$(OBJEXT) sg_map_OBJECTS = $(am_sg_map_OBJECTS) sg_map_DEPENDENCIES = ../lib/libsgutils2.la am_sg_map26_OBJECTS = sg_map26.$(OBJEXT) sg_map26_OBJECTS = $(am_sg_map26_OBJECTS) sg_map26_DEPENDENCIES = am_sg_modes_OBJECTS = sg_modes.$(OBJEXT) sg_modes_OBJECTS = $(am_sg_modes_OBJECTS) sg_modes_DEPENDENCIES = ../lib/libsgutils2.la am_sg_opcodes_OBJECTS = sg_opcodes.$(OBJEXT) sg_opcodes_OBJECTS = $(am_sg_opcodes_OBJECTS) sg_opcodes_DEPENDENCIES = ../lib/libsgutils2.la am_sg_persist_OBJECTS = sg_persist.$(OBJEXT) sg_persist_OBJECTS = $(am_sg_persist_OBJECTS) sg_persist_DEPENDENCIES = ../lib/libsgutils2.la am_sg_prevent_OBJECTS = sg_prevent.$(OBJEXT) sg_prevent_OBJECTS = $(am_sg_prevent_OBJECTS) sg_prevent_DEPENDENCIES = ../lib/libsgutils2.la am_sg_raw_OBJECTS = sg_raw.$(OBJEXT) sg_raw_OBJECTS = $(am_sg_raw_OBJECTS) sg_raw_DEPENDENCIES = ../lib/libsgutils2.la am_sg_rbuf_OBJECTS = sg_rbuf.$(OBJEXT) sg_rbuf_OBJECTS = $(am_sg_rbuf_OBJECTS) sg_rbuf_DEPENDENCIES = ../lib/libsgutils2.la am_sg_rdac_OBJECTS = sg_rdac.$(OBJEXT) sg_rdac_OBJECTS = $(am_sg_rdac_OBJECTS) sg_rdac_DEPENDENCIES = ../lib/libsgutils2.la am_sg_read_OBJECTS = sg_read.$(OBJEXT) sg_read_OBJECTS = $(am_sg_read_OBJECTS) sg_read_DEPENDENCIES = ../lib/libsgutils2.la am_sg_read_block_limits_OBJECTS = sg_read_block_limits.$(OBJEXT) sg_read_block_limits_OBJECTS = $(am_sg_read_block_limits_OBJECTS) sg_read_block_limits_DEPENDENCIES = ../lib/libsgutils2.la am_sg_read_buffer_OBJECTS = sg_read_buffer.$(OBJEXT) sg_read_buffer_OBJECTS = $(am_sg_read_buffer_OBJECTS) sg_read_buffer_DEPENDENCIES = ../lib/libsgutils2.la am_sg_read_long_OBJECTS = sg_read_long.$(OBJEXT) sg_read_long_OBJECTS = $(am_sg_read_long_OBJECTS) sg_read_long_DEPENDENCIES = ../lib/libsgutils2.la am_sg_readcap_OBJECTS = sg_readcap.$(OBJEXT) sg_readcap_OBJECTS = $(am_sg_readcap_OBJECTS) sg_readcap_DEPENDENCIES = ../lib/libsgutils2.la am_sg_reassign_OBJECTS = sg_reassign.$(OBJEXT) sg_reassign_OBJECTS = $(am_sg_reassign_OBJECTS) sg_reassign_DEPENDENCIES = ../lib/libsgutils2.la am_sg_referrals_OBJECTS = sg_referrals.$(OBJEXT) sg_referrals_OBJECTS = $(am_sg_referrals_OBJECTS) sg_referrals_DEPENDENCIES = ../lib/libsgutils2.la am_sg_rep_zones_OBJECTS = sg_rep_zones.$(OBJEXT) sg_rep_zones_OBJECTS = $(am_sg_rep_zones_OBJECTS) sg_rep_zones_DEPENDENCIES = ../lib/libsgutils2.la am_sg_requests_OBJECTS = sg_requests.$(OBJEXT) sg_requests_OBJECTS = $(am_sg_requests_OBJECTS) sg_requests_DEPENDENCIES = ../lib/libsgutils2.la am_sg_reset_OBJECTS = sg_reset.$(OBJEXT) sg_reset_OBJECTS = $(am_sg_reset_OBJECTS) sg_reset_DEPENDENCIES = am_sg_reset_wp_OBJECTS = sg_reset_wp.$(OBJEXT) sg_reset_wp_OBJECTS = $(am_sg_reset_wp_OBJECTS) sg_reset_wp_DEPENDENCIES = ../lib/libsgutils2.la am_sg_rmsn_OBJECTS = sg_rmsn.$(OBJEXT) sg_rmsn_OBJECTS = $(am_sg_rmsn_OBJECTS) sg_rmsn_DEPENDENCIES = ../lib/libsgutils2.la am_sg_rtpg_OBJECTS = sg_rtpg.$(OBJEXT) sg_rtpg_OBJECTS = $(am_sg_rtpg_OBJECTS) sg_rtpg_DEPENDENCIES = ../lib/libsgutils2.la am_sg_safte_OBJECTS = sg_safte.$(OBJEXT) sg_safte_OBJECTS = $(am_sg_safte_OBJECTS) sg_safte_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sanitize_OBJECTS = sg_sanitize.$(OBJEXT) sg_sanitize_OBJECTS = $(am_sg_sanitize_OBJECTS) sg_sanitize_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sat_identify_OBJECTS = sg_sat_identify.$(OBJEXT) sg_sat_identify_OBJECTS = $(am_sg_sat_identify_OBJECTS) sg_sat_identify_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sat_phy_event_OBJECTS = sg_sat_phy_event.$(OBJEXT) sg_sat_phy_event_OBJECTS = $(am_sg_sat_phy_event_OBJECTS) sg_sat_phy_event_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sat_read_gplog_OBJECTS = sg_sat_read_gplog.$(OBJEXT) sg_sat_read_gplog_OBJECTS = $(am_sg_sat_read_gplog_OBJECTS) sg_sat_read_gplog_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sat_set_features_OBJECTS = sg_sat_set_features.$(OBJEXT) sg_sat_set_features_OBJECTS = $(am_sg_sat_set_features_OBJECTS) sg_sat_set_features_DEPENDENCIES = ../lib/libsgutils2.la am_sg_scan_OBJECTS = sg_scan.$(OBJEXT) sg_scan_OBJECTS = $(am_sg_scan_OBJECTS) sg_scan_DEPENDENCIES = ../lib/libsgutils2.la am_sg_senddiag_OBJECTS = sg_senddiag.$(OBJEXT) sg_senddiag_OBJECTS = $(am_sg_senddiag_OBJECTS) sg_senddiag_DEPENDENCIES = ../lib/libsgutils2.la am_sg_ses_OBJECTS = sg_ses.$(OBJEXT) sg_ses_OBJECTS = $(am_sg_ses_OBJECTS) sg_ses_DEPENDENCIES = ../lib/libsgutils2.la am_sg_ses_microcode_OBJECTS = sg_ses_microcode.$(OBJEXT) sg_ses_microcode_OBJECTS = $(am_sg_ses_microcode_OBJECTS) sg_ses_microcode_DEPENDENCIES = ../lib/libsgutils2.la am_sg_start_OBJECTS = sg_start.$(OBJEXT) sg_start_OBJECTS = $(am_sg_start_OBJECTS) sg_start_DEPENDENCIES = ../lib/libsgutils2.la am_sg_stpg_OBJECTS = sg_stpg.$(OBJEXT) sg_stpg_OBJECTS = $(am_sg_stpg_OBJECTS) sg_stpg_DEPENDENCIES = ../lib/libsgutils2.la am_sg_sync_OBJECTS = sg_sync.$(OBJEXT) sg_sync_OBJECTS = $(am_sg_sync_OBJECTS) sg_sync_DEPENDENCIES = ../lib/libsgutils2.la am_sg_test_rwbuf_OBJECTS = sg_test_rwbuf.$(OBJEXT) sg_test_rwbuf_OBJECTS = $(am_sg_test_rwbuf_OBJECTS) sg_test_rwbuf_DEPENDENCIES = ../lib/libsgutils2.la am_sg_turs_OBJECTS = sg_turs.$(OBJEXT) sg_turs_OBJECTS = $(am_sg_turs_OBJECTS) sg_turs_DEPENDENCIES = ../lib/libsgutils2.la am_sg_unmap_OBJECTS = sg_unmap.$(OBJEXT) sg_unmap_OBJECTS = $(am_sg_unmap_OBJECTS) sg_unmap_DEPENDENCIES = ../lib/libsgutils2.la am_sg_verify_OBJECTS = sg_verify.$(OBJEXT) sg_verify_OBJECTS = $(am_sg_verify_OBJECTS) sg_verify_DEPENDENCIES = ../lib/libsgutils2.la am_sg_vpd_OBJECTS = sg_vpd.$(OBJEXT) sg_vpd_vendor.$(OBJEXT) sg_vpd_OBJECTS = $(am_sg_vpd_OBJECTS) sg_vpd_DEPENDENCIES = ../lib/libsgutils2.la am_sg_wr_mode_OBJECTS = sg_wr_mode.$(OBJEXT) sg_wr_mode_OBJECTS = $(am_sg_wr_mode_OBJECTS) sg_wr_mode_DEPENDENCIES = ../lib/libsgutils2.la am_sg_write_buffer_OBJECTS = sg_write_buffer.$(OBJEXT) sg_write_buffer_OBJECTS = $(am_sg_write_buffer_OBJECTS) sg_write_buffer_DEPENDENCIES = ../lib/libsgutils2.la am_sg_write_long_OBJECTS = sg_write_long.$(OBJEXT) sg_write_long_OBJECTS = $(am_sg_write_long_OBJECTS) sg_write_long_DEPENDENCIES = ../lib/libsgutils2.la am_sg_write_same_OBJECTS = sg_write_same.$(OBJEXT) sg_write_same_OBJECTS = $(am_sg_write_same_OBJECTS) sg_write_same_DEPENDENCIES = ../lib/libsgutils2.la am_sg_write_verify_OBJECTS = sg_write_verify.$(OBJEXT) sg_write_verify_OBJECTS = $(am_sg_write_verify_OBJECTS) sg_write_verify_DEPENDENCIES = ../lib/libsgutils2.la am_sg_xcopy_OBJECTS = sg_xcopy.$(OBJEXT) sg_xcopy_OBJECTS = $(am_sg_xcopy_OBJECTS) sg_xcopy_DEPENDENCIES = ../lib/libsgutils2.la am_sginfo_OBJECTS = sginfo.$(OBJEXT) sginfo_OBJECTS = $(am_sginfo_OBJECTS) sginfo_DEPENDENCIES = ../lib/libsgutils2.la am_sgm_dd_OBJECTS = sgm_dd.$(OBJEXT) sgm_dd_OBJECTS = $(am_sgm_dd_OBJECTS) sgm_dd_DEPENDENCIES = ../lib/libsgutils2.la am_sgp_dd_OBJECTS = sgp_dd.$(OBJEXT) sgp_dd_OBJECTS = $(am_sgp_dd_OBJECTS) sgp_dd_DEPENDENCIES = ../lib/libsgutils2.la AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(sg_compare_and_write_SOURCES) $(sg_copy_results_SOURCES) \ $(sg_dd_SOURCES) $(sg_decode_sense_SOURCES) \ $(sg_emc_trespass_SOURCES) $(sg_format_SOURCES) \ $(sg_get_config_SOURCES) $(sg_get_lba_status_SOURCES) \ $(sg_ident_SOURCES) $(sg_inq_SOURCES) $(sg_logs_SOURCES) \ $(sg_luns_SOURCES) $(sg_map_SOURCES) $(sg_map26_SOURCES) \ $(sg_modes_SOURCES) $(sg_opcodes_SOURCES) \ $(sg_persist_SOURCES) $(sg_prevent_SOURCES) $(sg_raw_SOURCES) \ $(sg_rbuf_SOURCES) $(sg_rdac_SOURCES) $(sg_read_SOURCES) \ $(sg_read_block_limits_SOURCES) $(sg_read_buffer_SOURCES) \ $(sg_read_long_SOURCES) $(sg_readcap_SOURCES) \ $(sg_reassign_SOURCES) $(sg_referrals_SOURCES) \ $(sg_rep_zones_SOURCES) $(sg_requests_SOURCES) \ $(sg_reset_SOURCES) $(sg_reset_wp_SOURCES) $(sg_rmsn_SOURCES) \ $(sg_rtpg_SOURCES) $(sg_safte_SOURCES) $(sg_sanitize_SOURCES) \ $(sg_sat_identify_SOURCES) $(sg_sat_phy_event_SOURCES) \ $(sg_sat_read_gplog_SOURCES) $(sg_sat_set_features_SOURCES) \ $(sg_scan_SOURCES) $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) \ $(sg_ses_microcode_SOURCES) $(sg_start_SOURCES) \ $(sg_stpg_SOURCES) $(sg_sync_SOURCES) $(sg_test_rwbuf_SOURCES) \ $(sg_turs_SOURCES) $(sg_unmap_SOURCES) $(sg_verify_SOURCES) \ $(sg_vpd_SOURCES) $(sg_wr_mode_SOURCES) \ $(sg_write_buffer_SOURCES) $(sg_write_long_SOURCES) \ $(sg_write_same_SOURCES) $(sg_write_verify_SOURCES) \ $(sg_xcopy_SOURCES) $(sginfo_SOURCES) $(sgm_dd_SOURCES) \ $(sgp_dd_SOURCES) DIST_SOURCES = $(sg_compare_and_write_SOURCES) \ $(sg_copy_results_SOURCES) $(sg_dd_SOURCES) \ $(sg_decode_sense_SOURCES) $(sg_emc_trespass_SOURCES) \ $(sg_format_SOURCES) $(sg_get_config_SOURCES) \ $(sg_get_lba_status_SOURCES) $(sg_ident_SOURCES) \ $(sg_inq_SOURCES) $(sg_logs_SOURCES) $(sg_luns_SOURCES) \ $(sg_map_SOURCES) $(sg_map26_SOURCES) $(sg_modes_SOURCES) \ $(sg_opcodes_SOURCES) $(sg_persist_SOURCES) \ $(sg_prevent_SOURCES) $(sg_raw_SOURCES) $(sg_rbuf_SOURCES) \ $(sg_rdac_SOURCES) $(sg_read_SOURCES) \ $(sg_read_block_limits_SOURCES) $(sg_read_buffer_SOURCES) \ $(sg_read_long_SOURCES) $(sg_readcap_SOURCES) \ $(sg_reassign_SOURCES) $(sg_referrals_SOURCES) \ $(sg_rep_zones_SOURCES) $(sg_requests_SOURCES) \ $(sg_reset_SOURCES) $(sg_reset_wp_SOURCES) $(sg_rmsn_SOURCES) \ $(sg_rtpg_SOURCES) $(sg_safte_SOURCES) $(sg_sanitize_SOURCES) \ $(sg_sat_identify_SOURCES) $(sg_sat_phy_event_SOURCES) \ $(sg_sat_read_gplog_SOURCES) $(sg_sat_set_features_SOURCES) \ $(sg_scan_SOURCES) $(sg_senddiag_SOURCES) $(sg_ses_SOURCES) \ $(sg_ses_microcode_SOURCES) $(sg_start_SOURCES) \ $(sg_stpg_SOURCES) $(sg_sync_SOURCES) $(sg_test_rwbuf_SOURCES) \ $(sg_turs_SOURCES) $(sg_unmap_SOURCES) $(sg_verify_SOURCES) \ $(sg_vpd_SOURCES) $(sg_wr_mode_SOURCES) \ $(sg_write_buffer_SOURCES) $(sg_write_long_SOURCES) \ $(sg_write_same_SOURCES) $(sg_write_verify_SOURCES) \ $(sg_xcopy_SOURCES) $(sginfo_SOURCES) $(sgm_dd_SOURCES) \ $(sgp_dd_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GETOPT_O_FILES = @GETOPT_O_FILES@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ RANLIB = @RANLIB@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ os_cflags = @os_cflags@ os_libs = @os_libs@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ # For C++/clang testing # -std= can be c99, c11, gnu11, etc. Default is gnu89 (gnu90 is the same) # -Wall is no longer all warnings. Add -W (since renamed to -Wextra) for more AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ -pedantic -std=c11 # AM_CFLAGS = -iquote ../include -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -Wall -W @os_cflags@ -pedantic -std=c++11 sg_dd_SOURCES = sg_dd.c sg_dd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_decode_sense_SOURCES = sg_decode_sense.c sg_decode_sense_LDADD = ../lib/libsgutils2.la @os_libs@ sg_emc_trespass_SOURCES = sg_emc_trespass.c sg_emc_trespass_LDADD = ../lib/libsgutils2.la @os_libs@ sg_format_SOURCES = sg_format.c sg_format_LDADD = ../lib/libsgutils2.la @os_libs@ sg_get_config_SOURCES = sg_get_config.c sg_get_config_LDADD = ../lib/libsgutils2.la @os_libs@ sg_get_lba_status_SOURCES = sg_get_lba_status.c sg_get_lba_status_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ident_SOURCES = sg_ident.c sg_ident_LDADD = ../lib/libsgutils2.la @os_libs@ sginfo_SOURCES = sginfo.c sginfo_LDADD = ../lib/libsgutils2.la @os_libs@ sg_inq_SOURCES = sg_inq.c sg_inq_data.c sg_inq_LDADD = ../lib/libsgutils2.la @os_libs@ sg_logs_SOURCES = sg_logs.c sg_logs_LDADD = ../lib/libsgutils2.la @os_libs@ sg_luns_SOURCES = sg_luns.c sg_luns_LDADD = ../lib/libsgutils2.la @os_libs@ sg_map26_SOURCES = sg_map26.c sg_map26_LDADD = @os_libs@ sg_map_SOURCES = sg_map.c sg_map_LDADD = ../lib/libsgutils2.la @os_libs@ sgm_dd_SOURCES = sgm_dd.c sgm_dd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_modes_SOURCES = sg_modes.c sg_modes_LDADD = ../lib/libsgutils2.la @os_libs@ sg_opcodes_SOURCES = sg_opcodes.c sg_opcodes_LDADD = ../lib/libsgutils2.la @os_libs@ sgp_dd_SOURCES = sgp_dd.c sgp_dd_LDADD = ../lib/libsgutils2.la @os_libs@ -lpthread sg_persist_SOURCES = sg_persist.c sg_persist_LDADD = ../lib/libsgutils2.la @os_libs@ sg_prevent_SOURCES = sg_prevent.c sg_prevent_LDADD = ../lib/libsgutils2.la @os_libs@ sg_raw_SOURCES = sg_raw.c sg_raw_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rbuf_SOURCES = sg_rbuf.c sg_rbuf_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rdac_SOURCES = sg_rdac.c sg_rdac_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_SOURCES = sg_read.c sg_read_LDADD = ../lib/libsgutils2.la @os_libs@ sg_readcap_SOURCES = sg_readcap.c sg_readcap_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_block_limits_SOURCES = sg_read_block_limits.c sg_read_block_limits_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_buffer_SOURCES = sg_read_buffer.c sg_read_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_read_long_SOURCES = sg_read_long.c sg_read_long_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reassign_SOURCES = sg_reassign.c sg_reassign_LDADD = ../lib/libsgutils2.la @os_libs@ sg_requests_SOURCES = sg_requests.c sg_requests_LDADD = ../lib/libsgutils2.la @os_libs@ sg_referrals_SOURCES = sg_referrals.c sg_referrals_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reset_SOURCES = sg_reset.c sg_reset_LDADD = @os_libs@ sg_rmsn_SOURCES = sg_rmsn.c sg_rmsn_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rtpg_SOURCES = sg_rtpg.c sg_rtpg_LDADD = ../lib/libsgutils2.la @os_libs@ sg_safte_SOURCES = sg_safte.c sg_safte_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sanitize_SOURCES = sg_sanitize.c sg_sanitize_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_identify_SOURCES = sg_sat_identify.c sg_sat_identify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_phy_event_SOURCES = sg_sat_phy_event.c sg_sat_phy_event_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_set_features_SOURCES = sg_sat_set_features.c sg_sat_set_features_LDADD = ../lib/libsgutils2.la @os_libs@ sg_scan_SOURCES = sg_scan.c sg_scan_LDADD = ../lib/libsgutils2.la @os_libs@ sg_senddiag_SOURCES = sg_senddiag.c sg_senddiag_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ses_SOURCES = sg_ses.c sg_ses_LDADD = ../lib/libsgutils2.la @os_libs@ sg_ses_microcode_SOURCES = sg_ses_microcode.c sg_ses_microcode_LDADD = ../lib/libsgutils2.la @os_libs@ sg_start_SOURCES = sg_start.c sg_start_LDADD = ../lib/libsgutils2.la @os_libs@ sg_stpg_SOURCES = sg_stpg.c sg_stpg_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sync_SOURCES = sg_sync.c sg_sync_LDADD = ../lib/libsgutils2.la @os_libs@ sg_test_rwbuf_SOURCES = sg_test_rwbuf.c sg_test_rwbuf_LDADD = ../lib/libsgutils2.la @os_libs@ sg_turs_SOURCES = sg_turs.c sg_turs_LDADD = ../lib/libsgutils2.la @os_libs@ sg_unmap_SOURCES = sg_unmap.c sg_unmap_LDADD = ../lib/libsgutils2.la @os_libs@ sg_verify_SOURCES = sg_verify.c sg_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_vpd_SOURCES = sg_vpd.c sg_vpd_vendor.c sg_vpd_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_buffer_SOURCES = sg_write_buffer.c sg_write_buffer_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_long_SOURCES = sg_write_long.c sg_write_long_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_same_SOURCES = sg_write_same.c sg_write_same_LDADD = ../lib/libsgutils2.la @os_libs@ sg_wr_mode_SOURCES = sg_wr_mode.c sg_wr_mode_LDADD = ../lib/libsgutils2.la @os_libs@ sg_xcopy_SOURCES = sg_xcopy.c sg_xcopy_LDADD = ../lib/libsgutils2.la @os_libs@ sg_copy_results_SOURCES = sg_copy_results.c sg_copy_results_LDADD = ../lib/libsgutils2.la @os_libs@ sg_compare_and_write_SOURCES = sg_compare_and_write.c sg_compare_and_write_LDADD = ../lib/libsgutils2.la @os_libs@ sg_rep_zones_SOURCES = sg_rep_zones.c sg_rep_zones_LDADD = ../lib/libsgutils2.la @os_libs@ sg_reset_wp_SOURCES = sg_reset_wp.c sg_reset_wp_LDADD = ../lib/libsgutils2.la @os_libs@ sg_write_verify_SOURCES = sg_write_verify.c sg_write_verify_LDADD = ../lib/libsgutils2.la @os_libs@ sg_sat_read_gplog_SOURCES = sg_sat_read_gplog.c sg_sat_read_gplog_LDADD = ../lib/libsgutils2.la @os_libs@ all: all-am .SUFFIXES: .SUFFIXES: .c .lo .o .obj $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu src/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ || test -f $$p1 \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list sg_compare_and_write$(EXEEXT): $(sg_compare_and_write_OBJECTS) $(sg_compare_and_write_DEPENDENCIES) $(EXTRA_sg_compare_and_write_DEPENDENCIES) @rm -f sg_compare_and_write$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_compare_and_write_OBJECTS) $(sg_compare_and_write_LDADD) $(LIBS) sg_copy_results$(EXEEXT): $(sg_copy_results_OBJECTS) $(sg_copy_results_DEPENDENCIES) $(EXTRA_sg_copy_results_DEPENDENCIES) @rm -f sg_copy_results$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_copy_results_OBJECTS) $(sg_copy_results_LDADD) $(LIBS) sg_dd$(EXEEXT): $(sg_dd_OBJECTS) $(sg_dd_DEPENDENCIES) $(EXTRA_sg_dd_DEPENDENCIES) @rm -f sg_dd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_dd_OBJECTS) $(sg_dd_LDADD) $(LIBS) sg_decode_sense$(EXEEXT): $(sg_decode_sense_OBJECTS) $(sg_decode_sense_DEPENDENCIES) $(EXTRA_sg_decode_sense_DEPENDENCIES) @rm -f sg_decode_sense$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_decode_sense_OBJECTS) $(sg_decode_sense_LDADD) $(LIBS) sg_emc_trespass$(EXEEXT): $(sg_emc_trespass_OBJECTS) $(sg_emc_trespass_DEPENDENCIES) $(EXTRA_sg_emc_trespass_DEPENDENCIES) @rm -f sg_emc_trespass$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_emc_trespass_OBJECTS) $(sg_emc_trespass_LDADD) $(LIBS) sg_format$(EXEEXT): $(sg_format_OBJECTS) $(sg_format_DEPENDENCIES) $(EXTRA_sg_format_DEPENDENCIES) @rm -f sg_format$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_format_OBJECTS) $(sg_format_LDADD) $(LIBS) sg_get_config$(EXEEXT): $(sg_get_config_OBJECTS) $(sg_get_config_DEPENDENCIES) $(EXTRA_sg_get_config_DEPENDENCIES) @rm -f sg_get_config$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_get_config_OBJECTS) $(sg_get_config_LDADD) $(LIBS) sg_get_lba_status$(EXEEXT): $(sg_get_lba_status_OBJECTS) $(sg_get_lba_status_DEPENDENCIES) $(EXTRA_sg_get_lba_status_DEPENDENCIES) @rm -f sg_get_lba_status$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_get_lba_status_OBJECTS) $(sg_get_lba_status_LDADD) $(LIBS) sg_ident$(EXEEXT): $(sg_ident_OBJECTS) $(sg_ident_DEPENDENCIES) $(EXTRA_sg_ident_DEPENDENCIES) @rm -f sg_ident$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_ident_OBJECTS) $(sg_ident_LDADD) $(LIBS) sg_inq$(EXEEXT): $(sg_inq_OBJECTS) $(sg_inq_DEPENDENCIES) $(EXTRA_sg_inq_DEPENDENCIES) @rm -f sg_inq$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_inq_OBJECTS) $(sg_inq_LDADD) $(LIBS) sg_logs$(EXEEXT): $(sg_logs_OBJECTS) $(sg_logs_DEPENDENCIES) $(EXTRA_sg_logs_DEPENDENCIES) @rm -f sg_logs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_logs_OBJECTS) $(sg_logs_LDADD) $(LIBS) sg_luns$(EXEEXT): $(sg_luns_OBJECTS) $(sg_luns_DEPENDENCIES) $(EXTRA_sg_luns_DEPENDENCIES) @rm -f sg_luns$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_luns_OBJECTS) $(sg_luns_LDADD) $(LIBS) sg_map$(EXEEXT): $(sg_map_OBJECTS) $(sg_map_DEPENDENCIES) $(EXTRA_sg_map_DEPENDENCIES) @rm -f sg_map$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_map_OBJECTS) $(sg_map_LDADD) $(LIBS) sg_map26$(EXEEXT): $(sg_map26_OBJECTS) $(sg_map26_DEPENDENCIES) $(EXTRA_sg_map26_DEPENDENCIES) @rm -f sg_map26$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_map26_OBJECTS) $(sg_map26_LDADD) $(LIBS) sg_modes$(EXEEXT): $(sg_modes_OBJECTS) $(sg_modes_DEPENDENCIES) $(EXTRA_sg_modes_DEPENDENCIES) @rm -f sg_modes$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_modes_OBJECTS) $(sg_modes_LDADD) $(LIBS) sg_opcodes$(EXEEXT): $(sg_opcodes_OBJECTS) $(sg_opcodes_DEPENDENCIES) $(EXTRA_sg_opcodes_DEPENDENCIES) @rm -f sg_opcodes$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_opcodes_OBJECTS) $(sg_opcodes_LDADD) $(LIBS) sg_persist$(EXEEXT): $(sg_persist_OBJECTS) $(sg_persist_DEPENDENCIES) $(EXTRA_sg_persist_DEPENDENCIES) @rm -f sg_persist$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_persist_OBJECTS) $(sg_persist_LDADD) $(LIBS) sg_prevent$(EXEEXT): $(sg_prevent_OBJECTS) $(sg_prevent_DEPENDENCIES) $(EXTRA_sg_prevent_DEPENDENCIES) @rm -f sg_prevent$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_prevent_OBJECTS) $(sg_prevent_LDADD) $(LIBS) sg_raw$(EXEEXT): $(sg_raw_OBJECTS) $(sg_raw_DEPENDENCIES) $(EXTRA_sg_raw_DEPENDENCIES) @rm -f sg_raw$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_raw_OBJECTS) $(sg_raw_LDADD) $(LIBS) sg_rbuf$(EXEEXT): $(sg_rbuf_OBJECTS) $(sg_rbuf_DEPENDENCIES) $(EXTRA_sg_rbuf_DEPENDENCIES) @rm -f sg_rbuf$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rbuf_OBJECTS) $(sg_rbuf_LDADD) $(LIBS) sg_rdac$(EXEEXT): $(sg_rdac_OBJECTS) $(sg_rdac_DEPENDENCIES) $(EXTRA_sg_rdac_DEPENDENCIES) @rm -f sg_rdac$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rdac_OBJECTS) $(sg_rdac_LDADD) $(LIBS) sg_read$(EXEEXT): $(sg_read_OBJECTS) $(sg_read_DEPENDENCIES) $(EXTRA_sg_read_DEPENDENCIES) @rm -f sg_read$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_read_OBJECTS) $(sg_read_LDADD) $(LIBS) sg_read_block_limits$(EXEEXT): $(sg_read_block_limits_OBJECTS) $(sg_read_block_limits_DEPENDENCIES) $(EXTRA_sg_read_block_limits_DEPENDENCIES) @rm -f sg_read_block_limits$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_read_block_limits_OBJECTS) $(sg_read_block_limits_LDADD) $(LIBS) sg_read_buffer$(EXEEXT): $(sg_read_buffer_OBJECTS) $(sg_read_buffer_DEPENDENCIES) $(EXTRA_sg_read_buffer_DEPENDENCIES) @rm -f sg_read_buffer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_read_buffer_OBJECTS) $(sg_read_buffer_LDADD) $(LIBS) sg_read_long$(EXEEXT): $(sg_read_long_OBJECTS) $(sg_read_long_DEPENDENCIES) $(EXTRA_sg_read_long_DEPENDENCIES) @rm -f sg_read_long$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_read_long_OBJECTS) $(sg_read_long_LDADD) $(LIBS) sg_readcap$(EXEEXT): $(sg_readcap_OBJECTS) $(sg_readcap_DEPENDENCIES) $(EXTRA_sg_readcap_DEPENDENCIES) @rm -f sg_readcap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_readcap_OBJECTS) $(sg_readcap_LDADD) $(LIBS) sg_reassign$(EXEEXT): $(sg_reassign_OBJECTS) $(sg_reassign_DEPENDENCIES) $(EXTRA_sg_reassign_DEPENDENCIES) @rm -f sg_reassign$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_reassign_OBJECTS) $(sg_reassign_LDADD) $(LIBS) sg_referrals$(EXEEXT): $(sg_referrals_OBJECTS) $(sg_referrals_DEPENDENCIES) $(EXTRA_sg_referrals_DEPENDENCIES) @rm -f sg_referrals$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_referrals_OBJECTS) $(sg_referrals_LDADD) $(LIBS) sg_rep_zones$(EXEEXT): $(sg_rep_zones_OBJECTS) $(sg_rep_zones_DEPENDENCIES) $(EXTRA_sg_rep_zones_DEPENDENCIES) @rm -f sg_rep_zones$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rep_zones_OBJECTS) $(sg_rep_zones_LDADD) $(LIBS) sg_requests$(EXEEXT): $(sg_requests_OBJECTS) $(sg_requests_DEPENDENCIES) $(EXTRA_sg_requests_DEPENDENCIES) @rm -f sg_requests$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_requests_OBJECTS) $(sg_requests_LDADD) $(LIBS) sg_reset$(EXEEXT): $(sg_reset_OBJECTS) $(sg_reset_DEPENDENCIES) $(EXTRA_sg_reset_DEPENDENCIES) @rm -f sg_reset$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_reset_OBJECTS) $(sg_reset_LDADD) $(LIBS) sg_reset_wp$(EXEEXT): $(sg_reset_wp_OBJECTS) $(sg_reset_wp_DEPENDENCIES) $(EXTRA_sg_reset_wp_DEPENDENCIES) @rm -f sg_reset_wp$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_reset_wp_OBJECTS) $(sg_reset_wp_LDADD) $(LIBS) sg_rmsn$(EXEEXT): $(sg_rmsn_OBJECTS) $(sg_rmsn_DEPENDENCIES) $(EXTRA_sg_rmsn_DEPENDENCIES) @rm -f sg_rmsn$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rmsn_OBJECTS) $(sg_rmsn_LDADD) $(LIBS) sg_rtpg$(EXEEXT): $(sg_rtpg_OBJECTS) $(sg_rtpg_DEPENDENCIES) $(EXTRA_sg_rtpg_DEPENDENCIES) @rm -f sg_rtpg$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_rtpg_OBJECTS) $(sg_rtpg_LDADD) $(LIBS) sg_safte$(EXEEXT): $(sg_safte_OBJECTS) $(sg_safte_DEPENDENCIES) $(EXTRA_sg_safte_DEPENDENCIES) @rm -f sg_safte$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_safte_OBJECTS) $(sg_safte_LDADD) $(LIBS) sg_sanitize$(EXEEXT): $(sg_sanitize_OBJECTS) $(sg_sanitize_DEPENDENCIES) $(EXTRA_sg_sanitize_DEPENDENCIES) @rm -f sg_sanitize$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sanitize_OBJECTS) $(sg_sanitize_LDADD) $(LIBS) sg_sat_identify$(EXEEXT): $(sg_sat_identify_OBJECTS) $(sg_sat_identify_DEPENDENCIES) $(EXTRA_sg_sat_identify_DEPENDENCIES) @rm -f sg_sat_identify$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sat_identify_OBJECTS) $(sg_sat_identify_LDADD) $(LIBS) sg_sat_phy_event$(EXEEXT): $(sg_sat_phy_event_OBJECTS) $(sg_sat_phy_event_DEPENDENCIES) $(EXTRA_sg_sat_phy_event_DEPENDENCIES) @rm -f sg_sat_phy_event$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sat_phy_event_OBJECTS) $(sg_sat_phy_event_LDADD) $(LIBS) sg_sat_read_gplog$(EXEEXT): $(sg_sat_read_gplog_OBJECTS) $(sg_sat_read_gplog_DEPENDENCIES) $(EXTRA_sg_sat_read_gplog_DEPENDENCIES) @rm -f sg_sat_read_gplog$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sat_read_gplog_OBJECTS) $(sg_sat_read_gplog_LDADD) $(LIBS) sg_sat_set_features$(EXEEXT): $(sg_sat_set_features_OBJECTS) $(sg_sat_set_features_DEPENDENCIES) $(EXTRA_sg_sat_set_features_DEPENDENCIES) @rm -f sg_sat_set_features$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sat_set_features_OBJECTS) $(sg_sat_set_features_LDADD) $(LIBS) sg_scan$(EXEEXT): $(sg_scan_OBJECTS) $(sg_scan_DEPENDENCIES) $(EXTRA_sg_scan_DEPENDENCIES) @rm -f sg_scan$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_scan_OBJECTS) $(sg_scan_LDADD) $(LIBS) sg_senddiag$(EXEEXT): $(sg_senddiag_OBJECTS) $(sg_senddiag_DEPENDENCIES) $(EXTRA_sg_senddiag_DEPENDENCIES) @rm -f sg_senddiag$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_senddiag_OBJECTS) $(sg_senddiag_LDADD) $(LIBS) sg_ses$(EXEEXT): $(sg_ses_OBJECTS) $(sg_ses_DEPENDENCIES) $(EXTRA_sg_ses_DEPENDENCIES) @rm -f sg_ses$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_ses_OBJECTS) $(sg_ses_LDADD) $(LIBS) sg_ses_microcode$(EXEEXT): $(sg_ses_microcode_OBJECTS) $(sg_ses_microcode_DEPENDENCIES) $(EXTRA_sg_ses_microcode_DEPENDENCIES) @rm -f sg_ses_microcode$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_ses_microcode_OBJECTS) $(sg_ses_microcode_LDADD) $(LIBS) sg_start$(EXEEXT): $(sg_start_OBJECTS) $(sg_start_DEPENDENCIES) $(EXTRA_sg_start_DEPENDENCIES) @rm -f sg_start$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_start_OBJECTS) $(sg_start_LDADD) $(LIBS) sg_stpg$(EXEEXT): $(sg_stpg_OBJECTS) $(sg_stpg_DEPENDENCIES) $(EXTRA_sg_stpg_DEPENDENCIES) @rm -f sg_stpg$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_stpg_OBJECTS) $(sg_stpg_LDADD) $(LIBS) sg_sync$(EXEEXT): $(sg_sync_OBJECTS) $(sg_sync_DEPENDENCIES) $(EXTRA_sg_sync_DEPENDENCIES) @rm -f sg_sync$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_sync_OBJECTS) $(sg_sync_LDADD) $(LIBS) sg_test_rwbuf$(EXEEXT): $(sg_test_rwbuf_OBJECTS) $(sg_test_rwbuf_DEPENDENCIES) $(EXTRA_sg_test_rwbuf_DEPENDENCIES) @rm -f sg_test_rwbuf$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_test_rwbuf_OBJECTS) $(sg_test_rwbuf_LDADD) $(LIBS) sg_turs$(EXEEXT): $(sg_turs_OBJECTS) $(sg_turs_DEPENDENCIES) $(EXTRA_sg_turs_DEPENDENCIES) @rm -f sg_turs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_turs_OBJECTS) $(sg_turs_LDADD) $(LIBS) sg_unmap$(EXEEXT): $(sg_unmap_OBJECTS) $(sg_unmap_DEPENDENCIES) $(EXTRA_sg_unmap_DEPENDENCIES) @rm -f sg_unmap$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_unmap_OBJECTS) $(sg_unmap_LDADD) $(LIBS) sg_verify$(EXEEXT): $(sg_verify_OBJECTS) $(sg_verify_DEPENDENCIES) $(EXTRA_sg_verify_DEPENDENCIES) @rm -f sg_verify$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_verify_OBJECTS) $(sg_verify_LDADD) $(LIBS) sg_vpd$(EXEEXT): $(sg_vpd_OBJECTS) $(sg_vpd_DEPENDENCIES) $(EXTRA_sg_vpd_DEPENDENCIES) @rm -f sg_vpd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_vpd_OBJECTS) $(sg_vpd_LDADD) $(LIBS) sg_wr_mode$(EXEEXT): $(sg_wr_mode_OBJECTS) $(sg_wr_mode_DEPENDENCIES) $(EXTRA_sg_wr_mode_DEPENDENCIES) @rm -f sg_wr_mode$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_wr_mode_OBJECTS) $(sg_wr_mode_LDADD) $(LIBS) sg_write_buffer$(EXEEXT): $(sg_write_buffer_OBJECTS) $(sg_write_buffer_DEPENDENCIES) $(EXTRA_sg_write_buffer_DEPENDENCIES) @rm -f sg_write_buffer$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_buffer_OBJECTS) $(sg_write_buffer_LDADD) $(LIBS) sg_write_long$(EXEEXT): $(sg_write_long_OBJECTS) $(sg_write_long_DEPENDENCIES) $(EXTRA_sg_write_long_DEPENDENCIES) @rm -f sg_write_long$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_long_OBJECTS) $(sg_write_long_LDADD) $(LIBS) sg_write_same$(EXEEXT): $(sg_write_same_OBJECTS) $(sg_write_same_DEPENDENCIES) $(EXTRA_sg_write_same_DEPENDENCIES) @rm -f sg_write_same$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_same_OBJECTS) $(sg_write_same_LDADD) $(LIBS) sg_write_verify$(EXEEXT): $(sg_write_verify_OBJECTS) $(sg_write_verify_DEPENDENCIES) $(EXTRA_sg_write_verify_DEPENDENCIES) @rm -f sg_write_verify$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_write_verify_OBJECTS) $(sg_write_verify_LDADD) $(LIBS) sg_xcopy$(EXEEXT): $(sg_xcopy_OBJECTS) $(sg_xcopy_DEPENDENCIES) $(EXTRA_sg_xcopy_DEPENDENCIES) @rm -f sg_xcopy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sg_xcopy_OBJECTS) $(sg_xcopy_LDADD) $(LIBS) sginfo$(EXEEXT): $(sginfo_OBJECTS) $(sginfo_DEPENDENCIES) $(EXTRA_sginfo_DEPENDENCIES) @rm -f sginfo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sginfo_OBJECTS) $(sginfo_LDADD) $(LIBS) sgm_dd$(EXEEXT): $(sgm_dd_OBJECTS) $(sgm_dd_DEPENDENCIES) $(EXTRA_sgm_dd_DEPENDENCIES) @rm -f sgm_dd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sgm_dd_OBJECTS) $(sgm_dd_LDADD) $(LIBS) sgp_dd$(EXEEXT): $(sgp_dd_OBJECTS) $(sgp_dd_DEPENDENCIES) $(EXTRA_sgp_dd_DEPENDENCIES) @rm -f sgp_dd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sgp_dd_OBJECTS) $(sgp_dd_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_compare_and_write.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_copy_results.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_dd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_decode_sense.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_emc_trespass.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_format.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_get_lba_status.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ident.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_inq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_inq_data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_logs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_luns.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_map26.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_modes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_opcodes.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_persist.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_prevent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_raw.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rbuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rdac.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_block_limits.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_read_long.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_readcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reassign.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_referrals.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rep_zones.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_requests.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_reset_wp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rmsn.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_rtpg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_safte.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sanitize.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_identify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_phy_event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_read_gplog.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sat_set_features.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_scan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_senddiag.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_ses_microcode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_start.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_stpg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_sync.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_test_rwbuf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_turs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_unmap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_verify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_vpd_vendor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_wr_mode.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_buffer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_long.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_same.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_write_verify.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sg_xcopy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sginfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgm_dd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sgp_dd.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-am CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscopelist: cscopelist-am cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." @OS_LINUX_FALSE@@OS_WIN32_CYGWIN_FALSE@@OS_WIN32_MINGW_FALSE@distclean-local: clean: clean-am clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am distclean: distclean-am -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-local distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ clean-binPROGRAMS clean-generic clean-libtool cscopelist-am \ ctags ctags-am distclean distclean-compile distclean-generic \ distclean-libtool distclean-local distclean-tags distdir dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am install-dvi \ install-dvi-am install-exec install-exec-am install-html \ install-html-am install-info install-info-am install-man \ install-pdf install-pdf-am install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ uninstall-binPROGRAMS @OS_LINUX_TRUE@distclean-local: @OS_LINUX_TRUE@ rm -f sg_scan.c @OS_LINUX_TRUE@sg_scan.c : sg_scan.c.linux @OS_LINUX_TRUE@ cp sg_scan.c.linux sg_scan.c @OS_WIN32_MINGW_TRUE@distclean-local: @OS_WIN32_MINGW_TRUE@ rm -f sg_scan.c @OS_WIN32_MINGW_TRUE@sg_scan.c : sg_scan.c.win32 @OS_WIN32_MINGW_TRUE@ cp sg_scan.c.win32 sg_scan.c @OS_WIN32_CYGWIN_TRUE@distclean-local: @OS_WIN32_CYGWIN_TRUE@ rm -f sg_scan.c @OS_WIN32_CYGWIN_TRUE@sg_scan.c : sg_scan.c.win32 @OS_WIN32_CYGWIN_TRUE@ cp sg_scan.c.win32 sg_scan.c # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: sg3_utils-1.40/src/sg_sat_phy_event.c0000664000175000017500000004320712424673250016657 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "1.05 20141030"; /* This program uses a ATA PASS-THROUGH SCSI command. This usage is * defined in the SCSI to ATA Translation (SAT) drafts and standards. * See http://www.t10.org for drafts. SAT is a standard: SAT ANSI INCITS * 431-2007 (draft prior to that is sat-r09.pdf). SAT-2 is also a * standard: SAT-2 ANSI INCITS 465-2010 and the draft prior to that is * sat2r09.pdf . The SAT-3 project has started and the most recent draft * is sat3r01.pdf . */ /* This program uses a ATA PASS-THROUGH (16 or 12) SCSI command defined * by SAT to package an ATA READ LOG EXT (2Fh) command to fetch * log page 11h. That page contains SATA phy event counters. * For ATA READ LOG EXT command see ATA-8/ACS at www.t13.org . * For SATA phy counter definitions see SATA 2.5 . * * Invocation: see the usage() function below */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK comand */ #define SAT_ATA_PASS_THROUGH12_LEN 12 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d #define ATA_READ_LOG_EXT 0x2f #define SATA_PHY_EVENT_LPAGE 0x11 #define READ_LOG_EXT_RESPONSE_LEN 512 #define DEF_TIMEOUT 20 #define EBUFF_SZ 256 static struct option long_options[] = { {"ck_cond", no_argument, 0, 'c'}, {"extend", no_argument, 0, 'e'}, {"hex", no_argument, 0, 'H'}, {"ignore", no_argument, 0, 'i'}, {"len", no_argument, 0, 'l'}, {"raw", no_argument, 0, 'r'}, {"reset", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct phy_event_t { int id; const char * desc; }; static struct phy_event_t phy_event_arr[] = { /* SATA 2.5 section 13.7.2 */ {0x1, "Command failed and ICRC error bit set in Error register"}, /* M */ {0x2, "R_ERR(p) response for data FIS"}, {0x3, "R_ERR(p) response for device-to-host data FIS"}, {0x4, "R_ERR(p) response for host-to-device data FIS"}, {0x5, "R_ERR(p) response for non-data FIS"}, {0x6, "R_ERR(p) response for device-to-host non-data FIS"}, {0x7, "R_ERR(p) response for host-to-device non-data FIS"}, {0x8, "Device-to-host non-data FIS retries"}, {0x9, "Transition from drive PHYRDY to drive PHYRDYn"}, {0xa, "Signature device-to-host register FISes due to COMRESET"}, /* M */ {0xb, "CRC errors within host-to-device FIS"}, {0xd, "non CRC errors within host-to-device FIS"}, {0xf, "R_ERR(p) response for host-to-device data FIS, CRC"}, {0x10, "R_ERR(p) response for host-to-device data FIS, non-CRC"}, {0x12, "R_ERR(p) response for host-to-device non-data FIS, CRC"}, {0x13, "R_ERR(p) response for host-to-device non-data FIS, non-CRC"}, {0xc00, "PM: host-to-device non-data FIS, R_ERR(p) due to collision"}, {0xc01, "PM: signature register - device-to-host FISes"}, {0xc02, "PM: corrupts CRC propagation of device-to-host FISes"}, {0x0, NULL}, /* end marker */ /* M(andatory) */ }; static void usage() { fprintf(stderr, "Usage: " "sg_sat_phy_event [--ck_cond] [--extend] [--help] [--hex] " "[--ignore]\n" " [--len=16|12] [--raw] [--reset] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --ck_cond|-c sets ck_cond bit in cdb (def: 0)\n" " --extend|-e sets extend bit in cdb (def: 0)\n" " --help|-h print this usage message then exit\n" " --hex|-H output response in hex bytes, use twice for\n" " hex words\n" " --ignore|-i ignore identifier names, output id value " "instead\n" " --len=16|12 | -l 16|12 cdb length: 16 or 12 bytes " "(default: 16)\n" " --raw|-r output response in binary to stdout\n" " --reset|-R reset counters (after read)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n\n" "Sends an ATA READ LOG EXT command via a SAT pass through to " "fetch\nlog page 11h which contains SATA phy event counters\n"); } static const char * find_phy_desc(int id) { const struct phy_event_t * pep; for (pep = phy_event_arr; pep->desc; ++pep) { if ((id & 0xfff) == pep->id) return pep->desc; } return NULL; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* ATA READ LOG EXT command [2Fh, PIO data-in] */ /* N.B. "log_addr" is the log page number, "page_in_log" is usually zero */ static int 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, int ck_cond, int extend, int do_hex, int do_raw, int verbose) { int ok, res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> device's LB size */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks (if t_type=0) */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); ok = 0; if (SAT_ATA_PASS_THROUGH16_LEN == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[3] = (feature >> 8) & 0xff; /* feature(15:8) */ aptCmdBlk[4] = feature & 0xff; /* feature(7:0) */ aptCmdBlk[5] = (blk_count >> 8) & 0xff; /* sector_count(15:8) */ aptCmdBlk[6] = blk_count & 0xff; /* sector_count(7:0) */ aptCmdBlk[8] = log_addr & 0xff; /* lba_low(7:0) == LBA(7:0) */ aptCmdBlk[9] = (page_in_log >> 8) & 0xff; /* lba_mid(15:8) == LBA(39:32) */ aptCmdBlk[10] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */ aptCmdBlk[14] = ATA_READ_LOG_EXT; aptCmdBlk[1] = (multiple_count << 5) | (protocol << 1) | extend; aptCmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, aptCmdBlk, cdb_len, DEF_TIMEOUT, resp, NULL /* doutp */, mx_resp_len, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ apt12CmdBlk[3] = feature & 0xff; /* feature(7:0) */ apt12CmdBlk[4] = blk_count & 0xff; /* sector_count(7:0) */ apt12CmdBlk[5] = log_addr & 0xff; /* lba_low(7:0) == LBA(7:0) */ apt12CmdBlk[6] = page_in_log & 0xff; /* lba_mid(7:0) == LBA(15:8) */ apt12CmdBlk[9] = ATA_READ_LOG_EXT; apt12CmdBlk[1] = (multiple_count << 5) | (protocol << 1); apt12CmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, cdb_len, DEF_TIMEOUT, resp, NULL /* doutp */, mx_resp_len, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } if (0 == res) { ok = 1; if (verbose > 2) fprintf(stderr, "command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) sg_print_sense("ATA pass through", sense_buffer, sb_sz, ((verbose > 2) ? 1 : 0)); if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d) not " "supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), bad " "field in cdb\n", cdb_len); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (verbose) fprintf(stderr, "did not find ATA Return " "(sense) Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), Unit Attention " "detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), device not " "ready\n", cdb_len); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), medium or " "hardware error\n", cdb_len); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { fprintf(stderr, "Aborted command: protection " "information\n"); return SG_LIB_CAT_PROTECTION; } else { fprintf(stderr, "Aborted command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: fprintf(stderr, "ATA PASS-THROUGH (%d): data protect, read " "only media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), some sense " "data, use '-v' for more information\n", cdb_len); return SG_LIB_CAT_SENSE; } } else { fprintf(stderr, "CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { fprintf(stderr, "expected descriptor sense format, response " "code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { fprintf(stderr, "SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { fprintf(stderr, "Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { fprintf(stderr, "ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) fprintf(stderr, " try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) fprintf(stderr, "Seem to have got ATA Result Descriptor but " "it was not indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { fprintf(stderr, "error indication in returned FIS: aborted " "command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } ok = 1; } if (ok) { /* output result if ok and --hex or --raw given */ if (do_raw) dStrRaw((const char *)resp, mx_resp_len); else if (1 == do_hex) dStrHex((const char *)resp, mx_resp_len, 0); else if (do_hex > 1) dWordHex((const unsigned short *)resp, mx_resp_len / 2, 0, sg_is_big_endian()); } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, k, j, res, id, len, vendor; char * device_name = 0; char ebuff[EBUFF_SZ]; unsigned char inBuff[READ_LOG_EXT_RESPONSE_LEN]; int cdb_len = 16; int hex = 0; int ignore = 0; int raw = 0; int reset = 0; int verbose = 0; int ck_cond = 0; /* set to 1 to read register(s) back */ int extend = 0; int ret = 0; uint64_t ull; const char * cp; memset(inBuff, 0, sizeof(inBuff)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "cehHil:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': ++ck_cond; break; case 'e': ++extend; break; case 'h': case '?': usage(); exit(0); case 'H': ++hex; break; case 'i': ++ignore; break; case 'l': cdb_len = sg_get_num(optarg); if (! ((cdb_len == 12) || (cdb_len == 16))) { fprintf(stderr, "argument to '--len' should be 12 or 16\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++raw; break; case 'R': ++reset; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); exit(0); default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (0 == device_name) { fprintf(stderr, "no DEVICE name detected\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = open(device_name, O_RDWR)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_sat_phy_event: error opening file: %s", device_name); perror(ebuff); return SG_LIB_FILE_ERROR; } ret = do_read_log_ext(sg_fd, SATA_PHY_EVENT_LPAGE, 0 /* page_in_log */, (reset ? 1 : 0) /* feature */, 1 /* blk_count */, inBuff, READ_LOG_EXT_RESPONSE_LEN, cdb_len, ck_cond, extend, hex, raw, verbose); if ((0 == ret) && (0 == hex) && (0 == raw)) { printf("SATA phy event counters:\n"); for (k = 4; k < 512; k += (len + 2)) { id = (inBuff[k + 1] << 8) + inBuff[k]; if (0 == id) break; len = ((id >> 12) & 0x7) * 2; vendor = !!(id & 0x8000); id = id & 0xfff; ull = 0; for (j = len - 1; j >= 0; --j) { if (j < (len - 1)) ull <<= 8; ull |= inBuff[k + 2 + j]; } cp = NULL; if ((0 == vendor) && (0 == ignore)) cp = find_phy_desc(id); if (cp) printf(" %s: %" PRIu64 "\n", cp, ull); else printf(" id=0x%x, vendor=%d, data_len=%d, " "val=%" PRIu64 "\n", id, vendor, len, ull); } } res = close(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_opcodes.c0000664000175000017500000010431612404322612015431 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2004-2014 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. This program outputs information provided by a SCSI REPORT SUPPORTED OPERATION CODES [0xa3/0xc] and REPORT SUPPORTED TASK MANAGEMENT FUNCTIONS [0xa3/0xd] commands. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" static const char * version_str = "0.42 20140904"; /* spc4r37 */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_TIMEOUT_SECS 60 #define SG_MAINTENANCE_IN 0xa3 #define RSOC_SA 0xc #define RSTMF_SA 0xd #define RSOC_CMD_LEN 12 #define RSTMF_CMD_LEN 12 #define MX_ALLOC_LEN 8192 #define NAME_BUFF_SZ 128 static int peri_type = 0; /* ugly but not easy to pass to alpha compare */ static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode, int rq_servact, void * resp, int mx_resp_len, int noisy, int verbose); static int do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len, int noisy, int verbose); static struct option long_options[] = { {"alpha", 0, 0, 'a'}, {"compact", 0, 0, 'c'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"mask", 0, 0, 'm'}, {"no-inquiry", 0, 0, 'n'}, {"new", 0, 0, 'N'}, {"opcode", 1, 0, 'o'}, {"old", 0, 0, 'O'}, {"raw", 0, 0, 'r'}, {"rctd", 0, 0, 'R'}, {"repd", 0, 0, 'q'}, {"sa", 1, 0, 's'}, {"tmf", 0, 0, 't'}, {"unsorted", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_alpha; int do_compact; int do_help; int do_hex; int no_inquiry; int do_mask; int do_opcode; int do_raw; int do_rctd; int do_repd; int do_servact; int do_verbose; int do_version; int do_unsorted; int do_taskman; const char * device_name; int opt_new; }; static void usage() { fprintf(stderr, "Usage: sg_opcodes [--alpha] [--compact] [--help] [--hex] " "[--mask]\n" " [--no-inquiry] [--opcode=OP[,SA]] [--raw] " "[--rctd]\n" " [--repd] [--sa=SA] [--tmf] [--unsorted] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --alpha|-a output list of operation codes sorted " "alphabetically\n" " --compact|-c more compact output\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex\n" " --mask|-m and show cdb usage data (a mask) when " "all listed\n" " --no-inquiry|-n don't output INQUIRY information\n" " --opcode=OP|-o OP first byte of command to query\n" " (decimal, prefix with '0x' for hex)\n" " --opcode=OP,SA|-o OP,SA opcode (OP) and service action " "(SA)\n" " (decimal, each prefix with '0x' for " "hex)\n" " --raw|-r output response in binary to stdout\n" " --rctd|-R set RCTD (return command timeout " "descriptor) bit\n" " --repd|-q set Report Extended Parameter Data bit, " "with --tmf\n" " --sa=SA|-s SA service action in addition to opcode\n" " (decimal, prefix with '0x' for hex)\n" " --tmf|-t output list of supported task management " "functions\n" " --unsorted|-u output list of operation codes as is\n" " (def: sort by opcode (then service " "action))\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n\n" "Performs a SCSI REPORT SUPPORTED OPERATION CODES or a REPORT " "SUPPORTED\nTASK MANAGEMENT FUNCTIONS command.\n"); } static void usage_old() { fprintf(stderr, "Usage: sg_opcodes [-a] [-c] [-H] [-m] [-n] [-o=OP] [-q] [-r] " "[-R] [-s=SA]\n" " [-t] [-u] [-v] [-V] DEVICE\n" " where:\n" " -a output list of operation codes sorted " "alphabetically\n" " -c more compact output\n" " -H print response in hex\n" " -m and show cdb usage data (a mask) when all listed\n" " -n don't output INQUIRY information\n" " -o=OP first byte of command to query (in hex)\n" " -q set REPD bit for tmf_s\n" " -r output response in binary to stdout\n" " -R set RCTD (return command timeout " "descriptor) bit\n" " -s=SA in addition to opcode (in hex)\n" " -t output list of supported task management functions\n" " -u output list of operation codes as is (unsorted)\n" " -v verbose\n" " -V output version string\n" " -? output this usage message\n\n" "Performs a SCSI REPORT SUPPORTED OPERATION CODES (or a REPORT " "TASK MANAGEMENT\nFUNCTIONS) command\n"); } static int process_cl_new(struct opts_t * optsp, int argc, char * argv[]) { int c, n; char * cp; char b[32]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "achHmnNo:OqrRs:tuvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++optsp->do_alpha; break; case 'c': ++optsp->do_compact; break; case 'h': case '?': ++optsp->do_help; break; case 'H': ++optsp->do_hex; break; case 'm': ++optsp->do_mask; break; case 'n': ++optsp->no_inquiry; break; case 'N': break; /* ignore */ case 'o': if (strlen(optarg) >= (sizeof(b) - 1)) { fprintf(stderr, "argument to '--opcode' too long\n"); return SG_LIB_SYNTAX_ERROR; } cp = strchr(optarg, ','); if (cp) { memset(b, 0, sizeof(b)); strncpy(b, optarg, cp - optarg); n = sg_get_num(b); if ((n < 0) || (n > 255)) { fprintf(stderr, "bad OP argument to '--opcode'\n"); return SG_LIB_SYNTAX_ERROR; } optsp->do_opcode = n; n = sg_get_num(cp + 1); if ((n < 0) || (n > 0xffff)) { fprintf(stderr, "bad SA argument to '--opcode'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } optsp->do_servact = n; } else { n = sg_get_num(optarg); if ((n < 0) || (n > 255)) { fprintf(stderr, "bad argument to '--opcode'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } optsp->do_opcode = n; } break; case 'O': optsp->opt_new = 0; return 0; case 'q': ++optsp->do_repd; break; case 'r': ++optsp->do_raw; break; case 'R': ++optsp->do_rctd; break; case 's': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { fprintf(stderr, "bad argument to '--sa'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } optsp->do_servact = n; break; case 't': ++optsp->do_taskman; break; case 'u': ++optsp->do_unsorted; 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, n, num; 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 'a': ++optsp->do_alpha; break; case 'c': ++optsp->do_compact; break; case 'H': ++optsp->do_hex; break; case 'm': ++optsp->do_mask; break; case 'n': ++optsp->no_inquiry; break; case 'N': optsp->opt_new = 1; return 0; case 'O': break; case 'q': ++optsp->do_repd; break; case 'R': ++optsp->do_rctd; break; case 't': ++optsp->do_taskman; break; case 'u': ++optsp->do_unsorted; break; case 'v': ++optsp->do_verbose; break; case 'V': ++optsp->do_version; break; case 'h': case '?': ++optsp->do_help; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("o=", cp, 2)) { num = sscanf(cp + 2, "%x", (unsigned int *)&n); if ((1 != num) || (n > 255)) { fprintf(stderr, "Bad number after 'o=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } optsp->do_opcode = n; } else if (0 == strncmp("s=", cp, 2)) { num = sscanf(cp + 2, "%x", (unsigned int *)&n); if (1 != num) { fprintf(stderr, "Bad number after 's=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } optsp->do_servact = n; } 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 (NULL == 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; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* returns -1 when left < right, 0 when left == right, else returns 1 */ static int opcode_num_compare(const void * left, const void * right) { const unsigned char * ll = *(unsigned char **)left; const unsigned char * rr = *(unsigned char **)right; int l_serv_act = 0; int r_serv_act = 0; int l_opc, r_opc; if (NULL == ll) return -1; if (NULL == rr) return -1; l_opc = ll[0]; if (ll[5] & 1) l_serv_act = ((ll[2] << 8) | ll[3]); r_opc = rr[0]; if (rr[5] & 1) r_serv_act = ((rr[2] << 8) | rr[3]); if (l_opc < r_opc) return -1; if (l_opc > r_opc) return 1; if (l_serv_act < r_serv_act) return -1; if (l_serv_act > r_serv_act) return 1; return 0; } /* returns -1 when left < right, 0 when left == right, else returns 1 */ static int opcode_alpha_compare(const void * left, const void * right) { const unsigned char * ll = *(unsigned char **)left; const unsigned char * rr = *(unsigned char **)right; int l_serv_act = 0; int r_serv_act = 0; char l_name_buff[NAME_BUFF_SZ]; char r_name_buff[NAME_BUFF_SZ]; int l_opc, r_opc; if (NULL == ll) return -1; if (NULL == rr) return -1; l_opc = ll[0]; if (ll[5] & 1) l_serv_act = ((ll[2] << 8) | ll[3]); l_name_buff[0] = '\0'; sg_get_opcode_sa_name(l_opc, l_serv_act, peri_type, NAME_BUFF_SZ, l_name_buff); r_opc = rr[0]; if (rr[5] & 1) r_serv_act = ((rr[2] << 8) | rr[3]); r_name_buff[0] = '\0'; sg_get_opcode_sa_name(r_opc, r_serv_act, peri_type, NAME_BUFF_SZ, r_name_buff); return strncmp(l_name_buff, r_name_buff, NAME_BUFF_SZ); } static void list_all_codes(unsigned char * rsoc_buff, int rsoc_len, struct opts_t * op, int sg_fd) { int k, j, m, cd_len, serv_act, len, sa_v, opcode, res; unsigned int to; unsigned char * ucp; char name_buff[NAME_BUFF_SZ]; char sa_buff[8]; unsigned char ** sort_arr = NULL; cd_len = ((rsoc_buff[0] << 24) | (rsoc_buff[1] << 16) | (rsoc_buff[2] << 8) | rsoc_buff[3]); if (cd_len > (rsoc_len - 4)) { printf("sg_opcodes: command data length=%d, allocation=%d; " "truncate\n", cd_len, rsoc_len - 4); cd_len = ((rsoc_len - 4) / 8) * 8; } if (0 == cd_len) { printf("sg_opcodes: no commands to display\n"); return; } if (op->do_rctd) { if (op->do_compact) { printf("\nOpcode,sa Nominal Recommended Name\n"); printf( " (hex) timeout timeout(sec) \n"); printf("-----------------------------------------------" "---------\n"); } else { printf("\nOpcode Service CDB Nominal Recommended Name\n"); printf( "(hex) action(h) size timeout timeout(sec) \n"); printf("-------------------------------------------------------" "---------\n"); } } else { if (op->do_compact) { printf("\nOpcode,sa Name\n"); printf( " (hex) \n"); printf("---------------------------------------\n"); } else { printf("\nOpcode Service CDB Name\n"); printf( "(hex) action(h) size \n"); printf("-----------------------------------------------\n"); } } /* SPC-4 does _not_ require any ordering of opcodes in the response */ if (! op->do_unsorted) { sort_arr = (unsigned char **)malloc(cd_len * sizeof(unsigned char *)); if (NULL == sort_arr) { printf("sg_opcodes: no memory to sort operation codes, " "try '-u'\n"); return; } memset(sort_arr, 0, cd_len * sizeof(unsigned char *)); ucp = rsoc_buff + 4; for (k = 0, j = 0; k < cd_len; ++j, k += len, ucp += len) { sort_arr[j] = ucp; len = (ucp[5] & 0x2) ? 20 : 8; } qsort(sort_arr, j, sizeof(unsigned char *), (op->do_alpha ? opcode_alpha_compare : opcode_num_compare)); } for (k = 0, j = 0; k < cd_len; ++j, k += len) { ucp = op->do_unsorted ? (rsoc_buff + 4 + k) : sort_arr[j]; len = (ucp[5] & 0x2) ? 20 : 8; opcode = ucp[0]; sa_v = ucp[5] & 1; serv_act = 0; if (sa_v) { serv_act = ((ucp[2] << 8) | ucp[3]); sg_get_opcode_sa_name(opcode, serv_act, peri_type, NAME_BUFF_SZ, name_buff); if (op->do_compact) snprintf(sa_buff, sizeof(sa_buff), "%-4x", serv_act); else snprintf(sa_buff, sizeof(sa_buff), "%4x", serv_act); } else { sg_get_opcode_name(opcode, peri_type, NAME_BUFF_SZ, name_buff); memset(sa_buff, ' ', sizeof(sa_buff)); } if (op->do_rctd) { if (ucp[5] & 0x2) { if (op->do_compact) printf(" %.2x%c%.4s", opcode, (sa_v ? ',' : ' '), sa_buff); else printf(" %.2x %.4s %3d", opcode, sa_buff, ((ucp[6] << 8) | ucp[7])); to = ((unsigned int)ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) + ucp[15]; if (0 == to) printf(" -"); else printf(" %8u", to); to = ((unsigned int)ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) + ucp[19]; if (0 == to) printf(" -"); else printf(" %8u", to); printf(" %s\n", name_buff); } else if (op->do_compact) printf(" %.2x%c%.4s %s\n", opcode, (sa_v ? ',' : ' '), sa_buff, name_buff); else printf(" %.2x %.4s %3d " "%s\n", opcode, sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff); } else if (op->do_compact) printf(" %.2x%c%.4s %s\n", ucp[0], (sa_v ? ',' : ' '), sa_buff, name_buff); else printf(" %.2x %.4s %3d %s\n", ucp[0], sa_buff, ((ucp[6] << 8) | ucp[7]), name_buff); if (op->do_mask) { int cdb_sz; unsigned char b[64]; memset(b, 0, sizeof(b)); res = do_rsoc(sg_fd, 0, (sa_v ? 2 : 1), opcode, serv_act, b, sizeof(b), 1, op->do_verbose); if (0 == res) { cdb_sz = (b[2] << 8) + b[3]; if ((cdb_sz > 0) && (cdb_sz <= 80)) { if (op->do_compact) printf(" usage: "); else printf(" cdb usage: "); for (m = 0; m < cdb_sz; ++m) printf("%.2x ", b[4 + m]); printf("\n"); } } } } if (sort_arr) free(sort_arr); } static void decode_cmd_to_descriptor(unsigned char * dp, int max_b_len, char * b) { int len; unsigned int to; if ((max_b_len < 2) || (NULL == dp)) return; b[max_b_len - 1] = '\0'; --max_b_len; len = (dp[0] << 8) + dp[1]; if (10 != len) { snprintf(b, max_b_len, "command timeout descriptor length %d " "(expect 10)", len); return; } to = ((unsigned int)dp[4] << 24) + (dp[5] << 16) + (dp[6] << 8) + dp[7]; if (0 == to) snprintf(b, max_b_len, "no nominal timeout, "); else snprintf(b, max_b_len, "nominal timeout: %u secs, ", to); len = strlen(b); max_b_len -= len; b += len; to = ((unsigned int)dp[8] << 24) + (dp[9] << 16) + (dp[10] << 8) + dp[11]; if (0 == to) snprintf(b, max_b_len, "no recommended timeout"); else snprintf(b, max_b_len, "recommended timeout: %u secs", to); return; } static void list_one(unsigned char * rsoc_buff, int cd_len, int rep_opts, struct opts_t * op) { int k; char name_buff[NAME_BUFF_SZ]; unsigned char * ucp; const char * cp; int v = 0; printf("\n Opcode=0x%.2x", op->do_opcode); if (rep_opts > 1) printf(" Service_action=0x%.4x", op->do_servact); printf("\n"); sg_get_opcode_sa_name(((op->do_opcode > 0) ? op->do_opcode : 0), ((op->do_servact > 0) ? op->do_servact : 0), peri_type, NAME_BUFF_SZ, name_buff); printf(" Command_name: %s\n", name_buff); switch((int)(rsoc_buff[1] & 7)) { case 0: cp = "not currently available"; break; case 1: cp = "NOT supported"; break; case 3: cp = "supported [conforming to SCSI standard]"; v = 1; break; case 5: cp = "supported [in a vendor specific manner]"; v = 1; break; default: snprintf(name_buff, NAME_BUFF_SZ, "support reserved [0x%x]", rsoc_buff[1] & 7); cp = name_buff; break; } printf(" Command %s\n", cp); if (v) { printf(" Usage data: "); ucp = rsoc_buff + 4; for (k = 0; k < cd_len; ++k) printf("%.2x ", ucp[k]); printf("\n"); } if (0x80 & rsoc_buff[1]) { /* CTDP */ ucp = rsoc_buff + 4 + cd_len; decode_cmd_to_descriptor(ucp, NAME_BUFF_SZ, name_buff); printf(" %s\n", name_buff); } } int main(int argc, char * argv[]) { int sg_fd, cd_len, res, len; unsigned char rsoc_buff[MX_ALLOC_LEN]; int rep_opts = 0; const char * cp; char buff[48]; char b[80]; struct sg_simple_inquiry_resp inq_resp; const char * op_name; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->do_opcode = -1; op->do_servact = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { fprintf(stderr, "No DEVICE argument given\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if ((-1 != op->do_servact) && (-1 == op->do_opcode)) { fprintf(stderr, "When '-s' is chosen, so must '-o' be chosen\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (op->do_unsorted && op->do_alpha) fprintf(stderr, "warning: unsorted ('-u') and alpha ('-a') options " "chosen, ignoring alpha\n"); if (op->do_taskman && ((-1 != op->do_opcode) || op->do_alpha || op->do_unsorted)) { fprintf(stderr, "warning: task management functions ('-t') chosen " "so alpha ('-a'),\n unsorted ('-u') and opcode " "('-o') options ignored\n"); } op_name = op->do_taskman ? "Report supported task management functions" : "Report supported operation codes"; if (op->do_opcode < 0) { if ((sg_fd = scsi_pt_open_device(op->device_name, 1 /* RO */, op->do_verbose)) < 0) { fprintf(stderr, "sg_opcodes: error opening file (ro): %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, op->do_verbose)) { peri_type = inq_resp.peripheral_type; if (! (op->do_raw || op->no_inquiry)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } } else { fprintf(stderr, "sg_opcodes: %s doesn't respond to a SCSI " "INQUIRY\n", op->device_name); return SG_LIB_CAT_OTHER; } res = scsi_pt_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); return SG_LIB_FILE_ERROR; } } if ((sg_fd = scsi_pt_open_device(op->device_name, 0 /* RW */, op->do_verbose)) < 0) { fprintf(stderr, "sg_opcodes: error opening file (rw): %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->do_opcode >= 0) rep_opts = ((op->do_servact >= 0) ? 2 : 1); memset(rsoc_buff, 0, sizeof(rsoc_buff)); if (op->do_taskman) res = do_rstmf(sg_fd, op->do_repd, rsoc_buff, (op->do_repd ? 16 : 4), 1, op->do_verbose); else res = do_rsoc(sg_fd, op->do_rctd, rep_opts, op->do_opcode, op->do_servact, rsoc_buff, sizeof(rsoc_buff), 1, op->do_verbose); if (res) { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); fprintf(stderr, "%s: %s\n", op_name, b); goto err_out; } if (op->do_taskman) { if (op->do_raw) { dStrRaw((const char *)rsoc_buff, (op->do_repd ? 16 : 4)); goto err_out; } printf("\nTask Management Functions supported by device:\n"); if (op->do_hex) { dStrHex((const char *)rsoc_buff, (op->do_repd ? 16 : 4), 1); goto err_out; } if (rsoc_buff[0] & 0x80) printf(" Abort task\n"); if (rsoc_buff[0] & 0x40) printf(" Abort task set\n"); if (rsoc_buff[0] & 0x20) printf(" Clear ACA\n"); if (rsoc_buff[0] & 0x10) printf(" Clear task set\n"); if (rsoc_buff[0] & 0x8) printf(" Logical unit reset\n"); if (rsoc_buff[0] & 0x4) printf(" Query task\n"); if (rsoc_buff[0] & 0x2) printf(" Target reset\n"); if (rsoc_buff[0] & 0x1) printf(" Wakeup\n"); if (rsoc_buff[1] & 0x4) printf(" Query asynchronous event\n"); if (rsoc_buff[1] & 0x2) printf(" Query task set\n"); if (rsoc_buff[1] & 0x1) printf(" I_T nexus reset\n"); if (op->do_repd) { if (rsoc_buff[3] < 0xc) { fprintf(stderr, "when REPD given, byte 3 of response " "should be >= 12\n"); res = SG_LIB_CAT_OTHER; goto err_out; } else printf(" Extended parameter data:\n"); printf(" TMFTMOV=%d\n", !!(rsoc_buff[4] & 0x1)); printf(" ATTS=%d\n", !!(rsoc_buff[6] & 0x80)); printf(" ATSTS=%d\n", !!(rsoc_buff[6] & 0x40)); printf(" CACATS=%d\n", !!(rsoc_buff[6] & 0x20)); printf(" CTSTS=%d\n", !!(rsoc_buff[6] & 0x10)); printf(" LURTS=%d\n", !!(rsoc_buff[6] & 0x8)); printf(" QTTS=%d\n", !!(rsoc_buff[6] & 0x4)); printf(" QAETS=%d\n", !!(rsoc_buff[7] & 0x4)); printf(" QTSTS=%d\n", !!(rsoc_buff[7] & 0x2)); printf(" ITNRTS=%d\n", !!(rsoc_buff[7] & 0x1)); printf(" tmf long timeout: %d (100 ms units)\n", (rsoc_buff[8] << 24) + (rsoc_buff[9] << 16) + (rsoc_buff[10] << 8) + rsoc_buff[11]); printf(" tmf short timeout: %d (100 ms units)\n", (rsoc_buff[12] << 24) + (rsoc_buff[13] << 16) + (rsoc_buff[14] << 8) + rsoc_buff[15]); } } else if (0 == rep_opts) { /* list all supported operation codes */ len = ((rsoc_buff[0] << 24) | (rsoc_buff[1] << 16) | (rsoc_buff[2] << 8) | rsoc_buff[3]) + 4; if (len > (int)sizeof(rsoc_buff)) len = sizeof(rsoc_buff); if (op->do_raw) { dStrRaw((const char *)rsoc_buff, len); goto err_out; } if (op->do_hex) { dStrHex((const char *)rsoc_buff, len, 1); goto err_out; } list_all_codes(rsoc_buff, sizeof(rsoc_buff), op, sg_fd); } else { /* asked about specific command */ cd_len = ((rsoc_buff[2] << 8) | rsoc_buff[3]); len = cd_len + 4; if (len > (int)sizeof(rsoc_buff)) len = sizeof(rsoc_buff); if (op->do_raw) { dStrRaw((const char *)rsoc_buff, len); goto err_out; } if (op->do_hex) { dStrHex((const char *)rsoc_buff, len, 1); goto err_out; } list_one(rsoc_buff, cd_len, rep_opts, op); } res = 0; err_out: scsi_pt_close_device(sg_fd); return res; } static int do_rsoc(int sg_fd, int rctd, int rep_opts, int rq_opcode, int rq_servact, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rsocCmdBlk[RSOC_CMD_LEN] = {SG_MAINTENANCE_IN, RSOC_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (rctd) rsocCmdBlk[2] |= 0x80; if (rep_opts) rsocCmdBlk[2] |= (rep_opts & 0x7); if (rq_opcode > 0) rsocCmdBlk[3] = (rq_opcode & 0xff); if (rq_servact > 0) { rsocCmdBlk[4] = (unsigned char)((rq_servact >> 8) & 0xff); rsocCmdBlk[5] = (unsigned char)(rq_servact & 0xff); } rsocCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff); rsocCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff); rsocCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff); rsocCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { fprintf(stderr, " Report Supported Operation Codes cmd: "); for (k = 0; k < RSOC_CMD_LEN; ++k) fprintf(stderr, "%02x ", rsocCmdBlk[k]); fprintf(stderr, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Report Supported Operation Codes: out " "of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rsocCmdBlk, sizeof(rsocCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT_SECS, verbose); ret = sg_cmds_process_resp(ptvp, "Report Supported Operation Codes", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } static int do_rstmf(int sg_fd, int repd, void * resp, int mx_resp_len, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rstmfCmdBlk[RSTMF_CMD_LEN] = {SG_MAINTENANCE_IN, RSTMF_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (repd) rstmfCmdBlk[2] = 0x80; rstmfCmdBlk[6] = (unsigned char)((mx_resp_len >> 24) & 0xff); rstmfCmdBlk[7] = (unsigned char)((mx_resp_len >> 16) & 0xff); rstmfCmdBlk[8] = (unsigned char)((mx_resp_len >> 8) & 0xff); rstmfCmdBlk[9] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { fprintf(stderr, " Report Supported Task Management Functions " "cmd: "); for (k = 0; k < RSTMF_CMD_LEN; ++k) fprintf(stderr, "%02x ", rstmfCmdBlk[k]); fprintf(stderr, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Report Supported Task Management " "Functions: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rstmfCmdBlk, sizeof(rstmfCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT_SECS, verbose); ret = sg_cmds_process_resp(ptvp, "Report Supported Task management " "functions", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } sg3_utils-1.40/src/sg_verify.c0000664000175000017500000003347012335513125015307 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program for the Linux OS SCSI subsystem. * * This program issues the SCSI VERIFY(10) or VERIFY(16) command to the given * SCSI block device. * * N.B. This utility should, but doesn't, check the logical block size with * the SCSI READ CAPACITY command. It is up to the user to make sure that * the count of blocks requested and the number of bytes transferred (when * BYTCHK>0) are "in sync". That caclculation is somewhat complicated by * the possibility of protection data (DIF). */ static const char * version_str = "1.21 20140516"; /* sbc4r01 */ #define ME "sg_verify: " #define EBUFF_SZ 256 static struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"bpc", required_argument, 0, 'b'}, {"bytchk", required_argument, 0, 'B'}, {"count", required_argument, 0, 'c'}, {"dpo", no_argument, 0, 'd'}, {"ebytchk", required_argument, 0, 'E'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"nbo", required_argument, 0, 'n'}, {"quiet", no_argument, 0, 'q'}, {"readonly", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"vrprotect", required_argument, 0, 'P'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_verify [--16] [--bpc=BPC] [--count=COUNT] [--dpo] " "[--ebytchk=BCH]\n" " [--group=GN] [--help] [--in=IF] " "[--lba=LBA] [--ndo=NDO]\n" " [--quiet] [--readonly] [--verbose] " "[--version]\n" " [--vrprotect=VRP] DEVICE\n" " where:\n" " --16|-S use VERIFY(16) (def: use " "VERIFY(10) )\n" " --bpc=BPC|-b BPC max blocks per verify command " "(def: 128)\n" " --count=COUNT|-c COUNT count of blocks to verify " "(def: 1).\n" " If BCH=3 then COUNT must " "be 1 .\n" " --dpo|-d disable page out (cache retention " "priority)\n" " --ebytchk=BCH|-E BCH sets BYTCHK value, either 1, 2 " "or 3 (def: 0).\n" " BCH overrides BYTCHK=1 set by " "'--ndo='. If\n" " BCH is 3 then NDO must be the LBA " "size\n" " (plus protection size if DIF " "active)\n" " --group=GN|-g GN set group number field to GN (def: 0)\n" " --help|-h print out usage message\n" " --in=IF|-i IF input from file called IF (def: " "stdin)\n" " only active if --bytchk=N given\n" " --lba=LBA|-l LBA logical block address to start " "verify (def: 0)\n" " --ndo=NDO|-n NDO NDO is number of bytes placed in " "data-out buffer.\n" " These are fetched from IF (or " "stdin) and used\n" " to verify the device data against. " "Forces\n" " --bpc=COUNT. Sets BYTCHK (byte check) " "to 1\n" " --quiet|-q suppress miscompare report to stderr, " "still\n" " causes an exit status of 14\n" " --readonly|-r open DEVICE read-only (def: open it " "read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --vrprotect=VRP|-P VRP set vrprotect field to VRP " "(def: 0)\n" "Performs one or more SCSI VERIFY(10) or SCSI VERIFY(16) " "commands. sbc3r34\nmade the BYTCHK field two bits wide " "(it was a single bit).\n" ); } int main(int argc, char * argv[]) { int sg_fd, res, c, num, nread, infd; int64_t ll; int dpo = 0; int bytchk = 0; int ndo = 0; char *ref_data = NULL; int vrprotect = 0; int64_t count = 1; int64_t orig_count; int bpc = 128; int bpc_given = 0; int got_stdin = 0; int group = 0; uint64_t lba = 0; uint64_t orig_lba; int quiet = 0; int readonly = 0; int verbose = 0; int verify16 = 0; const char * device_name = NULL; const char * file_name = NULL; const char * vc; int ret = 0; unsigned int info = 0; uint64_t info64 = 0; char ebuff[EBUFF_SZ]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:B:c:dE:g:hi:l:n:P:qrSvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': bpc = sg_get_num(optarg); if (bpc < 1) { fprintf(stderr, "bad argument to '--bpc'\n"); return SG_LIB_SYNTAX_ERROR; } ++bpc_given; break; case 'c': count = sg_get_llnum(optarg); if (count < 0) { fprintf(stderr, "bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = 1; break; case 'E': bytchk = sg_get_num(optarg); if ((bytchk < 1) || (bytchk > 3)) { fprintf(stderr, "bad argument to '--ebytchk'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 31)) { fprintf(stderr, "bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': file_name = optarg; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'n': case 'B': /* undocumented, old --bytchk=NDO option */ ndo = sg_get_num(optarg); if (ndo < 1) { fprintf(stderr, "bad argument to '--ndo'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'P': vrprotect = sg_get_num(optarg); if (-1 == vrprotect) { fprintf(stderr, "bad argument to '--vrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } if ((vrprotect < 0) || (vrprotect > 7)) { fprintf(stderr, "'--vrprotect' requires a value from 0 to " "7 (inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': ++quiet; break; case 'r': ++readonly; break; case 'S': ++verify16; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (ndo > 0) { if (0 == bytchk) bytchk = 1; if (bpc_given && (bpc != count)) fprintf(stderr, "'bpc' argument ignored, using --bpc=%" PRIu64 "\n", count); if (count > 0x7fffffffLL) { fprintf(stderr, "count exceed 31 bits, way too large\n"); return SG_LIB_SYNTAX_ERROR; } if ((3 == bytchk) && (1 != count)) { fprintf(stderr, "count must be 1 when bytchk=3\n"); return SG_LIB_SYNTAX_ERROR; } bpc = (int)count; } else if (bytchk > 0) { fprintf(stderr, "when the 'ebytchk=BCH' option is given, " "then '--bytchk=NDO' must also be given\n"); return SG_LIB_SYNTAX_ERROR; } if ((bpc > 0xffff) && (0 == verify16)) { fprintf(stderr, "'%s' exceeds 65535, so use VERIFY(16)\n", (ndo > 0) ? "count" : "bpc"); ++verify16; } if (((lba + count - 1) > 0xffffffffLLU) && (0 == verify16)) { fprintf(stderr, "'lba' exceed 32 bits, so use VERIFY(16)\n"); ++verify16; } if ((group > 0) && (0 == verify16)) fprintf(stderr, "group number ignored with VERIFY(10) command, " "use the --16 option\n"); orig_count = count; orig_lba = lba; if (ndo > 0) { ref_data = (char *)malloc(ndo); if (NULL == ref_data) { fprintf(stderr, "failed to allocate %d byte buffer\n", ndo); return SG_LIB_FILE_ERROR; } if ((NULL == file_name) || (0 == strcmp(file_name, "-"))) { ++got_stdin; infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { if ((infd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } if (verbose && got_stdin) fprintf(stderr, "about to wait on STDIN\n"); for (nread = 0; nread < ndo; nread += res) { res = read(infd, ref_data + nread, ndo - nread); if (res <= 0) { fprintf(stderr, "reading from %s failed at file offset=%d\n", (got_stdin ? "stdin" : file_name), nread); ret = SG_LIB_FILE_ERROR; goto err_out; } } if (! got_stdin) close(infd); } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto err_out; } vc = verify16 ? "VERIFY(16)" : "VERIFY(10)"; for (; count > 0; count -= bpc, lba += bpc) { num = (count > bpc) ? bpc : count; if (verify16) res = sg_ll_verify16(sg_fd, vrprotect, dpo, bytchk, lba, num, group, ref_data, ndo, &info64, !quiet , verbose); else res = sg_ll_verify10(sg_fd, vrprotect, dpo, bytchk, (unsigned int)lba, num, ref_data, ndo, &info, !quiet, verbose); if (0 != res) { char b[80]; ret = res; switch (res) { case SG_LIB_CAT_ILLEGAL_REQ: fprintf(stderr, "bad field in %s cdb, near lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD: fprintf(stderr, "%s medium or hardware error near " "lba=0x%" PRIx64 "\n", vc, lba); break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: if (verify16) fprintf(stderr, "%s medium or hardware error, reported " "lba=0x%" PRIx64 "\n", vc, info64); else fprintf(stderr, "%s medium or hardware error, reported " "lba=0x%x\n", vc, info); break; case SG_LIB_CAT_MISCOMPARE: if ((0 == quiet) || verbose) fprintf(stderr, "%s reported MISCOMPARE\n", vc); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "%s: %s\n", vc, b); fprintf(stderr, " failed near lba=%" PRIu64 " [0x%" PRIx64 "]\n", lba, lba); break; } break; } } if (verbose && (0 == ret) && (orig_count > 1)) fprintf(stderr, "Verified %" PRId64 " [0x%" PRIx64 "] blocks from " "lba %" PRIu64 " [0x%" PRIx64 "]\n without error\n", orig_count, (uint64_t)orig_count, orig_lba, orig_lba); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } err_out: if (ref_data) free(ref_data); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_stpg.c0000664000175000017500000005327712335513125014767 0ustar douggdougg/* * Copyright (c) 2004-2013 Hannes Reinecke, Christophe Varoqui, Douglas Gilbert * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI command SET TARGET PORT GROUPS * to the given SCSI device. */ static const char * version_str = "1.7 20130730"; #define TGT_GRP_BUFF_LEN 1024 #define MX_ALLOC_LEN (0xc000 + 0x80) #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_OFFLINE 0xe /* SPC-4 rev 9 */ #define TPGS_STATE_TRANSITIONING 0xf /* See also table 306 - Target port group descriptor format in SPC-4 rev 36e */ #ifndef __cplusplus static const unsigned char state_sup_mask[] = { [TPGS_STATE_OPTIMIZED] = 0x01, [TPGS_STATE_NONOPTIMIZED] = 0x02, [TPGS_STATE_STANDBY] = 0x04, [TPGS_STATE_UNAVAILABLE] = 0x08, [TPGS_STATE_OFFLINE] = 0x40, [TPGS_STATE_TRANSITIONING] = 0x80, }; #else // C++ does not support designated initializers static const unsigned char state_sup_mask[] = { 0x1, 0x2, 0x4, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x80, }; #endif /* C or C++ ? */ #define VPD_DEVICE_ID 0x83 #define DEF_VPD_DEVICE_ID_LEN 252 #define MAX_PORT_LIST_ARR_LEN 16 struct tgtgrp { int id; int current; int valid; }; static struct option long_options[] = { {"active", 0, 0, 'a'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"offline", 0, 0, 'l'}, {"optimized", 0, 0, 'o'}, {"raw", 0, 0, 'r'}, {"standby", 0, 0, 's'}, {"state", required_argument, 0, 'S'}, {"tp", required_argument, 0, 't'}, {"unavailable", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_stpg [--active] [--help] [--hex] [--offline] [--optimized] " "[--raw]\n" " [--standby] [--state=S,S...] [--tp=P,P...] " "[--unavailable]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --active|-a set asymm. access state to " "active/non-optimized\n" " --help|-h print out usage message\n" " --hex|-H print out report response in hex, then " "exit\n" " --offline|-l set asymm. access state to offline, takes " "relative\n" " target port id, rather than target port " "group id\n" " --optimized|-o set asymm. access state to " "active/optimized\n" " --raw|-r output report response in binary to " "stdout, then exit\n" " --standby|-s set asymm. access state to standby\n" " --state=S,S.. |-S S,S... list of states (values or " "acronyms)\n" " --tp=P,P.. |-t P,P... list of target port group " "identifiers,\n" " or relative target port " "identifiers\n" " --unavailable|-u set asymm. access state to unavailable\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI SET TARGET PORT GROUPS command\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static int decode_target_port(unsigned char * buff, int len, int *d_id, int *d_tpg) { int c_set, assoc, desig_type, i_len; int off, u; const unsigned char * ucp; const unsigned char * ip; *d_id = -1; *d_tpg = -1; off = -1; while ((u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0) { ucp = buff + off; i_len = ucp[3]; if ((off + i_len + 4) > len) { fprintf(stderr, " VPD page error: designator length longer " "than\n remaining response length=%d\n", (len - off)); return SG_LIB_CAT_MALFORMED; } ip = ucp + 4; c_set = (ucp[0] & 0xf); /* piv = ((ucp[1] & 0x80) ? 1 : 0); */ assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); switch (desig_type) { case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { fprintf(stderr, " << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } *d_id = ((ip[2] << 8) | ip[3]); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { fprintf(stderr, " << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } *d_tpg = ((ip[2] << 8) | ip[3]); break; default: break; } } if (-1 == *d_id || -1 == *d_tpg) { fprintf(stderr, "VPD page error: no target port group information\n"); return SG_LIB_CAT_MALFORMED; } return 0; } static void decode_tpgs_state(const int st) { switch (st) { case TPGS_STATE_OPTIMIZED: printf(" (active/optimized)"); break; case TPGS_STATE_NONOPTIMIZED: printf(" (active/non optimized)"); break; case TPGS_STATE_STANDBY: printf(" (standby)"); break; case TPGS_STATE_UNAVAILABLE: printf(" (unavailable)"); break; case TPGS_STATE_OFFLINE: printf(" (offline)"); break; case TPGS_STATE_TRANSITIONING: printf(" (transitioning between states)"); break; default: printf(" (unknown: 0x%x)", st); break; } } static int transition_tpgs_states(struct tgtgrp *tgtState, int numgrp, int portgroup, int newstate) { int i,oldstate; for ( i = 0; i < numgrp; i++) { if (tgtState[i].id == portgroup) break; } if (i == numgrp) { printf("Portgroup 0x%02x does not exist\n", portgroup); return 1; } if (!( state_sup_mask[newstate] & tgtState[i].valid )) { printf("Portgroup 0x%02x: Invalid state 0x%x\n", portgroup, newstate); return 1; } oldstate = tgtState[i].current; tgtState[i].current = newstate; if (newstate == TPGS_STATE_OPTIMIZED) { /* Switch with current optimized path */ for ( i = 0; i < numgrp; i++) { if (tgtState[i].id == portgroup) continue; if (tgtState[i].current == TPGS_STATE_OPTIMIZED) tgtState[i].current = oldstate; } } else if (oldstate == TPGS_STATE_OPTIMIZED) { /* Enable next path group */ for ( i = 0; i < numgrp; i++) { if (tgtState[i].id == portgroup) continue; if (tgtState[i].current == TPGS_STATE_NONOPTIMIZED) { tgtState[i].current = TPGS_STATE_OPTIMIZED; break; } } } printf("New target port groups:\n"); for (i = 0; i < numgrp; i++) { printf(" target port group id : 0x%x\n", tgtState[i].id); printf(" target port group asymmetric access state : "); printf("0x%02x\n", tgtState[i].current); } return 0; } static void encode_tpgs_states(unsigned char *buff, struct tgtgrp *tgtState, int numgrp) { int i; unsigned char *desc; for (i = 0, desc = buff + 4; i < numgrp; desc += 4, i++) { desc[0] = tgtState[i].current & 0x0f; desc[2] = (tgtState[i].id >> 8) & 0x0f; desc[3] = tgtState[i].id & 0x0f; } } /* Read numbers (up to 32 bits in size) from command line (comma separated */ /* list). Assumed decimal unless prefixed by '0x', '0X' or contains */ /* trailing 'h' or 'H' (which indicate hex). Returns 0 if ok, 1 if error. */ static int build_port_arr(const char * inp, int * port_arr, int * port_arr_len, int max_arr_len) { int in_len, k; const char * lcp; int v; char * cp; if ((NULL == inp) || (NULL == port_arr) || (NULL == port_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *port_arr_len = 0; k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX,"); if (in_len != k) { fprintf(stderr, "build_port_arr: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { v = sg_get_num_nomult(lcp); if (-1 != v) { port_arr[k] = v; cp = (char *)strchr(lcp, ','); if (NULL == cp) break; lcp = cp + 1; } else { fprintf(stderr, "build_port_arr: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *port_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_port_arr: array length exceeded\n"); return 1; } return 0; } /* Read numbers (up to 32 bits in size) from command line (comma separated */ /* list). Assumed decimal unless prefixed by '0x', '0X' or contains */ /* trailing 'h' or 'H' (which indicate hex). Also accepts 'ao' for active */ /* optimized [0], 'an' for active/non-optimized [1], 's' for standby [2], */ /* 'u' for unavailable [3], 'o' for offline [14]. */ /* Returns 0 if ok, 1 if error. */ static int build_state_arr(const char * inp, int * state_arr, int * state_arr_len, int max_arr_len) { int in_len, k, v, try_num; const char * lcp; char * cp; if ((NULL == inp) || (NULL == state_arr) || (NULL == state_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *state_arr_len = 0; k = strspn(inp, "0123456789aAbBcCdDeEfFhHnNoOsSuUxX,"); if (in_len != k) { fprintf(stderr, "build_state_arr: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { try_num = 1; if (isalpha(*lcp)) { try_num = 0; switch (toupper(*lcp)) { case 'A': if ('N' == toupper(*(lcp + 1))) state_arr[k] = 1; else if ('O' == toupper(*(lcp + 1))) state_arr[k] = 0; else try_num = 1; break; case 'O': state_arr[k] = 14; break; case 'S': state_arr[k] = 2; break; case 'U': state_arr[k] = 3; break; default: fprintf(stderr, "build_state_arr: expected 'ao', 'an', 'o', " "'s' or 'u' at pos %d\n", (int)(lcp - inp + 1)); return 1; } } if (try_num) { v = sg_get_num_nomult(lcp); if (((v >= 0) && (v <= 3)) || (14 ==v)) state_arr[k] = v; else if (-1 == v) { fprintf(stderr, "build_state_arr: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } else { fprintf(stderr, "build_state_arr: expect 0,1,2,3 or 14\n"); return 1; } } cp = (char *)strchr(lcp, ','); if (NULL == cp) break; lcp = cp + 1; } *state_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_state_arr: array length exceeded\n"); return 1; } return 0; } int main(int argc, char * argv[]) { int sg_fd, k, off, res, c, report_len, tgt_port_count; unsigned char reportTgtGrpBuff[TGT_GRP_BUFF_LEN]; unsigned char setTgtGrpBuff[TGT_GRP_BUFF_LEN]; unsigned char rsp_buff[MX_ALLOC_LEN + 2]; unsigned char * ucp; struct tgtgrp tgtGrpState[256], *tgtStatePtr; int state = -1; const char * state_arg = NULL; const char * tp_arg = NULL; int hex = 0; int raw = 0; int verbose = 0; int port_arr[MAX_PORT_LIST_ARR_LEN]; int port_arr_len = 0; int state_arr[MAX_PORT_LIST_ARR_LEN]; char b[80]; int state_arr_len = 0; int portgroup = -1; int relport = -1; int numgrp = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ahHloOrsS:t:uvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': state = TPGS_STATE_NONOPTIMIZED; break; case 'h': case '?': usage(); return 0; case 'H': hex = 1; break; case 'l': case 'O': state = TPGS_STATE_OFFLINE; break; case 'o': state = TPGS_STATE_OPTIMIZED; break; case 'r': raw = 1; break; case 's': state = TPGS_STATE_STANDBY; break; case 'S': state_arg = optarg; break; case 't': tp_arg = optarg; break; case 'u': state = TPGS_STATE_UNAVAILABLE; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "Version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (state_arg) { if (build_state_arr(state_arg, state_arr, &state_arr_len, MAX_PORT_LIST_ARR_LEN)) { usage(); return SG_LIB_SYNTAX_ERROR; } } if (tp_arg) { if (build_port_arr(tp_arg, port_arr, &port_arr_len, MAX_PORT_LIST_ARR_LEN)) { usage(); return SG_LIB_SYNTAX_ERROR; } } if ((state >= 0) && (state_arr_len > 0)) { fprintf(stderr, "either use individual state option or '--state=' " "but not both\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((0 == state_arr_len) && (0 == port_arr_len) && (-1 == state)) state = 0; /* default to active/optimized */ if ((1 == state_arr_len) && (0 == port_arr_len) && (-1 == state)) { state = state_arr[0]; state_arr_len = 0; } if (state_arr_len > port_arr_len) { fprintf(stderr, "'state=' list longer than expected\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((port_arr_len > 0) && (0 == state_arr_len)) { if (-1 == state) { fprintf(stderr, "target port list given but no state " "indicated\n"); usage(); return SG_LIB_SYNTAX_ERROR; } state_arr[0] = state; state_arr_len = 1; state = -1; } if ((port_arr_len > 1) && (1 == state_arr_len)) { for (k = 1; k < port_arr_len; ++k) state_arr[k] = state_arr[0]; state_arr_len = port_arr_len; } if (port_arr_len != state_arr_len) { fprintf(stderr, "'state=' and '--tp=' lists mismatched\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == port_arr_len) { res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff, DEF_VPD_DEVICE_ID_LEN, 1, verbose); if (0 == res) { report_len = ((rsp_buff[2] << 8) + rsp_buff[3]) + 4; if (VPD_DEVICE_ID != rsp_buff[1]) { fprintf(stderr, "invalid VPD response; probably a STANDARD " "INQUIRY response\n"); if (verbose) { fprintf(stderr, "First 32 bytes of bad response\n"); dStrHexErr((const char *)rsp_buff, 32, 0); } return SG_LIB_CAT_MALFORMED; } if (report_len > MX_ALLOC_LEN) { fprintf(stderr, "response length too long: %d > %d\n", report_len, MX_ALLOC_LEN); return SG_LIB_CAT_MALFORMED; } else if (report_len > DEF_VPD_DEVICE_ID_LEN) { if (sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rsp_buff, report_len, 1, verbose)) return SG_LIB_CAT_OTHER; } decode_target_port(rsp_buff + 4, report_len - 4, &relport, &portgroup); printf("Device is at port Group 0x%02x, relative port 0x%02x\n", portgroup, relport); } memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff)); /* trunc = 0; */ res = sg_ll_report_tgt_prt_grp2(sg_fd, reportTgtGrpBuff, sizeof(reportTgtGrpBuff), 0, 1, verbose); ret = res; if (0 == res) { report_len = (reportTgtGrpBuff[0] << 24) + (reportTgtGrpBuff[1] << 16) + (reportTgtGrpBuff[2] << 8) + reportTgtGrpBuff[3] + 4; if (report_len > (int)sizeof(reportTgtGrpBuff)) { /* trunc = 1; */ fprintf(stderr, " <id = (ucp[2] << 8) + ucp[3]; tgtStatePtr->current = ucp[0] & 0x0f; tgtStatePtr->valid = ucp[1]; tgt_port_count = ucp[7]; tgtStatePtr++; off = 8 + tgt_port_count * 4; } } else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Report Target Port Groups: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for more information\n"); } if (0 != res) goto err_out; printf("Port group 0x%02x: Set asymmetric access state to", portgroup); decode_tpgs_state(state); printf("\n"); transition_tpgs_states(tgtGrpState, numgrp, portgroup, state); memset(setTgtGrpBuff, 0x0, sizeof(setTgtGrpBuff)); /* trunc = 0; */ encode_tpgs_states(setTgtGrpBuff, tgtGrpState, numgrp); report_len = numgrp * 4 + 4; } else { /* port_arr_len > 0 */ memset(setTgtGrpBuff, 0x0, sizeof(setTgtGrpBuff)); for (k = 0, ucp = setTgtGrpBuff + 4; k < port_arr_len; ++k, ucp +=4) { ucp[0] = state_arr[k] & 0xf; ucp[2] = (port_arr[k] >> 8) & 0xff; ucp[3] = port_arr[k] & 0xff; } report_len = port_arr_len * 4 + 4; } res = sg_ll_set_tgt_prt_grp(sg_fd, setTgtGrpBuff, report_len, 1, verbose); if (0 == res) goto err_out; else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Set Target Port Groups: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for more information\n"); } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_rtpg.c0000664000175000017500000002275012335161436014762 0ustar douggdougg/* * Copyright (c) 2004-2014 Christophe Varoqui and Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program for the Linux OS SCSI subsystem. * * * This program issues the SCSI command REPORT TARGET PORT GROUPS * to the given SCSI device. */ static const char * version_str = "1.19 20140515"; #define REPORT_TGT_GRP_BUFF_LEN 1024 #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_LB_DEPENDENT 0x4 #define TPGS_STATE_OFFLINE 0xe /* SPC-4 rev 9 */ #define TPGS_STATE_TRANSITIONING 0xf #define STATUS_CODE_NOSTATUS 0x0 #define STATUS_CODE_CHANGED_BY_SET 0x1 #define STATUS_CODE_CHANGED_BY_IMPLICIT 0x2 static struct option long_options[] = { {"decode", 0, 0, 'd'}, {"extended", 0, 0, 'e'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"raw", 0, 0, 'r'}, {"readonly", 0, 0, 'R'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_rtpg [--decode] [--extended] [--help] [--hex] [--raw] " "[--readonly]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --decode|-d decode status and asym. access state\n" " --extended|-e use extended header parameter data format\n" " --help|-h print out usage message\n" " --hex|-H print out response in hex\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT TARGET PORT GROUPS command\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static void decode_status(const int st) { switch (st) { case STATUS_CODE_NOSTATUS: printf(" (no status available)"); break; case STATUS_CODE_CHANGED_BY_SET: printf(" (target port asym. state changed by SET TARGET PORT " "GROUPS command)"); break; case STATUS_CODE_CHANGED_BY_IMPLICIT: printf(" (target port asym. state changed by implicit lu " "behaviour)"); break; default: printf(" (unknown status code)"); break; } } static void decode_tpgs_state(const int st) { switch (st) { case TPGS_STATE_OPTIMIZED: printf(" (active/optimized)"); break; case TPGS_STATE_NONOPTIMIZED: printf(" (active/non optimized)"); break; case TPGS_STATE_STANDBY: printf(" (standby)"); break; case TPGS_STATE_UNAVAILABLE: printf(" (unavailable)"); break; case TPGS_STATE_LB_DEPENDENT: printf(" (logical block dependent)"); break; case TPGS_STATE_OFFLINE: printf(" (offline)"); break; case TPGS_STATE_TRANSITIONING: printf(" (transitioning between states)"); break; default: printf(" (unknown)"); break; } } int main(int argc, char * argv[]) { int sg_fd, k, j, off, res, c, report_len, tgt_port_count; unsigned char reportTgtGrpBuff[REPORT_TGT_GRP_BUFF_LEN]; unsigned char * ucp; int decode = 0; int hex = 0; int raw = 0; int o_readonly = 0; int verbose = 0; int extended = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "dehHrRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': decode = 1; break; case 'e': extended = 1; break; case 'h': case '?': usage(); return 0; case 'H': hex = 1; break; case 'r': raw = 1; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "Version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(reportTgtGrpBuff, 0x0, sizeof(reportTgtGrpBuff)); /* trunc = 0; */ res = sg_ll_report_tgt_prt_grp2(sg_fd, reportTgtGrpBuff, sizeof(reportTgtGrpBuff), extended, 1, verbose); ret = res; if (0 == res) { report_len = (reportTgtGrpBuff[0] << 24) + (reportTgtGrpBuff[1] << 16) + (reportTgtGrpBuff[2] << 8) + reportTgtGrpBuff[3] + 4; if (report_len > (int)sizeof(reportTgtGrpBuff)) { /* trunc = 1; */ fprintf(stderr, " <> 4) & 0x07); printf(" target port group asymmetric access state : "); printf("0x%02x", ucp[0] & 0x0f); if (decode) decode_tpgs_state(ucp[0] & 0x0f); printf("\n"); printf(" T_SUP : %d, ", !!(ucp[1] & 0x80)); printf("O_SUP : %d, ", !!(ucp[1] & 0x40)); printf("LBD_SUP : %d, ", !!(ucp[1] & 0x10)); printf("U_SUP : %d, ", !!(ucp[1] & 0x08)); printf("S_SUP : %d, ", !!(ucp[1] & 0x04)); printf("AN_SUP : %d, ", !!(ucp[1] & 0x02)); printf("AO_SUP : %d\n", !!(ucp[1] & 0x01)); printf(" status code : "); printf("0x%02x", ucp[5]); if (decode) decode_status(ucp[5]); printf("\n"); printf(" vendor unique status : "); printf("0x%02x\n", ucp[6]); printf(" target port count : "); tgt_port_count = ucp[7]; printf("%02x\n", tgt_port_count); for (j = 0; j < tgt_port_count * 4; j += 4) { if (0 == j) printf(" Relative target port ids:\n"); printf(" 0x%02x\n", (ucp[8 + j + 2] << 8) + ucp[8 + j + 3]); } off = 8 + j; } } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Report Target Port Groups command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "bad field in Report Target Port Groups cdb " "including unsupported service action\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Report Target Port Groups: %s\n", b); } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_inq_data.c0000664000175000017500000005301612341217414015560 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2014 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. This is an auxiliary file holding data tables for the sg_inq utility. It is mainly based on the SCSI SPC-4 document at http://www.t10.org . */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif /* Assume index is less than 16 */ const char * sg_ansi_version_arr[] = { "no conformance claimed", "SCSI-1", /* obsolete, ANSI X3.131-1986 */ "SCSI-2", /* obsolete, ANSI X3.131-1994 */ "SPC", /* withdrawn */ "SPC-2", "SPC-3", "SPC-4", "SPC-5", "ecma=1, [8h]", "ecma=1, [9h]", "ecma=1, [Ah]", "ecma=1, [Bh]", "reserved [Ch]", "reserved [Dh]", "reserved [Eh]", "reserved [Fh]", }; /* Copy of structure found in sg_inq.c */ struct sg_version_descriptor { int value; const char * name; }; /* table from SPC-4 revision 36 [sorted numerically (from Annex E.9)] */ /* Can also be obtained from : http://www.t10.org/lists/stds.txt 20140517 */ #ifdef SG_SCSI_STRINGS struct sg_version_descriptor sg_version_descriptor_arr[] = { {0x0, "Version Descriptor not supported or No standard identified"}, {0x20, "SAM (no version claimed)"}, {0x3b, "SAM T10/0994-D revision 18"}, {0x3c, "SAM ANSI INCITS 270-1996"}, {0x40, "SAM-2 (no version claimed)"}, {0x54, "SAM-2 T10/1157-D revision 23"}, {0x55, "SAM-2 T10/1157-D revision 24"}, {0x5c, "SAM-2 ANSI INCITS 366-2003"}, {0x5e, "SAM-2 ISO/IEC 14776-412"}, {0x60, "SAM-3 (no version claimed)"}, {0x62, "SAM-3 T10/1561-D revision 7"}, {0x75, "SAM-3 T10/1561-D revision 13"}, {0x76, "SAM-3 T10/1561-D revision 14"}, {0x77, "SAM-3 ANSI INCITS 402-2005"}, {0x80, "SAM-4 (no version claimed)"}, {0x87, "SAM-4 T10/1683-D revision 13"}, {0x8b, "SAM-4 T10/1683-D revision 14"}, {0x90, "SAM-4 ANSI INCITS 447-2008"}, {0x92, "SAM-4 ISO/IEC 14776-414"}, {0xa0, "SAM-5 (no version claimed)"}, {0xa2, "SAM-5 T10/2104-D revision 4"}, {0x120, "SPC (no version claimed)"}, {0x13b, "SPC T10/0995-D revision 11a"}, {0x13c, "SPC ANSI INCITS 301-1997"}, {0x140, "MMC (no version claimed)"}, {0x15b, "MMC T10/1048-D revision 10a"}, {0x15c, "MMC ANSI INCITS 304-1997"}, {0x160, "SCC (no version claimed)"}, {0x17b, "SCC T10/1047-D revision 06c"}, {0x17c, "SCC ANSI INCITS 276-1997"}, {0x180, "SBC (no version claimed)"}, {0x19b, "SBC T10/0996-D revision 08c"}, {0x19c, "SBC ANSI INCITS 306-1998"}, {0x1a0, "SMC (no version claimed)"}, {0x1bb, "SMC T10/0999-D revision 10a"}, {0x1bc, "SMC ANSI INCITS 314-1998"}, {0x1be, "SMC ISO/IEC 14776-351"}, {0x1c0, "SES (no version claimed)"}, {0x1db, "SES T10/1212-D revision 08b"}, {0x1dc, "SES ANSI INCITS 305-1998"}, {0x1dd, "SES T10/1212-D revision 08b w/ Amendment ANSI " "INCITS.305/AM1:2000"}, {0x1de, "SES ANSI INCITS 305-1998 w/ Amendment ANSI " "INCITS.305/AM1:2000"}, {0x1e0, "SCC-2 (no version claimed}"}, {0x1fb, "SCC-2 T10/1125-D revision 04"}, {0x1fc, "SCC-2 ANSI INCITS 318-1998"}, {0x200, "SSC (no version claimed)"}, {0x201, "SSC T10/0997-D revision 17"}, {0x207, "SSC T10/0997-D revision 22"}, {0x21c, "SSC ANSI INCITS 335-2000"}, {0x220, "RBC (no version claimed)"}, {0x238, "RBC T10/1240-D revision 10a"}, {0x23c, "RBC ANSI INCITS 330-2000"}, {0x240, "MMC-2 (no version claimed)"}, {0x255, "MMC-2 T10/1228-D revision 11"}, {0x25b, "MMC-2 T10/1228-D revision 11a"}, {0x25c, "MMC-2 ANSI INCITS 333-2000"}, {0x260, "SPC-2 (no version claimed)"}, {0x267, "SPC-2 T10/1236-D revision 12"}, {0x269, "SPC-2 T10/1236-D revision 18"}, {0x275, "SPC-2 T10/1236-D revision 19"}, {0x276, "SPC-2 T10/1236-D revision 20"}, {0x277, "SPC-2 ANSI INCITS 351-2001"}, {0x278, "SPC-2 ISO/IEC 14776-452"}, {0x280, "OCRW (no version claimed)"}, {0x29e, "OCRW ISO/IEC 14776-381"}, {0x2a0, "MMC-3 (no version claimed)"}, {0x2b5, "MMC-3 T10/1363-D revision 9"}, {0x2b6, "MMC-3 T10/1363-D revision 10g"}, {0x2b8, "MMC-3 ANSI INCITS 360-2002"}, {0x2e0, "SMC-2 (no version claimed)"}, {0x2f5, "SMC-2 T10/1383-D revision 5"}, {0x2fc, "SMC-2 T10/1383-D revision 6"}, {0x2fd, "SMC-2 T10/1383-D revision 7"}, {0x2fe, "SMC-2 ANSI INCITS 382-2004"}, {0x300, "SPC-3 (no version claimed)"}, {0x301, "SPC-3 T10/1416-D revision 7"}, {0x307, "SPC-3 T10/1416-D revision 21"}, {0x30f, "SPC-3 T10/1416-D revision 22"}, {0x312, "SPC-3 T10/1416-D revision 23"}, {0x314, "SPC-3 ANSI INCITS 408-2005"}, {0x316, "SPC-3 ISO/IEC 14776-453"}, {0x320, "SBC-2 (no version claimed)"}, {0x322, "SBC-2 T10/1417-D revision 5a"}, {0x324, "SBC-2 T10/1417-D revision 15"}, {0x33b, "SBC-2 T10/1417-D revision 16"}, {0x33d, "SBC-2 ANSI INCITS 405-2005"}, {0x33e, "SBC-2 ISO/IEC 14776-322"}, {0x340, "OSD (no version claimed)"}, {0x341, "OSD T10/1355-D revision 0"}, {0x342, "OSD T10/1355-D revision 7a"}, {0x343, "OSD T10/1355-D revision 8"}, {0x344, "OSD T10/1355-D revision 9"}, {0x355, "OSD T10/1355-D revision 10"}, {0x356, "OSD ANSI INCITS 400-2004"}, {0x360, "SSC-2 (no version claimed)"}, {0x374, "SSC-2 T10/1434-D revision 7"}, {0x375, "SSC-2 T10/1434-D revision 9"}, {0x37d, "SSC-2 ANSI INCITS 380-2003"}, {0x380, "BCC (no version claimed)"}, {0x3a0, "MMC-4 (no version claimed)"}, {0x3b0, "MMC-4 T10/1545-D revision 5"}, /* dropped in spc4r09 */ {0x3b1, "MMC-4 T10/1545-D revision 5a"}, {0x3bd, "MMC-4 T10/1545-D revision 3"}, {0x3be, "MMC-4 T10/1545-D revision 3d"}, {0x3bf, "MMC-4 ANSI INCITS 401-2005"}, {0x3c0, "ADC (no version claimed)"}, {0x3d5, "ADC T10/1558-D revision 6"}, {0x3d6, "ADC T10/1558-D revision 7"}, {0x3d7, "ADC ANSI INCITS 403-2005"}, {0x3e0, "SES-2 (no version claimed)"}, {0x3e1, "SES-2 T10/1559-D revision 16"}, {0x3e7, "SES-2 T10/1559-D revision 19"}, {0x3eb, "SES-2 T10/1559-D revision 20"}, {0x3f0, "SES-2 ANSI INCITS 448-2008"}, {0x3f2, "SES-2 ISO/IEC 14776-372"}, {0x400, "SSC-3 (no version claimed)"}, {0x403, "SSC-3 T10/1611-D revision 04a"}, {0x407, "SSC-3 T10/1611-D revision 05"}, {0x409, "SSC-3 ANSI INCITS 467-2011"}, {0x420, "MMC-5 (no version claimed)"}, {0x42f, "MMC-5 T10/1675-D revision 03"}, {0x431, "MMC-5 T10/1675-D revision 03b"}, {0x432, "MMC-5 T10/1675-D revision 04"}, {0x434, "MMC-5 ANSI INCITS 430-2007"}, {0x440, "OSD-2 (no version claimed)"}, {0x444, "OSD-2 T10/1729-D revision 4"}, {0x446, "OSD-2 T10/1729-D revision 5"}, {0x448, "OSD-2 ANSI INCITS 458-2011"}, {0x460, "SPC-4 (no version claimed)"}, {0x461, "SPC-4 T10/BSR INCITS 513 revision 16"}, {0x462, "SPC-4 T10/BSR INCITS 513 revision 18"}, {0x463, "SPC-4 T10/BSR INCITS 513 revision 23"}, {0x466, "SPC-4 T10/BSR INCITS 513 revision 36"}, {0x468, "SPC-4 T10/BSR INCITS 513 revision 37"}, {0x480, "SMC-3 (no version claimed)"}, {0x482, "SMC-3 T10/1730-D revision 15"}, {0x482, "SMC-3 T10/1730-D revision 16"}, {0x486, "SMC-3 ANSI INCITS 484-2012"}, {0x4a0, "ADC-2 (no version claimed)"}, {0x4a7, "ADC-2 T10/1741-D revision 7"}, {0x4aa, "ADC-2 T10/1741-D revision 8"}, {0x4ac, "ADC-2 ANSI INCITS 441-2008"}, {0x4c0, "SBC-3 (no version claimed)"}, {0x4c3, "SBC-3 T10/BSR INCITS 514 revision 35"}, {0x4c5, "SBC-3 T10/BSR INCITS 514 revision 36"}, {0x4e0, "MMC-6 (no version claimed)"}, {0x4e3, "MMC-6 T10/1836-D revision 2b"}, {0x4e5, "MMC-6 T10/1836-D revision 02g"}, {0x4e6, "MMC-6 ANSI INCITS 468-2010"}, {0x4e7, "MMC-6 ANSI INCITS 468-2010 + MMC-6/AM1 ANSI INCITS " "468-2010/AM 1"}, {0x500, "ADC-3 (no version claimed)"}, {0x502, "ADC-3 T10/1895-D revision 04"}, {0x504, "ADC-3 T10/1895-D revision 05"}, {0x506, "ADC-3 T10/1895-D revision 05a"}, {0x50a, "ADC-3 ANSI INCITS 497-2012"}, {0x520, "SSC-4 (no version claimed)"}, {0x523, "SSC-4 T10/BSR INCITS 516 revision 2"}, {0x525, "SSC-4 T10/BSR INCITS 516 revision 3"}, {0x527, "SSC-4 SSC-4 ANSI INCITS 516-2013"}, {0x560, "OSD-3 (no version claimed)"}, {0x580, "SES-3 (no version claimed)"}, {0x5a0, "SSC-5 (no version claimed)"}, {0x5c0, "SPC-5 (no version claimed)"}, {0x5e0, "SFSC (no version claimed)"}, {0x600, "SBC-4 (no version claimed)"}, {0x620, "ZBC (no version claimed)"}, {0x820, "SSA-TL2 (no version claimed)"}, {0x83b, "SSA-TL2 T10/1147-D revision 05b"}, {0x83c, "SSA-TL2 ANSI INCITS 308-1998"}, {0x840, "SSA-TL1 (no version claimed)"}, {0x85b, "SSA-TL1 T10/0989-D revision 10b"}, {0x85c, "SSA-TL1 ANSI INCITS 295-1996"}, {0x860, "SSA-S3P (no version claimed)"}, {0x87b, "SSA-S3P T10/1051-D revision 05b"}, {0x87c, "SSA-S3P ANSI INCITS 309-1998"}, {0x880, "SSA-S2P (no version claimed)"}, {0x89b, "SSA-S2P T10/1121-D revision 07b"}, {0x89c, "SSA-S2P ANSI INCITS 294-1996"}, {0x8a0, "SIP (no version claimed)"}, {0x8bb, "SIP T10/0856-D revision 10"}, {0x8bc, "SIP ANSI INCITS 292-1997"}, {0x8c0, "FCP (no version claimed)"}, {0x8db, "FCP T10/0856-D revision 12"}, {0x8dc, "FCP ANSI INCITS 269-1996"}, {0x8e0, "SBP-2 (no version claimed)"}, {0x8fb, "SBP-2 T10/1155-D revision 04"}, {0x8fc, "SBP-2 ANSI INCITS 325-1999"}, {0x900, "FCP-2 (no version claimed)"}, {0x901, "FCP-2 T10/1144-D revision 4"}, {0x915, "FCP-2 T10/1144-D revision 7"}, {0x916, "FCP-2 T10/1144-D revision 7a"}, {0x917, "FCP-2 ANSI INCITS 350-2003"}, {0x918, "FCP-2 T10/1144-D revision 8"}, {0x920, "SST (no version claimed)"}, {0x935, "SST T10/1380-D revision 8b"}, {0x940, "SRP (no version claimed)"}, {0x954, "SRP T10/1415-D revision 10"}, {0x955, "SRP T10/1415-D revision 16a"}, {0x95c, "SRP ANSI INCITS 365-2002"}, {0x960, "iSCSI (no version claimed)"}, {0x961, "iSCSI RFC 7143"}, {0x962, "iSCSI RFC 7144"}, /* 0x960 up to 0x97f for iSCSI use */ {0x980, "SBP-3 (no version claimed)"}, {0x982, "SBP-3 T10/1467-D revision 1f"}, {0x994, "SBP-3 T10/1467-D revision 3"}, {0x99a, "SBP-3 T10/1467-D revision 4"}, {0x99b, "SBP-3 T10/1467-D revision 5"}, {0x99c, "SBP-3 ANSI INCITS 375-2004"}, /* {0x9a0, "SRP-2 (no version claimed)"}, */ {0x9c0, "ADP (no version claimed)"}, {0x9e0, "ADT (no version claimed)"}, {0x9f9, "ADT T10/1557-D revision 11"}, {0x9fa, "ADT T10/1557-D revision 14"}, {0x9fd, "ADT ANSI INCITS 406-2005"}, {0xa00, "FCP-3 (no version claimed)"}, {0xa07, "FCP-3 T10/1560-D revision 3f"}, {0xa0f, "FCP-3 T10/1560-D revision 4"}, {0xa11, "FCP-3 ANSI INCITS 416-2006"}, {0xa1c, "FCP-3 ISO/IEC 14776-223"}, {0xa20, "ADT-2 (no version claimed)"}, {0xa22, "ADT-2 T10/1742-D revision 06"}, {0xa27, "ADT-2 T10/1742-D revision 08"}, {0xa28, "ADT-2 T10/1742-D revision 09"}, {0xa2b, "ADT-2 ANSI INCITS 472-2011"}, {0xa40, "FCP-4 (no version claimed)"}, {0xa42, "FCP-4 T10/1828-D revision 01"}, {0xa44, "FCP-4 T10/1828-D revision 02"}, {0xa45, "FCP-4 T10/1828-D revision 02b"}, {0xa46, "FCP-4 ANSI INCITS 481-2012"}, {0xaa0, "SPI (no version claimed)"}, {0xab9, "SPI T10/0855-D revision 15a"}, {0xaba, "SPI ANSI INCITS 253-1995"}, {0xabb, "SPI T10/0855-D revision 15a with SPI Amnd revision 3a"}, {0xabc, "SPI ANSI INCITS 253-1995 with SPI Amnd ANSI INCITS " "253/AM1:1998"}, {0xac0, "Fast-20 (no version claimed)"}, {0xadb, "Fast-20 T10/1071-D revision 06"}, {0xadc, "Fast-20 ANSI INCITS 277-1996"}, {0xae0, "SPI-2 (no version claimed)"}, {0xafb, "SPI-2 T10/1142-D revision 20b"}, {0xafc, "SPI-2 ANSI INCITS 302-1999"}, {0xb00, "SPI-3 (no version claimed)"}, {0xb18, "SPI-3 T10/1302-D revision 10"}, {0xb19, "SPI-3 T10/1302-D revision 13a"}, {0xb1a, "SPI-3 T10/1302-D revision 14"}, {0xb1c, "SPI-3 ANSI INCITS 336-2000"}, {0xb20, "EPI (no version claimed)"}, {0xb3b, "EPI T10/1134-D revision 16"}, {0xb3c, "EPI ANSI INCITS TR-23 1999"}, {0xb40, "SPI-4 (no version claimed)"}, {0xb54, "SPI-4 T10/1365-D revision 7"}, {0xb55, "SPI-4 T10/1365-D revision 9"}, {0xb56, "SPI-4 ANSI INCITS 362-2002"}, {0xb59, "SPI-4 T10/1365-D revision 10"}, {0xb60, "SPI-5 (no version claimed)"}, {0xb79, "SPI-5 T10/1525-D revision 3"}, {0xb7a, "SPI-5 T10/1525-D revision 5"}, {0xb7b, "SPI-5 T10/1525-D revision 6"}, {0xb7c, "SPI-5 ANSI INCITS 367-2004"}, {0xbe0, "SAS (no version claimed)"}, {0xbe1, "SAS T10/1562-D revision 01"}, {0xbf5, "SAS T10/1562-D revision 03"}, {0xbfa, "SAS T10/1562-D revision 04"}, {0xbfb, "SAS T10/1562-D revision 04"}, {0xbfc, "SAS T10/1562-D revision 05"}, {0xbfd, "SAS ANSI INCITS 376-2003"}, {0xc00, "SAS-1.1 (no version claimed)"}, {0xc07, "SAS-1.1 T10/1602-D revision 9"}, {0xc0f, "SAS-1.1 T10/1602-D revision 10"}, {0xc11, "SAS-1.1 ANSI INCITS 417-2006"}, {0xc12, "SAS-1.1 ISO/IEC 14776-151"}, {0xc20, "SAS-2 (no version claimed)"}, {0xc23, "SAS-2 T10/1760-D revision 14"}, {0xc27, "SAS-2 T10/1760-D revision 15"}, {0xc28, "SAS-2 T10/1760-D revision 16"}, {0xc2a, "SAS-2 ANSI INCITS 457-2010"}, {0xc40, "SAS-2.1 (no version claimed)"}, {0xc48, "SAS-2.1 T10/2125-D revision 04"}, {0xc4a, "SAS-2.1 T10/2125-D revision 06"}, {0xc4b, "SAS-2.1 T10/2125-D revision 07"}, {0xc4e, "SAS-2.1 ANSI INCITS 478-2011"}, {0xc4f, "SAS-2.1 ANSI INCITS 478-2011 w/ Amnd 1 ANSI INCITS " "478/AM1-2014"}, {0xc60, "SAS-3 (no version claimed)"}, {0xc63, "SAS-3 T10/BSR INCITS 519 revision 05a"}, {0xc65, "SAS-3 T10/BSR INCITS 519 revision 06"}, {0xc80, "SAS-4 (no version claimed)"}, {0xd20, "FC-PH (no version claimed)"}, {0xd3b, "FC-PH ANSI INCITS 230-1994"}, {0xd3c, "FC-PH ANSI INCITS 230-1994 with Amnd 1 ANSI INCITS " "230/AM1:1996"}, {0xd40, "FC-AL (no version claimed)"}, {0xd5c, "FC-AL ANSI INCITS 272-1996"}, {0xd60, "FC-AL-2 (no version claimed)"}, {0xd61, "FC-AL-2 T11/1133-D revision 7.0"}, {0xd63, "FC-AL-2 ANSI INCITS 332-1999 with AM1-2003 & AM2-2006"}, {0xd64, "FC-AL-2 ANSI INCITS 332-1999 with Amnd 2 AM2-2006"}, {0xd65, "FC-AL-2 ISO/IEC 14165-122 with AM1 & AM2"}, {0xd7c, "FC-AL-2 ANSI INCITS 332-1999"}, {0xd7d, "FC-AL-2 ANSI INCITS 332-1999 with Amnd 1 AM1:2002"}, {0xd80, "FC-PH-3 (no version claimed)"}, {0xd9c, "FC-PH-3 ANSI INCITS 303-1998"}, {0xda0, "FC-FS (no version claimed)"}, {0xdb7, "FC-FS T11/1331-D revision 1.2"}, {0xdb8, "FC-FS T11/1331-D revision 1.7"}, {0xdbc, "FC-FS ANSI INCITS 373-2003"}, {0xdbd, "FC-FS ISO/IEC 14165-251"}, {0xdc0, "FC-PI (no version claimed)"}, {0xddc, "FC-PI ANSI INCITS 352-2002"}, {0xde0, "FC-PI-2 (no version claimed)"}, {0xde2, "FC-PI-2 T11/1506-D revision 5.0"}, {0xde4, "FC-PI-2 ANSI INCITS 404-2006"}, {0xe00, "FC-FS-2 (no version claimed)"}, {0xe02, "FC-FS-2 ANSI INCITS 242-2007"}, {0xe03, "FC-FS-2 ANSI INCITS 242-2007 with AM1 ANSI INCITS 242/AM1-2007"}, {0xe20, "FC-LS (no version claimed)"}, {0xe21, "FC-LS T11/1620-D revision 1.62"}, {0xe29, "FC-LS ANSI INCITS 433-2007"}, {0xe40, "FC-SP (no version claimed)"}, {0xe42, "FC-SP T11/1570-D revision 1.6"}, {0xe45, "FC-SP ANSI INCITS 426-2007"}, {0xe60, "FC-PI-3 (no version claimed)"}, {0xe62, "FC-PI-3 T11/1625-D revision 2.0"}, {0xe68, "FC-PI-3 T11/1625-D revision 2.1"}, {0xe6a, "FC-PI-3 T11/1625-D revision 4.0"}, {0xe6e, "FC-PI-3 ANSI INCITS 460-2011"}, {0xe80, "FC-PI-4 (no version claimed)"}, {0xe82, "FC-PI-4 T11/1647-D revision 8.0"}, {0xea0, "FC 10GFC (no version claimed)"}, {0xea2, "FC 10GFC ANSI INCITS 364-2003"}, {0xea3, "FC 10GFC ISO/IEC 14165-116"}, {0xea5, "FC 10GFC ISO/IEC 14165-116 with AM1"}, {0xea6, "FC 10GFC ANSI INCITS 364-2003 with AM1 ANSI INCITS 364/AM1-2007"}, {0xec0, "FC-SP-2 (no version claimed)"}, {0xee0, "FC-FS-3 (no version claimed)"}, {0xee2, "FC-FS-3 T11/1861-D revision 0.9"}, {0xee7, "FC-FS-3 T11/1861-D revision 1.0"}, {0xee9, "FC-FS-3 T11/1861-D revision 1.10"}, {0xeeb, "FC-FS-3 ANSI INCITS 470-2011"}, {0xf00, "FC-LS-2 (no version claimed)"}, {0xf03, "FC-LS-2 T11/2103-D revision 2.11"}, {0xf05, "FC-LS-2 T11/2103-D revision 2.21"}, {0xf07, "FC-LS-2 ANSI INCITS 477-2011"}, {0xf20, "FC-PI-5 (no version claimed)"}, {0xf27, "FC-PI-5 T11/2118-D revision 2.00"}, {0xf28, "FC-PI-5 T11/2118-D revision 3.00"}, {0xf2a, "FC-PI-5 T11/2118-D revision 6.00"}, {0xf2b, "FC-PI-5 T11/2118-D revision 6.10"}, {0xf2e, "FC-PI-5 ANSI INCITS 479-2011"}, {0xf40, "FC-PI-6 (no version claimed)"}, {0xf60, "FC-FS-4 (no version claimed)"}, {0xf80, "FC-LS-3 (no version claimed)"}, {0x12a0, "FC-SCM (no version claimed)"}, {0x12a3, "FC-SCM T11/1824DT revision 1.0"}, {0x12a5, "FC-SCM T11/1824DT revision 1.1"}, {0x12a7, "FC-SCM T11/1824DT revision 1.4"}, {0x12aa, "FC-SCM INCITS TR-47 2012"}, {0x12c0, "FC-DA-2 (no version claimed)"}, {0x12c3, "FC-DA-2 T11/1870DT revision 1.04"}, {0x12c5, "FC-DA-2 T11/1870DT revision 1.06"}, {0x12c9, "FC-DA-2 INCITS TR-49 2012"}, {0x12e0, "FC-DA (no version claimed)"}, {0x12e2, "FC-DA T11/1513-DT revision 3.1"}, {0x12e8, "FC-DA ANSI INCITS TR-36 2004"}, {0x12e9, "FC-DA ISO/IEC 14165-341"}, {0x1300, "FC-Tape (no version claimed)"}, {0x1301, "FC-Tape T11/1315-D revision 1.16"}, {0x131b, "FC-Tape T11/1315-D revision 1.17"}, {0x131c, "FC-Tape ANSI INCITS TR-24 1999"}, {0x1320, "FC-FLA (no version claimed)"}, {0x133b, "FC-FLA T11/1235-D revision 7"}, {0x133c, "FC-FLA ANSI INCITS TR-20 1998"}, {0x1340, "FC-PLDA (no version claimed)"}, {0x135b, "FC-PLDA T11/1162-D revision 2.1"}, {0x135c, "FC-PLDA ANSI INCITS TR-19 1998"}, {0x1360, "SSA-PH2 (no version claimed)"}, {0x137b, "SSA-PH2 T10/1145-D revision 09c"}, {0x137c, "SSA-PH2 ANSI INCITS 293-1996"}, {0x1380, "SSA-PH3 (no version claimed)"}, {0x139b, "SSA-PH3 T10/1146-D revision 05b"}, {0x139c, "SSA-PH3 ANSI INCITS 307-1998"}, {0x14a0, "IEEE 1394 (no version claimed)"}, {0x14bd, "ANSI IEEE 1394:1995"}, {0x14c0, "IEEE 1394a (no version claimed)"}, {0x14e0, "IEEE 1394b (no version claimed)"}, {0x15e0, "ATA/ATAPI-6 (no version claimed)"}, {0x15fd, "ATA/ATAPI-6 ANSI INCITS 361-2002"}, {0x1600, "ATA/ATAPI-7 (no version claimed)"}, {0x1602, "ATA/ATAPI-7 T13/1532-D revision 3"}, {0x161c, "ATA/ATAPI-7 ANSI INCITS 397-2005"}, {0x161e, "ATA/ATAPI-7 ISO/IEC 24739"}, {0x1620, "ATA/ATAPI-8 ATA-AAM Architecture model (no version claimed)"}, {0x1621, "ATA/ATAPI-8 ATA-PT Parallel transport (no version claimed)"}, {0x1622, "ATA/ATAPI-8 ATA-AST Serial transport (no version claimed)"}, {0x1623, "ATA/ATAPI-8 ATA-ACS ATA/ATAPI command set (no version " "claimed)"}, {0x1628, "ATA/ATAPI-8 ATA-AAM ANSI INCITS 451-2008"}, {0x162a, "ATA/ATAPI-8 ATA8-ACS ANSI INCITS 452-2009 w/ Amendment 1"}, {0x1721, "ACS-2 (no version claimed)"}, {0x1722, "ACS-2 ANSI INCITS 482-2013"}, {0x1726, "ACS-3 (no version claimed)"}, {0x1728, "Universal Serial Bus Specification, Revision 1.1"}, {0x1729, "Universal Serial Bus Specification, Revision 2.0"}, {0x1730, "USB Mass Storage Class Bulk-Only Transport, Revision 1.0"}, {0x1740, "UAS (no version claimed)"}, /* USB attached SCSI */ {0x1743, "UAS T10/2095-D revision 02"}, {0x1747, "UAS T10/2095-D revision 04"}, {0x1748, "UAS ANSI INCITS 471-2010"}, {0x1780, "UAS-2 (no version claimed)"}, {0x1ea0, "SAT (no version claimed)"}, {0x1ea7, "SAT T10/1711-D rev 8"}, {0x1eab, "SAT T10/1711-D rev 9"}, {0x1ead, "SAT ANSI INCITS 431-2007"}, {0x1ec0, "SAT-2 (no version claimed)"}, {0x1ec4, "SAT-2 T10/1826-D revision 06"}, {0x1ec8, "SAT-2 T10/1826-D revision 09"}, {0x1eca, "SAT-2 ANSI INCITS 465-2010"}, {0x1ee0, "SAT-3 (no version claimed)"}, {0x1ee2, "SAT-3 T10/2126-D revision 4"}, {0x1f00, "SAT-4 (no version claimed)"}, {0x20a0, "SPL (no version claimed)"}, {0x20a3, "SPL T10/2124-D revision 6a"}, {0x20a5, "SPL T10/2124-D revision 7"}, {0x20a7, "SPL ANSI INCITS 476-2011"}, {0x20a8, "SPL ANSI INCITS 476-2011 + SPL AM1 INCITS 476/AM1 2012"}, {0x20aa, "SPL ISO/IEC 14776-261:2012"}, {0x20c0, "SPL-2 (no version claimed)"}, {0x20c2, "SPL-2 T10/BSR INCITS 505 revision 4"}, {0x20c4, "SPL-2 T10/BSR INCITS 505 revision 5"}, {0x20c8, "SPL-2 ANSI INCITS 505-2013"}, {0x20e0, "SPL-3 (no version claimed)"}, {0x20e4, "SPL-3 T10/BSR INCITS 492 revision 6"}, {0x20e6, "SPL-3 T10/BSR INCITS 492 revision 7"}, {0x2100, "SPL-4 (no version claimed)"}, {0x21e0, "SOP (no version claimed)"}, {0x21e4, "SOP T10/BSR INCITS 489 revision 4"}, {0x21e6, "SOP T10/BSR INCITS 489 revision 5"}, {0x2200, "PQI (no version claimed)"}, {0x2204, "PQI T10/BSR INCITS 490 revision 6"}, {0x2206, "PQI T10/BSR INCITS 490 revision 7"}, {0x2220, "SOP-2 (no version claimed)"}, {0x2240, "PQI-2 (no version claimed)"}, {0xffc0, "IEEE 1667 (no version claimed)"}, {0xffc1, "IEEE 1667-2006"}, {0xffc2, "IEEE 1667-2009"}, {0xffff, NULL}, }; #else struct sg_version_descriptor sg_version_descriptor_arr[] = { {0xffff, NULL}, }; #endif sg3_utils-1.40/src/sg_get_lba_status.c0000664000175000017500000002624112335161436017005 0ustar douggdougg/* * Copyright (c) 2009-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI GET LBA STATUS command to the given SCSI * device. */ static const char * version_str = "1.06 20140515"; /* sbc2r29 */ #define MAX_GLBAS_BUFF_LEN (1024 * 1024) #define DEF_GLBAS_BUFF_LEN 24 static unsigned char glbasBuff[DEF_GLBAS_BUFF_LEN]; static unsigned char * glbasBuffp = glbasBuff; static struct option long_options[] = { {"brief", no_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"lba", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_get_lba_status [--brief] [--help] [--hex] [--lba=LBA]\n" " [--maxlen=LEN] [--raw] [--readonly] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --brief|-b a descriptor per line: " "\n" " use twice ('-bb') for given LBA " "provisioning status\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" " --lba=LBA|-l LBA starting LBA (logical block address) " "(def: 0)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> %d bytes)\n", DEF_GLBAS_BUFF_LEN ); fprintf(stderr, " --raw|-r output in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI GET LBA STATUS command (SBC-3)\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Decodes given LBA status descriptor passing back the starting LBA, * the number of blocks and returns the provisioning status, -1 for error. */ static int decode_lba_status_desc(const unsigned char * ucp, uint64_t * slbap, uint32_t * blocksp) { int j; uint32_t blocks; uint64_t ull; if (NULL == ucp) return -1; ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[j]; } blocks = 0; for (j = 0; j < 4; ++j) { if (j > 0) blocks <<= 8; blocks |= ucp[8 + j]; } if (slbap) *slbap = ull; if (blocksp) *blocksp = blocks; return ucp[12] & 0xf; } int main(int argc, char * argv[]) { int sg_fd, k, j, res, c, rlen, num_descs; int do_brief = 0; int do_hex = 0; int64_t ll; uint64_t lba = 0; uint64_t d_lba = 0; uint32_t d_blocks = 0; int maxlen = DEF_GLBAS_BUFF_LEN; int do_raw = 0; int o_readonly = 0; int verbose = 0; const char * device_name = NULL; const unsigned char * ucp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bhHl:m:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++do_brief; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_GLBAS_BUFF_LEN)) { fprintf(stderr, "argument to '--maxlen' should be %d or " "less\n", MAX_GLBAS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_GLBAS_BUFF_LEN) { glbasBuffp = (unsigned char *)calloc(maxlen, 1); if (NULL == glbasBuffp) { fprintf(stderr, "unable to allocate %d bytes on heap\n", maxlen); return SG_LIB_SYNTAX_ERROR; } } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto free_buff; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto free_buff; } res = sg_ll_get_lba_status(sg_fd, lba, glbasBuffp, maxlen, 1, verbose); ret = res; if (0 == res) { /* in sbc3r25 offset for calculating the 'parameter data length' * (rlen variable below) was reduced from 8 to 4. */ if (maxlen >= 4) rlen = (glbasBuffp[0] << 24) + (glbasBuffp[1] << 16) + (glbasBuffp[2] << 8) + glbasBuffp[3] + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw((const char *)glbasBuffp, k); goto the_end; } if (do_hex) { dStrHex((const char *)glbasBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) fprintf(stderr, "Exiting because allocation length (maxlen) " " less than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { fprintf(stderr, "response length %d bytes\n", rlen); if (rlen > maxlen) fprintf(stderr, " ... which is greater than maxlen " "(allocation length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; if (do_brief > 1) { if (rlen < 24) { fprintf(stderr, "Need maxlen and response length to " " be at least 24, have %d bytes\n", rlen); ret = SG_LIB_CAT_OTHER; goto the_end; } res = decode_lba_status_desc(glbasBuffp + 8, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) { fprintf(stderr, "first LBA status descriptor returned %d " "??\n", res); ret = SG_LIB_CAT_OTHER; goto the_end; } if ((lba < d_lba) || (lba >= (d_lba + d_blocks))) { fprintf(stderr, "given LBA not in range of first " "descriptor:\n" " descriptor LBA: 0x"); for (j = 0; j < 8; ++j) fprintf(stderr, "%02x", glbasBuffp[8 + j]); fprintf(stderr, " blocks: 0x%x p_status: %d\n", (unsigned int)d_blocks, res); ret = SG_LIB_CAT_OTHER; goto the_end; } printf("%d\n", res); goto the_end; } if (rlen < 24) { printf("No complete LBA status descriptors available\n"); goto the_end; } num_descs = (rlen - 8) / 16; if (verbose) fprintf(stderr, "%d complete LBA status descriptors found\n", num_descs); for (ucp = glbasBuffp + 8, k = 0; k < num_descs; ucp += 16, ++k) { res = decode_lba_status_desc(ucp, &d_lba, &d_blocks); if ((res < 0) || (res > 15)) fprintf(stderr, "descriptor %d: bad LBA status descriptor " "returned %d\n", k + 1, res); if (do_brief) { printf("0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" 0x%x %d\n", (unsigned int)d_blocks, res); } else { printf("descriptor LBA: 0x"); for (j = 0; j < 8; ++j) printf("%02x", ucp[j]); printf(" blocks: %u", (unsigned int)d_blocks); switch (res) { case 0: printf(" mapped\n"); break; case 1: printf(" deallocated\n"); break; case 2: printf(" anchored\n"); break; default: printf(" Provisioning status: %d\n", res); break; } } } if ((num_descs * 16) + 8 < rlen) fprintf(stderr, "incomplete trailing LBA status descriptors " "found\n"); } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Get LBA Status command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "Get LBA Status command: bad field in cdb\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Get LBA Status command: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } free_buff: if (glbasBuffp && (glbasBuffp != glbasBuff)) free(glbasBuffp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_rep_zones.c0000664000175000017500000003130112423733033015776 0ustar douggdougg/* * Copyright (c) 2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT ZONES command to the given SCSI device * and decodes the response. Based on zbc-r01c.pdf */ static const char * version_str = "1.03 20141028"; #define MAX_RZONES_BUFF_LEN (1024 * 1024) #define DEF_RZONES_BUFF_LEN (1024 * 8) #define SERVICE_ACTION_IN_16_CMD 0x9e #define SERVICE_ACTION_IN_16_CMDLEN 16 #define REPORT_ZONES_SA 0x14 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"maxlen", required_argument, 0, 'm'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"report", required_argument, 0, 'o'}, {"start", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_rep_zones [--help] [--hex] [--maxlen=LEN] [--raw]\n" " [--readonly] [--report=OPT] " "[--start=LBA]\n" " [--verbose] [--version] DEVICE\n"); pr2serr(" where:\n" " --help|-h print out usage message\n" " --hex|-H output response in hexadecimal; used " "twice\n" " shows decoded values in hex\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 8192 bytes)\n" " --raw|-r output response in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --report=OPT|-o OP reporting option (def: 0)\n" " --start=LBA|-s LBA report zones from the LBA (def: 0)\n" " need not be a zone starting LBA\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT ZONES command.\n"); } /* Invokes a SCSI REPORT ZONES command (ZBC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_report_zones(int sg_fd, uint64_t zs_lba, int report_opts, void * resp, int mx_resp_len, int * residp, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rzCmdBlk[SERVICE_ACTION_IN_16_CMDLEN] = {SERVICE_ACTION_IN_16_CMD, REPORT_ZONES_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; sg_put_unaligned_be64(zs_lba, rzCmdBlk + 2); sg_put_unaligned_be32((uint32_t)mx_resp_len, rzCmdBlk + 10); rzCmdBlk[14] = report_opts & 0xf; if (verbose) { pr2serr(" Report zones cdb: "); for (k = 0; k < SERVICE_ACTION_IN_16_CMDLEN; ++k) pr2serr("%02x ", rzCmdBlk[k]); pr2serr("\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Report zones: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rzCmdBlk, sizeof(rzCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "report zones", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; if (residp) *residp = get_scsi_pt_resid(ptvp); destruct_scsi_pt_obj(ptvp); return ret; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static const char * zone_type_str(int zt, char * b, int blen, int vb) { const char * cp; if (NULL == b) return "zone_type_str: NULL ptr)"; switch (zt) { case 1: cp = "Conventional"; break; case 2: cp = "Sequential write required"; break; case 3: cp = "Sequential write preferred"; break; default: cp = NULL; break; } if (cp) { if (vb) snprintf(b, blen, "%s [0x%x]", cp, zt); else snprintf(b, blen, "%s", cp); } else snprintf(b, blen, "Reserved [0x%x]", zt); return b; } static const char * zone_condition_str(int zc, char * b, int blen, int vb) { const char * cp; if (NULL == b) return "zone_condition_str: NULL ptr)"; switch (zc) { case 0: cp = "No write pointer"; break; case 1: cp = "Empty"; break; case 2: cp = "Open"; break; case 0xd: cp = "Read only"; break; case 0xe: cp = "Full"; break; case 0xf: cp = "Offline"; break; default: cp = NULL; break; } if (cp) { if (vb) snprintf(b, blen, "%s [0x%x]", cp, zc); else snprintf(b, blen, "%s", cp); } else snprintf(b, blen, "Reserved [0x%x]", zc); return b; } static const char * same_desc_arr[4] = { "zone type and length may differ in each descriptor", "zone type and length same in each descriptor", "zone type and length same apart from length in last descriptor", "Reserved", }; int main(int argc, char * argv[]) { int sg_fd, k, res, c, zl_len, len, zones, resid, rlen, zt, zc, same; int do_hex = 0; int maxlen = 0; int do_raw = 0; int o_readonly = 0; int reporting_opt = 0; int verbose = 0; uint64_t st_lba = 0; int64_t ll; const char * device_name = NULL; unsigned char * reportZonesBuff = NULL; unsigned char * ucp; int ret = 0; char b[80]; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHm:o:rRs:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_RZONES_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or " "less\n", MAX_RZONES_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'o': reporting_opt = sg_get_num(optarg); if ((reporting_opt < 0) || (reporting_opt > 15)) { pr2serr("bad argument to '--report=OPT', expect 0 to " "15\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 's': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--start=LBA'\n"); return SG_LIB_SYNTAX_ERROR; } st_lba = (uint64_t)ll; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == maxlen) maxlen = DEF_RZONES_BUFF_LEN; reportZonesBuff = (unsigned char *)calloc(1, maxlen); if (NULL == reportZonesBuff) { pr2serr("unable to malloc %d bytes\n", maxlen); return SG_LIB_CAT_OTHER; } res = sg_ll_report_zones(sg_fd, st_lba, reporting_opt, reportZonesBuff, maxlen, &resid, 1, verbose); ret = res; if (0 == res) { rlen = maxlen - resid; if (rlen < 4) { pr2serr("Response length (%d) too short\n", rlen); ret = SG_LIB_CAT_MALFORMED; goto the_end; } zl_len = sg_get_unaligned_be32(reportZonesBuff + 0) + 64; if (zl_len > rlen) { if (verbose) pr2serr("zl_len available is %d, response length is %d\n", zl_len, rlen); len = rlen; } else len = zl_len; if (do_raw) { dStrRaw((const char *)reportZonesBuff, len); goto the_end; } if (do_hex && (2 != do_hex)) { dStrHex((const char *)reportZonesBuff, len, ((1 == do_hex) ? 1 : -1)); goto the_end; } printf("Report zones response:\n"); if (len < 64) { pr2serr("Zone length [%d] too short (perhaps after truncation\n)", len); ret = SG_LIB_CAT_MALFORMED; goto the_end; } same = reportZonesBuff[4] & 3; printf(" Same=%d: %s\n\n", same, same_desc_arr[same]); zones = (len - 64) / 64; for (k = 0, ucp = reportZonesBuff + 64; k < zones; ++k, ucp += 64) { printf(" Zone descriptor: %d\n", k); if (do_hex) { dStrHex((const char *)ucp, len, -1); continue; } zt = ucp[0] & 0xf; zc = (ucp[1] >> 4) & 0xf; printf(" Zone type: %s\n", zone_type_str(zt, b, sizeof(b), verbose)); printf(" Zone condition: %s\n", zone_condition_str(zc, b, sizeof(b), verbose)); printf(" Non_seq: %d\n", !!(ucp[1] & 0x2)); printf(" Reset: %d\n", ucp[1] & 0x1); printf(" Zone Length: 0x%" PRIx64 "\n", sg_get_unaligned_be64(ucp + 8)); printf(" Zone start LBA: 0x%" PRIx64 "\n", sg_get_unaligned_be64(ucp + 16)); printf(" Write pointer LBA: 0x%" PRIx64 "\n", sg_get_unaligned_be64(ucp + 24)); } if ((64 + (64 * zones)) < zl_len) printf("\n>>> Beware: Zone list truncated, may need another " "call\n"); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Report zones command not supported\n"); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report zones command: %s\n", b); } the_end: if (reportZonesBuff) free(reportZonesBuff); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_read_block_limits.c0000664000175000017500000001236012335513125017444 0ustar douggdougg/* * Copyright (c) 2009-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI READ BLOCK LIMITS command (SSC) to the given * SCSI device. */ static const char * version_str = "1.03 20140516"; #define MAX_READ_BLOCK_LIMITS_LEN 6 static unsigned char readBlkLmtBuff[MAX_READ_BLOCK_LIMITS_LEN]; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"raw", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_read_block_limits [--help] [--hex] [--raw] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --help|-h print out usage message\n" " --hex|-H output response in hexadecimal\n" " --raw|-r output response in binary to stdout\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI READ BLOCK LIMITS command and decode the " "response\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, k, m, res, c; int do_hex = 0; int do_raw = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; uint32_t max_block_size; uint16_t min_block_size; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHrvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'r': ++do_raw; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "invalid option -%c ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(readBlkLmtBuff, 0x0, 6); res = sg_ll_read_block_limits(sg_fd, readBlkLmtBuff, 6, 1, verbose); ret = res; if (0 == res) { if (do_hex) { dStrHex((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff), 1); goto the_end; } else if (do_raw) { dStrRaw((const char *)readBlkLmtBuff, sizeof(readBlkLmtBuff)); goto the_end; } max_block_size = (readBlkLmtBuff[0] << 24) + (readBlkLmtBuff[1] << 16) + (readBlkLmtBuff[2] << 8) + readBlkLmtBuff[3]; min_block_size = (readBlkLmtBuff[4] << 8) + readBlkLmtBuff[5]; k = min_block_size / 1024; fprintf(stderr, "Read Block Limits results:\n"); fprintf(stderr, "\tMinimum block size: %u byte(s)", (unsigned int)min_block_size); if (k != 0) fprintf(stderr, ", %d KB", k); fprintf(stderr, "\n"); k = max_block_size / 1024; m = max_block_size / 1048576; fprintf(stderr, "\tMaximum block size: %u byte(s)", (unsigned int)max_block_size); if (k != 0) fprintf(stderr, ", %d KB", k); if (m != 0) fprintf(stderr, ", %d MB", m); fprintf(stderr, "\n"); } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read block limits: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' option for more information\n"); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_read_buffer.c0000664000175000017500000002312712407706337016256 0ustar douggdougg/* * Copyright (c) 2006-2014 Luben Tuikov and Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ /* * This utility issues the SCSI READ BUFFER command to the given device. */ static const char * version_str = "1.12 20140919"; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"id", 1, 0, 'i'}, {"length", 1, 0, 'l'}, {"mode", 1, 0, 'm'}, {"offset", 1, 0, 'o'}, {"raw", 0, 0, 'r'}, {"readonly", 0, 0, 'R'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_read_buffer [--help] [--hex] [--id=ID] [--length=LEN] " "[--mode=MO]\n" " [--offset=OFF] [--raw] [--readonly] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --help|-h print out usage message\n" " --hex|-H print output in hex\n" " --id=ID|-i ID buffer identifier (0 (default) to 255)\n" " --length=LEN|-l LEN length in bytes to read (def: 4)\n" " --mode=MO|-m MO read buffer mode, MO is number or " "acronym (def: 0)\n" " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n" " --raw|-r output response to stdout\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI READ BUFFER command. Use '-m xxx' to list " "available\nmodes. Numbers given in options are decimal unless " "they have a hex\nindicator (e.g. a leading '0x').\n" ); } #define MODE_HEADER_DATA 0 #define MODE_VENDOR 1 #define MODE_DATA 2 #define MODE_DESCRIPTOR 3 #define MODE_ECHO_BUFFER 0x0A #define MODE_ECHO_BDESC 0x0B #define MODE_EN_EX_ECHO 0x1A #define MODE_ERR_HISTORY 0x1C static struct mode_s { const char *mode_string; int mode; const char *comment; } modes[] = { { "hd", MODE_HEADER_DATA, "combined header and data"}, { "vendor", MODE_VENDOR, "vendor specific"}, { "data", MODE_DATA, "data"}, { "desc", MODE_DESCRIPTOR, "descriptor"}, { "echo", MODE_ECHO_BUFFER, "read data from echo buffer " "(spc-2)"}, { "echo_desc", MODE_ECHO_BDESC, "echo buffer descriptor (spc-2)"}, { "en_ex", MODE_EN_EX_ECHO, "enable expander communications protocol and echo buffer (spc-3)"}, { "err_hist", MODE_ERR_HISTORY, "error history (spc-4)"}, }; #define NUM_MODES ((int)(sizeof(modes)/sizeof(modes[0]))) static void print_modes(void) { int k; fprintf(stderr, "The modes parameter argument can be numeric " "(hex or decimal)\nor symbolic:\n"); for (k = 0; k < NUM_MODES; k++) { fprintf(stderr, " %2d (0x%02x) %-16s%s\n", modes[k].mode, modes[k].mode, modes[k].mode_string, modes[k].comment); } } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, res, c, len, k; int do_help = 0; int do_hex = 0; int o_readonly = 0; int rb_id = 0; int rb_len = 4; int rb_mode = 0; int rb_offset = 0; int do_raw = 0; int verbose = 0; const char * device_name = NULL; unsigned char * resp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHi:l:m:o:rRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': ++do_help; break; case 'H': ++do_hex; break; case 'i': rb_id = sg_get_num(optarg); if ((rb_id < 0) || (rb_id > 255)) { fprintf(stderr, "argument to '--id' should be in the range " "0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': rb_len = sg_get_num(optarg); if (rb_len < 0) { fprintf(stderr, "bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': if (isdigit(*optarg)) { rb_mode = sg_get_num(optarg); if ((rb_mode < 0) || (rb_mode > 31)) { fprintf(stderr, "argument to '--mode' should be in the " "range 0 to 31\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (k = 0; k < NUM_MODES; ++k) { if (0 == strncmp(modes[k].mode_string, optarg, len)) { rb_mode = modes[k].mode; break; } } if (NUM_MODES == k) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': rb_offset = sg_get_num(optarg); if (rb_offset < 0) { fprintf(stderr, "bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); fprintf(stderr, "\n"); print_modes(); } else usage(); return 0; } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (rb_len > 0) { resp = (unsigned char *)malloc(rb_len); if (NULL == resp) { fprintf(stderr, "unable to allocate %d bytes on the heap\n", rb_len); return SG_LIB_CAT_OTHER; } memset(resp, 0, rb_len); } else resp = NULL; if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (verbose > 4) fprintf(stderr, "Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } res = sg_ll_read_buffer(sg_fd, rb_mode, rb_id, rb_offset, resp, rb_len, 1, verbose); if (0 != res) { char b[80]; ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read buffer failed: %s\n", b); } else if (rb_len > 0) { if (do_raw) dStrRaw((const char *)resp, rb_len); else if (do_hex || (rb_len < 4)) dStrHex((const char *)resp, rb_len, ((do_hex > 1) ? 0 : 1)); else { switch (rb_mode) { case MODE_DESCRIPTOR: k = (resp[1] << 16) | (resp[2] << 8) | resp[3]; printf("OFFSET BOUNDARY: %d, Buffer offset alignment: " "%d-byte\n", resp[0], (1 << resp[0])); printf("BUFFER CAPACITY: %d (0x%x)\n", k, k); break; case MODE_ECHO_BDESC: k = ((resp[2] & 0x1F) << 8) | resp[3]; printf("EBOS:%d\n", resp[0] & 1 ? 1 : 0); printf("Echo buffer capacity: %d (0x%x)\n", k, k); break; default: dStrHex((const char *)resp, rb_len, (verbose > 1 ? 0 : 1)); break; } } } if (resp) free(resp); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_reassign.c0000664000175000017500000003677012335513125015624 0ustar douggdougg/* * Copyright (c) 2005-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This utility invokes the REASSIGN BLOCKS SCSI command to reassign * an existing (possibly damaged) lba on a direct access device (e.g. * a disk) to a new physical location. The previous contents is * recoverable then it is written to the remapped lba otherwise * vendor specific data is written. */ static const char * version_str = "1.16 20140517"; #define DEF_DEFECT_LIST_FORMAT 4 /* bytes from index */ #define MAX_NUM_ADDR 1024 static struct option long_options[] = { {"address", 1, 0, 'a'}, {"dummy", 0, 0, 'd'}, {"eight", 1, 0, 'e'}, {"grown", 0, 0, 'g'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"longlist", 1, 0, 'l'}, {"primary", 0, 0, 'p'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_reassign [--address=A,A...] [--dummy] [--eight=0|1] " "[--grown]\n" " [--help] [--hex] [--longlist=0|1] [--primary] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --address=A,A...|-a A,A... comma separated logical block " "addresses\n" " one or more, assumed to be " "decimal\n" " --address=-|-a - read stdin for logical block " "addresses\n" " --dummy|-d prepare but do not execute REASSIGN " "BLOCKS command\n" " --eight=0|1\n" " -e 0|1 force eight byte (64 bit) lbas " "when 1,\n" " four byte (32 bit) lbas when 0 " "(def)\n" " --grown|-g fetch grown defect list length, " "don't reassign\n" " --help|-h print out usage message\n" " --hex|-H print response in hex (for '-g' or " "'-p')\n" " --longlist=0|1\n" " -l 0|1 use 4 byte list length when 1, safe to " "ignore\n" " (def: 0 (2 byte list length))\n" " --primary|-p fetch primary defect list length, " "don't reassign\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Perform a SCSI REASSIGN BLOCKS command (or READ DEFECT LIST)\n" ); } /* Trying to decode multipliers as sg_get_llnum() [in sg_libs] does would * only confuse things here, so use this local trimmed version */ static int64_t get_llnum(const char * buf) { int res, len; int64_t num; uint64_t unum; if ((NULL == buf) || ('\0' == buf[0])) return -1LL; len = strspn(buf, "0123456789aAbBcCdDeEfFhHxX"); if (0 == len) return -1LL; if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { res = sscanf(buf + 2, "%" SCNx64 "", &unum); num = unum; } else if ('H' == toupper(buf[len - 1])) { res = sscanf(buf, "%" SCNx64 "", &unum); num = unum; } else res = sscanf(buf, "%" SCNd64 "", &num); if (1 == res) return num; else return -1LL; } /* Read numbers (up to 64 bits in size) from command line (comma (or * (single) space) separated list) or from stdin (one per line, comma * separated list or space separated list). Assumed decimal unless prefixed * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex). * Returns 0 if ok, or 1 if error. */ static int build_lba_arr(const char * inp, uint64_t * lba_arr, int * lba_arr_len, int max_arr_len) { int in_len, k, j, m; const char * lcp; int64_t ll; char * cp; char * c2p; if ((NULL == inp) || (NULL == lba_arr) || (NULL == lba_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *lba_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ char line[1024]; int off = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), stdin)) break; // could improve with carry_over logic if sizeof(line) too small in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; } } if (in_len < 1) continue; lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxX ,\t"); if ((k < in_len) && ('#' != lcp[k])) { fprintf(stderr, "build_lba_arr: syntax error at " "line %d, pos %d\n", j + 1, m + k + 1); return 1; } for (k = 0; k < 1024; ++k) { ll = get_llnum(lcp); if (-1 != ll) { if ((off + k) >= max_arr_len) { fprintf(stderr, "build_lba_arr: array length " "exceeded\n"); return 1; } lba_arr[off + k] = (uint64_t)ll; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } fprintf(stderr, "build_lba_arr: error in " "line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } } off += (k + 1); } *lba_arr_len = off; } else { /* list of numbers (default decimal) on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxX, "); if (in_len != k) { fprintf(stderr, "build_lba_arr: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { ll = get_llnum(lcp); if (-1 != ll) { lba_arr[k] = (uint64_t)ll; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { fprintf(stderr, "build_lba_arr: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *lba_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_lba_arr: array length exceeded\n"); return 1; } } return 0; } int main(int argc, char * argv[]) { int sg_fd, res, c, num, k, j; int dummy = 0; int got_addr = 0; int eight = -1; int addr_arr_len = 0; int grown = 0; int do_hex = 0; int longlist = 0; int primary = 0; int verbose = 0; const char * device_name = NULL; uint64_t addr_arr[MAX_NUM_ADDR]; unsigned char param_arr[4 + (MAX_NUM_ADDR * 8)]; char b[80]; int param_len = 4; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "a:de:ghHl:pvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': memset(addr_arr, 0, sizeof(addr_arr)); if (0 != build_lba_arr(optarg, addr_arr, &addr_arr_len, MAX_NUM_ADDR)) { fprintf(stderr, "bad argument to '--address'\n"); return SG_LIB_SYNTAX_ERROR; } got_addr = 1; break; case 'd': dummy = 1; break; case 'e': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((0 == res) || (1 == res))) eight = res; else { fprintf(stderr, "value for '--eight=' must be 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'g': grown = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((0 == res) || (1 == res))) longlist = res; else { fprintf(stderr, "value for '--longlist=' must be 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': primary = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (grown || primary) { if (got_addr) { fprintf(stderr, "can't have '--address=' with '--grown' or " "'--primary'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } else if ((0 == got_addr) || (addr_arr_len < 1)) { fprintf(stderr, "need at least one address (see '--address=')\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (got_addr) { for (k = 0; k < addr_arr_len; ++k) { if (addr_arr[k] >= ULONG_MAX) { if (eight < 0) { eight = 1; break; } else if (0 == eight) { fprintf(stderr, "address number %d exceeds 32 bits so " "'--eight=0' invalid\n", k + 1); return SG_LIB_SYNTAX_ERROR; } } } if (eight < 0) eight = 0; k = 4; for (j = 0; j < addr_arr_len; ++j) { if (eight) { param_arr[k++] = (addr_arr[j] >> 56) & 0xff; param_arr[k++] = (addr_arr[j] >> 48) & 0xff; param_arr[k++] = (addr_arr[j] >> 40) & 0xff; param_arr[k++] = (addr_arr[j] >> 32) & 0xff; } param_arr[k++] = (addr_arr[j] >> 24) & 0xff; param_arr[k++] = (addr_arr[j] >> 16) & 0xff; param_arr[k++] = (addr_arr[j] >> 8) & 0xff; param_arr[k++] = addr_arr[j] & 0xff; } param_len = k; k -= 4; if (longlist) { param_arr[0] = (k >> 24) & 0xff; param_arr[1] = (k >> 16) & 0xff; } param_arr[2] = (k >> 8) & 0xff; param_arr[3] = k & 0xff; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (got_addr) { if (dummy) { fprintf(stderr, ">>> dummy: REASSIGN BLOCKS not executed\n"); if (verbose) { fprintf(stderr, " Would have reassigned these blocks:\n"); for (j = 0; j < addr_arr_len; ++j) printf(" 0x%" PRIx64 "\n", addr_arr[j]); } return 0; } res = sg_ll_reassign_blocks(sg_fd, eight, longlist, param_arr, param_len, 1, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "REASSIGN BLOCKS: %s\n", b); goto err_out; } } else /* if (grown || primary) */ { int dl_format = DEF_DEFECT_LIST_FORMAT; int div = 0; int dl_len, got_grown, got_primary; const char * lstp; param_len = 4; memset(param_arr, 0, param_len); res = sg_ll_read_defect10(sg_fd, primary, grown, dl_format, param_arr, param_len, 0, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "READ DEFECT DATA(10): %s\n", b); goto err_out; } if (do_hex) { dStrHex((const char *)param_arr, param_len, 1); goto err_out; /* ret is zero */ } lstp = ""; got_grown = !!(param_arr[1] & 0x8); got_primary = !!(param_arr[1] & 0x10); if (got_grown && got_primary) lstp = "grown and primary defect lists"; else if (got_grown) lstp = "grown defect list"; else if (got_primary) lstp = "primary defect list"; else { fprintf(stderr, "didn't get grown or primary list in response\n"); goto err_out; } if (verbose) fprintf(stderr, "asked for defect list format %d, got %d\n", dl_format, (param_arr[1] & 0x7)); dl_format = (param_arr[1] & 0x7); switch (dl_format) { case 0: /* short block */ div = 4; break; case 3: /* long block */ case 4: /* bytes from index */ case 5: /* physical sector */ div = 8; break; default: fprintf(stderr, "defect list format %d unknown\n", dl_format); break; } dl_len = (param_arr[2] << 8) + param_arr[3]; if (0 == dl_len) printf(">> Elements in %s: 0\n", lstp); else { if (0 == div) printf(">> %s length=%d bytes [unknown number of elements]\n", lstp, dl_len); else printf(">> Elements in %s: %d\n", lstp, dl_len / div); } } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_sat_set_features.c0000664000175000017500000003530712430315266017346 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* This program uses a ATA PASS-THROUGH SCSI command. This usage is * defined in the SCSI to ATA Translation (SAT) drafts and standards. * See http://www.t10.org for drafts. SAT is a standard: SAT ANSI INCITS * 431-2007 (draft prior to that is sat-r09.pdf). SAT-2 is also a * standard: SAT-2 ANSI INCITS 465-2010 and the draft prior to that is * sat2r09.pdf . The SAT-3 project has started and the most recent draft * is sat3r01.pdf . */ /* This program performs a ATA PASS-THROUGH (16) SCSI command in order * to perform an ATA SET FEATURES command. * * See man page (sg_sat_set_features.8) for details. */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK comand */ #define SAT_ATA_PASS_THROUGH12_LEN 12 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d #define ATA_SET_FEATURES 0xef #define DEF_TIMEOUT 20 static const char * version_str = "1.10 20141106"; static struct option long_options[] = { {"count", required_argument, 0, 'c'}, {"ck_cond", no_argument, 0, 'C'}, {"extended", no_argument, 0, 'e'}, {"feature", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"len", required_argument, 0, 'l'}, {"lba", required_argument, 0, 'L'}, {"readonly", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_sat_set_features [--count=CO] [--ck_cond] [--extended] " "[--feature=FEA]\n" " [--help] [--lba=LBA] [--len=16|12] " "[--readonly]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --count=CO | -c CO count field contents (def: 0)\n" " --ck_cond | -C set ck_cond field in pass-through " "(def: 0)\n" " --extended | -e enable extended lba values\n" " --feature=FEA|-f FEA feature field contents\n" " (def: 0 (which is reserved))\n" " --help | -h output this usage message\n" " --lba=LBA | -L LBA LBA field contents (def: 0)\n" " meaning depends on sub-command " "(feature)\n" " --len=16|12 | -l 16|12 cdb length: 16 or 12 bytes " "(def: 16)\n" " --verbose | -v increase verbosity\n" " --readonly | -r open DEVICE read-only (def: " "read-write)\n" " recommended if DEVICE is ATA disk\n" " --version | -V print version string and exit\n\n" "Sends an ATA SET FEATURES command via a SAT pass through.\n" "Primary feature code is placed in '--feature=FEA' with " "'--count=CO' and\n" "'--lba=LBA' being auxiliaries for some features. The arguments " "CO, FEA\n" "and LBA are decimal unless prefixed by '0x' or have a trailing " "'h'.\n" "Example enabling write cache: 'sg_sat_set_feature --feature=2 " "/dev/sdc'\n"); } static int do_set_features(int sg_fd, int feature, int count, uint64_t lba, int cdb_len, int ck_cond, int extend, int verbose) { int res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 3; /* non-data */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> device's LB size */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks (if t_type=0) */ int t_length = 0; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); if (16 == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[14] = ATA_SET_FEATURES; aptCmdBlk[4] = feature; aptCmdBlk[6] = count; aptCmdBlk[8] = lba & 0xff; aptCmdBlk[10] = (lba >> 8) & 0xff; aptCmdBlk[12] = (lba >> 16) & 0xff; aptCmdBlk[7] = (lba >> 24) & 0xff; aptCmdBlk[9] = (lba >> 32) & 0xff; aptCmdBlk[11] = (lba >> 40) & 0xff; aptCmdBlk[1] = (multiple_count << 5) | (protocol << 1) | extend; aptCmdBlk[2] = (ck_cond << 5) | (t_type << 4)| (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, aptCmdBlk, cdb_len, DEF_TIMEOUT, NULL, NULL /* doutp */, 0, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ apt12CmdBlk[9] = ATA_SET_FEATURES; apt12CmdBlk[3] = feature; apt12CmdBlk[4] = count; apt12CmdBlk[5] = lba & 0xff; apt12CmdBlk[6] = (lba >> 8) & 0xff; apt12CmdBlk[7] = (lba >> 16) & 0xff; apt12CmdBlk[1] = (multiple_count << 5) | (protocol << 1); apt12CmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, cdb_len, DEF_TIMEOUT, NULL, NULL /* doutp */, 0, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } if (0 == res) { if (verbose > 2) fprintf(stderr, "command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) sg_print_sense("ATA pass through", sense_buffer, sb_sz, ((verbose > 2) ? 1 : 0)); if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d) not " "supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), bad " "field in cdb\n", cdb_len); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (verbose) fprintf(stderr, "did not find ATA Return " "(sense) Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), Unit Attention " "detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), device not " "ready\n", cdb_len); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), medium or " "hardware error\n", cdb_len); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { fprintf(stderr, "Aborted command: protection " "information\n"); return SG_LIB_CAT_PROTECTION; } else { fprintf(stderr, "Aborted command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: fprintf(stderr, "ATA PASS-THROUGH (%d): data protect, read " "only media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), some sense " "data, use '-v' for more information\n", cdb_len); return SG_LIB_CAT_SENSE; } } else { fprintf(stderr, "CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { fprintf(stderr, "expected descriptor sense format, response " "code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { fprintf(stderr, "SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { fprintf(stderr, "Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { fprintf(stderr, "ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) fprintf(stderr, " try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) fprintf(stderr, "Seem to have got ATA Result Descriptor but " "it was not indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { fprintf(stderr, "error indication in returned FIS: aborted " "command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, ret, res; const char * device_name = NULL; int count = 0; int extend = 0; int rdonly = 0; int feature = 0; uint64_t lba = 0; int verbose = 0; int ck_cond = 0; int cdb_len = SAT_ATA_PASS_THROUGH16_LEN; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:Cef:hl:L:rvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': count = sg_get_num(optarg); if ((count < 0) || (count > 255)) { fprintf(stderr, "bad argument for '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': ck_cond = 1; break; case 'e': extend = 1; break; case 'f': feature = sg_get_num(optarg); if ((feature < 0) || (feature > 255)) { fprintf(stderr, "bad argument for '--feature'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'l': cdb_len = sg_get_num(optarg); if (! ((cdb_len == 12) || (cdb_len == 16))) { fprintf(stderr, "argument to '--len' should be 12 or 16\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': /* up to 32 bits, allow for 48 bits (less -1) */ lba = sg_get_llnum(optarg); if ((uint64_t)-1 == lba) { fprintf(stderr, "bad argument for '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } if (lba > 0xffffffff) extend = 1; break; case 'r': ++rdonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return 1; } if ((lba > 0xffffff) && (12 == cdb_len)) { cdb_len = 16; if (verbose) fprintf(stderr, "Since lba > 0xffffff, forcing cdb length to " "16\n"); } if ((sg_fd = sg_cmds_open_device(device_name, rdonly, verbose)) < 0) { fprintf(stderr, "error opening file: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } ret = do_set_features(sg_fd, feature, count, lba, cdb_len, ck_cond, extend, verbose); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_dd.c0000664000175000017500000023150012406465611014371 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2014 D. Gilbert and P. Allworth * 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. This program is a specialisation of the Unix "dd" command in which either the input or the output file is a scsi generic device, raw device, a block device or a normal file. The block size ('bs') is assumed to be 512 if not given. This program complains if 'ibs' or 'obs' are given with a value that differs from 'bs' (or the default 512). If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is not given or 'of=-' then stdout assumed. A non-standard argument "bpt" (blocks per transfer) is added to control the maximum number of blocks in each transfer. The default value is 128. For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB in this case) is transferred to or from the sg device in a single SCSI command. The actual size of the SCSI READ or WRITE command block can be selected with the "cdbsz" argument. This version is designed for the linux kernel 2.4, 2.6 and 3 series. */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE /* resolves u_char typedef in scsi/scsi.h [lk 2.4] */ #endif #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include #include #include /* */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_io_linux.h" #include "sg_unaligned.h" static const char * version_str = "5.81 20140917"; #define ME "sg_dd: " /* #define SG_DEBUG */ #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 512 #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 DEF_MODE_CDB_SZ 10 #define DEF_MODE_RESP_LEN 252 #define RW_ERR_RECOVERY_MP 1 #define CACHING_MP 8 #define CONTROL_MP 0xa #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #define READ_LONG_OPCODE 0x3E #define READ_LONG_CMD_LEN 10 #define READ_LONG_DEF_BLK_INC 8 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikey value */ #endif #define SG_LIB_FLOCK_ERR 90 #define FT_OTHER 1 /* filetype is probably normal */ #define FT_SG 2 /* filetype is sg char device or supports SG_IO ioctl */ #define FT_RAW 4 /* filetype is raw char device */ #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */ #define FT_ST 16 /* filetype is st char device (tape) */ #define FT_BLOCK 32 /* filetype is block device */ #define FT_FIFO 64 /* filetype is a fifo (name pipe) */ #define FT_ERROR 128 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 /* If platform does not support O_DIRECT then define it harmlessly */ #ifndef O_DIRECT #define O_DIRECT 0 #endif #define MIN_RESERVED_SIZE 8192 #define MAX_UNIT_ATTENTIONS 10 #define MAX_ABORTED_CMDS 256 static int sum_of_resids = 0; static int64_t dd_count = -1; static int64_t req_count = 0; static int64_t in_full = 0; static int in_partial = 0; static int64_t out_full = 0; static int out_partial = 0; static int64_t out_sparse = 0; static int recovered_errs = 0; static int unrecovered_errs = 0; static int read_longs = 0; static int num_retries = 0; static int do_time = 0; static int verbose = 0; static int start_tm_valid = 0; static struct timeval start_tm; static int blk_sz = 0; static int max_uas = MAX_UNIT_ATTENTIONS; static int max_aborted = MAX_ABORTED_CMDS; static int coe_limit = 0; static int coe_count = 0; static unsigned char * zeros_buff = NULL; static int read_long_blk_inc = READ_LONG_DEF_BLK_INC; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; struct flags_t { int append; int cdbsz; int coe; int dio; int direct; int dpo; int dsync; int excl; int fua; int flock; int nocache; int sgio; int pdt; int sparse; int retries; }; static struct flags_t iflag; static struct flags_t oflag; static void calc_duration_throughput(int contin); static void install_handler(int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } static void print_stats(const char * str) { if (0 != dd_count) fprintf(stderr, " remaining block count=%" PRId64 "\n", dd_count); fprintf(stderr, "%s%" PRId64 "+%d records in\n", str, in_full - in_partial, in_partial); fprintf(stderr, "%s%" PRId64 "+%d records out\n", str, out_full - out_partial, out_partial); if (oflag.sparse) fprintf(stderr, "%s%" PRId64 " bypassed records out\n", str, out_sparse); if (recovered_errs > 0) fprintf(stderr, "%s%d recovered errors\n", str, recovered_errs); if (num_retries > 0) fprintf(stderr, "%s%d retries attempted\n", str, num_retries); if (iflag.coe || oflag.coe) { fprintf(stderr, "%s%d unrecovered errors\n", str, unrecovered_errs); fprintf(stderr, "%s%d read_longs fetched part of unrecovered " "read errors\n", str, read_longs); } else if (unrecovered_errs) fprintf(stderr, "%s%d unrecovered error(s)\n", str, unrecovered_errs); } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(sig, &sigact, NULL); fprintf(stderr, "Interrupted by signal,"); if (do_time) calc_duration_throughput(0); print_stats(""); kill(getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ fprintf(stderr, "Progress report, continuing ...\n"); if (do_time) calc_duration_throughput(1); print_stats(" "); } static int bsg_major_checked = 0; static int bsg_major = 0; static void find_bsg_major(void) { const char * proc_devices = "/proc/devices"; FILE *fp; char a[128]; char b[128]; char * cp; int n; if (NULL == (fp = fopen(proc_devices, "r"))) { if (verbose) fprintf(stderr, "fopen %s failed: %s\n", proc_devices, strerror(errno)); return; } while ((cp = fgets(b, sizeof(b), fp))) { if ((1 == sscanf(b, "%s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, sizeof(b), fp))) { if (2 == sscanf(b, "%d %s", &n, a)) { if (0 == strcmp("bsg", a)) { bsg_major = n; break; } } else break; } if (verbose > 5) { if (cp) fprintf(stderr, "found bsg_major=%d\n", bsg_major); else fprintf(stderr, "found no bsg char device in %s\n", proc_devices); } fclose(fp); } static int dd_filetype(const char * filename) { struct stat st; size_t len = strlen(filename); if ((1 == len) && ('.' == filename[0])) return FT_DEV_NULL; if (stat(filename, &st) < 0) return FT_ERROR; if (S_ISCHR(st.st_mode)) { /* major() and minor() defined in sys/sysmacros.h */ if ((MEM_MAJOR == major(st.st_rdev)) && (DEV_NULL_MINOR_NUM == minor(st.st_rdev))) return FT_DEV_NULL; if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(); } if (bsg_major == (int)major(st.st_rdev)) return FT_SG; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; else if (S_ISFIFO(st.st_mode)) return FT_FIFO; return FT_OTHER; } static char * dd_filetype_str(int ft, char * buff) { int off = 0; if (FT_DEV_NULL & ft) off += snprintf(buff + off, 32, "null device "); if (FT_SG & ft) off += snprintf(buff + off, 32, "SCSI generic (sg) device "); if (FT_BLOCK & ft) off += snprintf(buff + off, 32, "block device "); if (FT_FIFO & ft) off += snprintf(buff + off, 32, "fifo (named pipe) "); if (FT_ST & ft) off += snprintf(buff + off, 32, "SCSI tape device "); if (FT_RAW & ft) off += snprintf(buff + off, 32, "raw device "); if (FT_OTHER & ft) off += snprintf(buff + off, 32, "other (perhaps ordinary file) "); if (FT_ERROR & ft) off += snprintf(buff + off, 32, "unable to 'stat' file "); return buff; } static void usage() { fprintf(stderr, "Usage: " "sg_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]" " [iflag=FLAGS]\n" " [obs=BS] [of=OFILE] [oflag=FLAGS] " "[seek=SEEK] [skip=SKIP]\n" " [--help] [--version]\n\n" " [blk_sgio=0|1] [bpt=BPT] [cdbsz=6|10|12|16] " "[coe=0|1|2|3]\n" " [coe_limit=CL] [dio=0|1] [odir=0|1] " "[of2=OFILE2] [retries=RETR]\n" " [sync=0|1] [time=0|1] [verbose=VERB]\n" " where:\n" " blk_sgio 0->block device use normal I/O(def), 1->use " "SG_IO\n" " bpt is blocks_per_transfer (default is 128 or 32 " "when BS>=2048)\n" " bs block size (default is 512)\n"); fprintf(stderr, " cdbsz size of SCSI READ or WRITE cdb (default is " "10)\n" " coe 0->exit on error (def), 1->continue on sg " "error (zero\n" " fill), 2->also try read_long on unrecovered " "reads,\n" " 3->and set the CORRCT bit on the read long\n" " coe_limit limit consecutive 'bad' blocks on reads to CL " "times\n" " when COE>1 (default: 0 which is no limit)\n" " count number of blocks to copy (def: device size)\n" " dio for direct IO, 1->attempt, 0->indirect IO (def)\n" " ibs input block size (if given must be same as " "'bs=')\n" " if file or device to read from (def: stdin)\n" " iflag comma separated list from: [coe,dio,direct," "dpo,dsync,excl,\n" " flock,fua,nocache,null,sgio]\n" " obs output block size (if given must be same as " "'bs=')\n" " odir 1->use O_DIRECT when opening block dev, " "0->don't(def)\n" " of file or device to write to (def: stdout), " "OFILE of '.'\n"); fprintf(stderr, " treated as /dev/null\n" " of2 additional output file (def: /dev/null), " "OFILE2 should be\n" " normal file or pipe\n" " oflag comma separated list from: [append,coe,dio," "direct,dpo,\n" " dsync,excl,flock,fua,nocache,null,sgio," "sparse]\n" " retries retry sgio errors RETR times (def: 0)\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on " "OFILE after copy\n" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose 0->quiet(def), 1->some noise, 2->more noise, " "etc\n" " --help print out this usage message then exit\n" " --version print version information then exit\n\n" "copy from IFILE to OFILE, similar to dd command; " "specialized for SCSI devices\n"); } /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { int res; unsigned int ui; unsigned char rcBuff[RCAP16_REPLY_LEN]; int verb; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 1, verb); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { int64_t ls; res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 1, verb); if (0 != res) return res; ls = (int64_t)sg_get_unaligned_be64(rcBuff); *num_sect = ls + 1; *sect_sz = (int)sg_get_unaligned_be32(rcBuff + 8); } else { ui = sg_get_unaligned_be32(rcBuff); /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)ui + 1; *sect_sz = (int)sg_get_unaligned_be32(rcBuff + 4); } if (verbose) fprintf(stderr, " number of blocks=%" PRId64 " [0x%" PRIx64 "], " "block size=%d\n", *num_sect, *num_sect, *sect_sz); return 0; } /* Return of 0 -> success, -1 -> failure. BLKGETSIZE64, BLKGETSIZE and */ /* BLKSSZGET macros problematic (from or ). */ static int read_blkdev_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { #ifdef BLKSSZGET if ((ioctl(sg_fd, BLKSSZGET, sect_sz) < 0) && (*sect_sz > 0)) { perror("BLKSSZGET ioctl error"); return -1; } else { #ifdef BLKGETSIZE64 uint64_t ull; if (ioctl(sg_fd, BLKGETSIZE64, &ull) < 0) { perror("BLKGETSIZE64 ioctl error"); return -1; } *num_sect = ((int64_t)ull / (int64_t)*sect_sz); if (verbose) fprintf(stderr, " [bgs64] number of blocks=%" PRId64 " [0x%" PRIx64 "], block size=%d\n", *num_sect, *num_sect, *sect_sz); #else unsigned long ul; if (ioctl(sg_fd, BLKGETSIZE, &ul) < 0) { perror("BLKGETSIZE ioctl error"); return -1; } *num_sect = (int64_t)ul; if (verbose) fprintf(stderr, " [bgs] number of blocks=%" PRId64 " [0x%" PRIx64 "], block size=%d\n", *num_sect, *num_sect, *sect_sz); #endif } return 0; #else if (verbose) fprintf(stderr, " BLKSSZGET+BLKGETSIZE ioctl not available\n"); *num_sect = 0; *sect_sz = 0; return -1; #endif } static int sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, int write_true, int fua, int dpo) { int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be24(start_block, cdbp + 1); cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks; if (blocks > 256) { fprintf(stderr, ME "for 6 byte commands, maximum number of " "blocks is 256\n"); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { fprintf(stderr, ME "for 6 byte commands, can't address blocks" " beyond %d\n", 0x1fffff); return 1; } if (dpo || fua) { fprintf(stderr, ME "for 6 byte commands, neither dpo nor fua" " bits supported\n"); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32(start_block, cdbp + 2); sg_put_unaligned_be16(blocks, cdbp + 7); if (blocks & (~0xffff)) { fprintf(stderr, ME "for 10 byte commands, maximum number of " "blocks is %d\n", 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be32(start_block, cdbp + 2); sg_put_unaligned_be32(blocks, cdbp + 6); break; case 16: sz_ind = 3; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); sg_put_unaligned_be64(start_block, cdbp + 2); sg_put_unaligned_be32(blocks, cdbp + 10); break; default: fprintf(stderr, ME "expected cdb size of 6, 10, 12, or 16 but got" " %d\n", cdb_sz); return 1; } return 0; } /* 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb, SG_LIB_CAT_UNIT_ATTENTION -> try again, SG_LIB_CAT_MEDIUM_HARD_WITH_INFO -> 'io_addrp' written to, SG_LIB_CAT_MEDIUM_HARD -> no info field, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_ABORTED_COMMAND, -2 -> ENOMEM -1 other errors */ static int sg_read_low(int sg_fd, unsigned char * buff, int blocks, int64_t from_block, int bs, const struct flags_t * ifp, int * diop, uint64_t * io_addrp) { unsigned char rdCmd[MAX_SCSI_CDBSZ]; unsigned char senseBuff[SENSE_BUFF_LEN]; const unsigned char * sbp; struct sg_io_hdr io_hdr; int res, k, info_valid, slen; if (sg_build_scsi_cdb(rdCmd, ifp->cdbsz, blocks, from_block, 0, ifp->fua, ifp->dpo)) { fprintf(stderr, ME "bad rd cdb build, from_block=%" PRId64 ", blocks=%d\n", from_block, blocks); return SG_LIB_SYNTAX_ERROR; } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = ifp->cdbsz; io_hdr.cmdp = rdCmd; io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = bs * blocks; io_hdr.dxferp = buff; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = (int)from_block; if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (verbose > 2) { fprintf(stderr, " read cdb: "); for (k = 0; k < ifp->cdbsz; ++k) fprintf(stderr, "%02x ", rdCmd[k]); fprintf(stderr, "\n"); } while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return -2; perror("reading (SG_IO) on sg device, error"); return -1; } if (verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); res = sg_err_category3(&io_hdr); sbp = io_hdr.sbp; slen = io_hdr.sb_len_wr; switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: ++recovered_errs; info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp); if (info_valid) { fprintf(stderr, " lba of last recovered error in this " "READ=0x%" PRIx64 "\n", *io_addrp); if (verbose > 1) sg_chk_n_print3("reading", &io_hdr, 1); } else { fprintf(stderr, "Recovered error: [no info] reading from " "block=0x%" PRIx64 ", num=%d\n", from_block, blocks); sg_chk_n_print3("reading", &io_hdr, verbose > 1); } break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: sg_chk_n_print3("reading", &io_hdr, verbose > 1); return res; case SG_LIB_CAT_MEDIUM_HARD: if (verbose > 1) sg_chk_n_print3("reading", &io_hdr, verbose > 1); ++unrecovered_errs; info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp); /* MMC devices don't necessarily set VALID bit */ if ((info_valid) || ((5 == ifp->pdt) && (*io_addrp > 0))) return SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; else { fprintf(stderr, "Medium, hardware or blank check error but " "no lba of failure in sense\n"); return res; } break; case SG_LIB_CAT_NOT_READY: ++unrecovered_errs; if (verbose > 0) sg_chk_n_print3("reading", &io_hdr, verbose > 1); return res; case SG_LIB_CAT_ILLEGAL_REQ: if (5 == ifp->pdt) { /* MMC READs can go down this path */ struct sg_scsi_sense_hdr ssh; int ili; if (verbose > 1) sg_chk_n_print3("reading", &io_hdr, verbose > 1); if (sg_scsi_normalize_sense(sbp, slen, &ssh) && (0x64 == ssh.asc) && (0x0 == ssh.ascq)) { if (sg_get_sense_filemark_eom_ili(sbp, slen, NULL, NULL, &ili) && ili) { info_valid = sg_get_sense_info_fld(sbp, slen, io_addrp); if (*io_addrp > 0) { ++unrecovered_errs; return SG_LIB_CAT_MEDIUM_HARD_WITH_INFO; } else fprintf(stderr, "MMC READ gave 'illegal mode for " "this track' and ILI but no LBA of failure\n"); } ++unrecovered_errs; return SG_LIB_CAT_MEDIUM_HARD; } } /* drop through */ default: ++unrecovered_errs; if (verbose > 0) sg_chk_n_print3("reading", &io_hdr, verbose > 1); return res; } if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = 0; /* flag that dio not done (completely) */ sum_of_resids += io_hdr.resid; return 0; } /* 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb, SG_LIB_CAT_UNIT_ATTENTION -> try again, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_ABORTED_COMMAND, -2 -> ENOMEM, -1 other errors */ static int sg_read(int sg_fd, unsigned char * buff, int blocks, int64_t from_block, int bs, struct flags_t * ifp, int * diop, int * blks_readp) { uint64_t io_addr; int64_t lba; int res, blks, repeat, xferred; unsigned char * bp; int retries_tmp; int ret = 0; int may_coe = 0; retries_tmp = ifp->retries; for (xferred = 0, blks = blocks, lba = from_block, bp = buff; blks > 0; blks = blocks - xferred) { io_addr = 0; repeat = 0; may_coe = 0; res = sg_read_low(sg_fd, bp, blks, lba, bs, ifp, diop, &io_addr); switch (res) { case 0: if (blks_readp) *blks_readp = xferred + blks; if (coe_limit > 0) coe_count = 0; /* good read clears coe_count */ return 0; case -2: /* ENOMEM */ return res; case SG_LIB_CAT_NOT_READY: fprintf(stderr, "Device (r) not ready\n"); return res; case SG_LIB_CAT_ABORTED_COMMAND: if (--max_aborted > 0) { fprintf(stderr, "Aborted command, continuing (r)\n"); repeat = 1; } else { fprintf(stderr, "Aborted command, too many (r)\n"); return res; } break; case SG_LIB_CAT_UNIT_ATTENTION: if (--max_uas > 0) { fprintf(stderr, "Unit attention, continuing (r)\n"); repeat = 1; } else { fprintf(stderr, "Unit attention, too many (r)\n"); return res; } break; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: if (retries_tmp > 0) { fprintf(stderr, ">>> retrying a sgio read, lba=0x%" PRIx64 "\n", (uint64_t)lba); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; repeat = 1; } ret = SG_LIB_CAT_MEDIUM_HARD; break; /* unrecovered read error at lba=io_addr */ case SG_LIB_SYNTAX_ERROR: ifp->coe = 0; ret = res; goto err_out; case -1: ret = res; goto err_out; case SG_LIB_CAT_MEDIUM_HARD: may_coe = 1; default: if (retries_tmp > 0) { fprintf(stderr, ">>> retrying a sgio read, lba=0x%" PRIx64 "\n", (uint64_t)lba); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; repeat = 1; break; } ret = res; goto err_out; } if (repeat) continue; if ((io_addr < (uint64_t)lba) || (io_addr >= (uint64_t)(lba + blks))) { fprintf(stderr, " Unrecovered error lba 0x%" PRIx64 " not " "in correct range:\n\t[0x%" PRIx64 ",0x%" PRIx64 "]\n", io_addr, (uint64_t)lba, (uint64_t)(lba + blks - 1)); may_coe = 1; goto err_out; } blks = (int)(io_addr - (uint64_t)lba); if (blks > 0) { if (verbose) fprintf(stderr, " partial read of %d blocks prior to " "medium error\n", blks); res = sg_read_low(sg_fd, bp, blks, lba, bs, ifp, diop, &io_addr); switch (res) { case 0: break; case -1: ifp->coe = 0; ret = res; goto err_out; case -2: fprintf(stderr, "ENOMEM again, unexpected (r)\n"); return -1; case SG_LIB_CAT_NOT_READY: fprintf(stderr, "device (r) not ready\n"); return res; case SG_LIB_CAT_UNIT_ATTENTION: fprintf(stderr, "Unit attention, unexpected (r)\n"); return res; case SG_LIB_CAT_ABORTED_COMMAND: fprintf(stderr, "Aborted command, unexpected (r)\n"); return res; case SG_LIB_CAT_MEDIUM_HARD_WITH_INFO: case SG_LIB_CAT_MEDIUM_HARD: ret = SG_LIB_CAT_MEDIUM_HARD; goto err_out; case SG_LIB_SYNTAX_ERROR: default: fprintf(stderr, ">> unexpected result=%d from " "sg_read_low() 2\n", res); ret = res; goto err_out; } } xferred += blks; if (0 == ifp->coe) { /* give up at block before problem unless 'coe' */ if (blks_readp) *blks_readp = xferred; return ret; } if (bs < 32) { fprintf(stderr, ">> bs=%d too small for read_long\n", bs); return -1; /* nah, block size can't be that small */ } bp += (blks * bs); lba += blks; if ((0 != ifp->pdt) || (ifp->coe < 2)) { fprintf(stderr, ">> unrecovered read error at blk=%" PRId64 ", " "pdt=%d, use zeros\n", lba, ifp->pdt); memset(bp, 0, bs); } else if (io_addr < UINT_MAX) { unsigned char * buffp; int offset, nl, r, ok, corrct; buffp = (unsigned char*)malloc(bs * 2); if (NULL == buffp) { fprintf(stderr, ">> heap problems\n"); return -1; } corrct = (ifp->coe > 2) ? 1 : 0; res = sg_ll_read_long10(sg_fd, /* pblock */0, corrct, lba, buffp, bs + read_long_blk_inc, &offset, 1, verbose); ok = 0; switch (res) { case 0: ok = 1; ++read_longs; break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: nl = bs + read_long_blk_inc - offset; if ((nl < 32) || (nl > (bs * 2))) { fprintf(stderr, ">> read_long(10) len=%d unexpected\n", nl); break; } /* remember for next read_long attempt, if required */ read_long_blk_inc = nl - bs; if (verbose) fprintf(stderr, "read_long(10): adjusted len=%d\n", nl); r = sg_ll_read_long10(sg_fd, 0, corrct, lba, buffp, nl, &offset, 1, verbose); if (0 == r) { ok = 1; ++read_longs; break; } else fprintf(stderr, ">> unexpected result=%d on second " "read_long(10)\n", r); break; case SG_LIB_CAT_INVALID_OP: fprintf(stderr, ">> read_long(10); not supported\n"); break; case SG_LIB_CAT_ILLEGAL_REQ: fprintf(stderr, ">> read_long(10): bad cdb field\n"); break; case SG_LIB_CAT_NOT_READY: fprintf(stderr, ">> read_long(10): device not ready\n"); break; case SG_LIB_CAT_UNIT_ATTENTION: fprintf(stderr, ">> read_long(10): unit attention\n"); break; case SG_LIB_CAT_ABORTED_COMMAND: fprintf(stderr, ">> read_long(10): aborted command\n"); break; default: fprintf(stderr, ">> read_long(10): problem (%d)\n", res); break; } if (ok) memcpy(bp, buffp, bs); else memset(bp, 0, bs); free(buffp); } else { fprintf(stderr, ">> read_long(10) cannot handle blk=%" PRId64 ", use zeros\n", lba); memset(bp, 0, bs); } ++xferred; bp += bs; ++lba; if ((coe_limit > 0) && (++coe_count > coe_limit)) { if (blks_readp) *blks_readp = xferred + blks; fprintf(stderr, ">> coe_limit on consecutive reads exceeded\n"); return SG_LIB_CAT_MEDIUM_HARD; } } if (blks_readp) *blks_readp = xferred; return 0; err_out: if (ifp->coe) { memset(bp, 0, bs * blks); fprintf(stderr, ">> unable to read at blk=%" PRId64 " for " "%d bytes, use zeros\n", lba, bs * blks); if (blks > 1) fprintf(stderr, ">> try reducing bpt to limit number " "of zeros written near bad block(s)\n"); /* fudge success */ if (blks_readp) *blks_readp = xferred + blks; if ((coe_limit > 0) && (++coe_count > coe_limit)) { fprintf(stderr, ">> coe_limit on consecutive reads exceeded\n"); return ret; } return may_coe ? 0 : ret; } else return ret ? ret : -1; } /* 0 -> successful, SG_LIB_SYNTAX_ERROR -> unable to build cdb, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_MEDIUM_HARD, SG_LIB_CAT_ABORTED_COMMAND, -2 -> recoverable (ENOMEM), -1 -> unrecoverable error + others */ static int sg_write(int sg_fd, unsigned char * buff, int blocks, int64_t to_block, int bs, const struct flags_t * ofp, int * diop) { unsigned char wrCmd[MAX_SCSI_CDBSZ]; unsigned char senseBuff[SENSE_BUFF_LEN]; struct sg_io_hdr io_hdr; int res, k, info_valid; uint64_t io_addr = 0; if (sg_build_scsi_cdb(wrCmd, ofp->cdbsz, blocks, to_block, 1, ofp->fua, ofp->dpo)) { fprintf(stderr, ME "bad wr cdb build, to_block=%" PRId64 ", blocks=%d\n", to_block, blocks); return SG_LIB_SYNTAX_ERROR; } memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = ofp->cdbsz; io_hdr.cmdp = wrCmd; io_hdr.dxfer_direction = SG_DXFER_TO_DEV; io_hdr.dxfer_len = bs * blocks; io_hdr.dxferp = buff; io_hdr.mx_sb_len = SENSE_BUFF_LEN; io_hdr.sbp = senseBuff; io_hdr.timeout = DEF_TIMEOUT; io_hdr.pack_id = (int)to_block; if (diop && *diop) io_hdr.flags |= SG_FLAG_DIRECT_IO; if (verbose > 2) { fprintf(stderr, " write cdb: "); for (k = 0; k < ofp->cdbsz; ++k) fprintf(stderr, "%02x ", wrCmd[k]); fprintf(stderr, "\n"); } while (((res = ioctl(sg_fd, SG_IO, &io_hdr)) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return -2; perror("writing (SG_IO) on sg device, error"); return -1; } if (verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: ++recovered_errs; info_valid = sg_get_sense_info_fld(io_hdr.sbp, io_hdr.sb_len_wr, &io_addr); if (info_valid) { fprintf(stderr, " lba of last recovered error in this " "WRITE=0x%" PRIx64 "\n", io_addr); if (verbose > 1) sg_chk_n_print3("writing", &io_hdr, 1); } else { fprintf(stderr, "Recovered error: [no info] writing to " "block=0x%" PRIx64 ", num=%d\n", to_block, blocks); sg_chk_n_print3("writing", &io_hdr, verbose > 1); } break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: sg_chk_n_print3("writing", &io_hdr, verbose > 1); return res; case SG_LIB_CAT_NOT_READY: ++unrecovered_errs; fprintf(stderr, "device not ready (w)\n"); return res; case SG_LIB_CAT_MEDIUM_HARD: default: sg_chk_n_print3("writing", &io_hdr, verbose > 1); ++unrecovered_errs; if (ofp->coe) { fprintf(stderr, ">> ignored errors for out blk=%" PRId64 " for " "%d bytes\n", to_block, bs * blocks); return 0; /* fudge success */ } else return res; } if (diop && *diop && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) *diop = 0; /* flag that dio not done (completely) */ return 0; } static void calc_duration_throughput(int contin) { struct timeval end_tm, res_tm; double a, b; int64_t blks; if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) { blks = (in_full > out_full) ? in_full : out_full; 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)blk_sz * blks; fprintf(stderr, "time to transfer data%s: %d.%06d secs", (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) fprintf(stderr, " at %.2f MB/sec\n", b / (a * 1000000.0)); else fprintf(stderr, "\n"); } } /* Process arguments given to 'iflag=" or 'oflag=" options. Returns 0 * on success, 1 on error. */ static int process_flags(const char * arg, struct flags_t * fp) { char buff[256]; char * cp; char * np; strncpy(buff, arg, sizeof(buff)); buff[sizeof(buff) - 1] = '\0'; if ('\0' == buff[0]) { fprintf(stderr, "no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = 1; else if (0 == strcmp(cp, "coe")) ++fp->coe; else if (0 == strcmp(cp, "dio")) fp->dio = 1; else if (0 == strcmp(cp, "direct")) fp->direct = 1; else if (0 == strcmp(cp, "dpo")) fp->dpo = 1; else if (0 == strcmp(cp, "dsync")) ++fp->dsync; else if (0 == strcmp(cp, "excl")) fp->excl = 1; else if (0 == strcmp(cp, "fua")) ++fp->fua; else if (0 == strcmp(cp, "nocache")) ++fp->nocache; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "sgio")) fp->sgio = 1; else if (0 == strcmp(cp, "sparse")) ++fp->sparse; else if (0 == strcmp(cp, "flock")) ++fp->flock; else { fprintf(stderr, "unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } /* Process arguments given to 'conv=" option. Returns 0 on success, * 1 on error. */ static int process_conv(const char * arg, struct flags_t * ifp, struct flags_t * ofp) { char buff[256]; char * cp; char * np; strncpy(buff, arg, sizeof(buff)); buff[sizeof(buff) - 1] = '\0'; if ('\0' == buff[0]) { fprintf(stderr, "no conversions found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; #if 0 if (0 == strcmp(cp, "fdatasync")) ++ofp->fdatasync; else if (0 == strcmp(cp, "fsync")) ++ofp->fsync; #endif if (0 == strcmp(cp, "noerror")) ++ifp->coe; /* will still fail on write error */ else if (0 == strcmp(cp, "notrunc")) ; /* this is the default action of ddpt so ignore */ else if (0 == strcmp(cp, "null")) ; #if 0 else if (0 == strcmp(cp, "sparing")) ++ofp->sparing; #endif else if (0 == strcmp(cp, "sparse")) ++ofp->sparse; else if (0 == strcmp(cp, "sync")) ; /* dd(susv4): pad errored block(s) with zeros but ddpt does * that by default. Typical dd use: 'conv=noerror,sync' */ #if 0 else if (0 == strcmp(cp, "trunc")) ++ofp->trunc; #endif else { fprintf(stderr, "unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } /* Returns open input file descriptor (>= 0) or a negative value * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error. */ static int open_if(const char * inf, int64_t skip, int bpt, struct flags_t * ifp, int * in_typep, int verbose) { int infd, flags, fl, t, verb, res; char ebuff[EBUFF_SZ]; struct sg_simple_inquiry_resp sir; verb = (verbose ? verbose - 1: 0); *in_typep = dd_filetype(inf); if (verbose) fprintf(stderr, " >> Input file type: %s\n", dd_filetype_str(*in_typep, ebuff)); if (FT_ERROR & *in_typep) { fprintf(stderr, ME "unable access %s\n", inf); goto file_err; } else if ((FT_BLOCK & *in_typep) && ifp->sgio) *in_typep |= FT_SG; if (FT_ST & *in_typep) { fprintf(stderr, ME "unable to use scsi tape device %s\n", inf); goto file_err; } else if (FT_SG & *in_typep) { flags = O_NONBLOCK; if (ifp->direct) flags |= O_DIRECT; if (ifp->excl) flags |= O_EXCL; if (ifp->dsync) flags |= O_SYNC; fl = O_RDWR; if ((infd = open(inf, fl | flags)) < 0) { fl = O_RDONLY; if ((infd = open(inf, fl | flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); goto file_err; } } if (verbose) fprintf(stderr, " open input(sg_io), flags=0x%x\n", fl | flags); if (sg_simple_inquiry(infd, &sir, 0, verb)) { fprintf(stderr, "INQUIRY failed on %s\n", inf); goto other_err; } ifp->pdt = sir.peripheral_type; if (verbose) fprintf(stderr, " %s: %.8s %.16s %.4s [pdt=%d]\n", inf, sir.vendor, sir.product, sir.revision, ifp->pdt); if (! (FT_BLOCK & *in_typep)) { t = blk_sz * bpt; res = ioctl(infd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror(ME "SG_SET_RESERVED_SIZE error"); res = ioctl(infd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { if (FT_BLOCK & *in_typep) fprintf(stderr, ME "SG_IO unsupported on this block" " device\n"); else fprintf(stderr, ME "sg driver prior to 3.x.y\n"); goto file_err; } } } else { flags = O_RDONLY; if (ifp->direct) flags |= O_DIRECT; if (ifp->excl) flags |= O_EXCL; if (ifp->dsync) flags |= O_SYNC; infd = open(inf, flags); if (infd < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); goto file_err; } else { if (verbose) fprintf(stderr, " open input, flags=0x%x\n", flags); if (skip > 0) { off64_t offset = skip; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", inf); perror(ebuff); goto file_err; } if (verbose) fprintf(stderr, " >> skip: lseek64 SEEK_SET, " "byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } #ifdef HAVE_POSIX_FADVISE if (ifp->nocache) { int rt; rt = posix_fadvise(infd, 0, 0, POSIX_FADV_SEQUENTIAL); if (rt) fprintf(stderr, "open_if: posix_fadvise(SEQUENTIAL), " "err=%d\n", rt); } #endif } } if (ifp->flock) { res = flock(infd, LOCK_EX | LOCK_NB); if (res < 0) { close(infd); snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %s " "failed", inf); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return infd; file_err: return -SG_LIB_FILE_ERROR; other_err: return -SG_LIB_CAT_OTHER; } /* Returns open output file descriptor (>= 0), -1 for don't * bother opening (e.g. /dev/null), or a more negative value * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error. */ static int open_of(const char * outf, int64_t seek, int bpt, struct flags_t * ofp, int * out_typep, int verbose) { int outfd, flags, t, verb, res; char ebuff[EBUFF_SZ]; struct sg_simple_inquiry_resp sir; verb = (verbose ? verbose - 1: 0); *out_typep = dd_filetype(outf); if (verbose) fprintf(stderr, " >> Output file type: %s\n", dd_filetype_str(*out_typep, ebuff)); if ((FT_BLOCK & *out_typep) && ofp->sgio) *out_typep |= FT_SG; if (FT_ST & *out_typep) { fprintf(stderr, ME "unable to use scsi tape device %s\n", outf); goto file_err; } else if (FT_SG & *out_typep) { flags = O_RDWR | O_NONBLOCK; if (ofp->direct) flags |= O_DIRECT; if (ofp->excl) flags |= O_EXCL; if (ofp->dsync) flags |= O_SYNC; if ((outfd = open(outf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg writing", outf); perror(ebuff); goto file_err; } if (verbose) fprintf(stderr, " open output(sg_io), flags=0x%x\n", flags); if (sg_simple_inquiry(outfd, &sir, 0, verb)) { fprintf(stderr, "INQUIRY failed on %s\n", outf); goto other_err; } ofp->pdt = sir.peripheral_type; if (verbose) fprintf(stderr, " %s: %.8s %.16s %.4s [pdt=%d]\n", outf, sir.vendor, sir.product, sir.revision, ofp->pdt); if (! (FT_BLOCK & *out_typep)) { t = blk_sz * bpt; res = ioctl(outfd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror(ME "SG_SET_RESERVED_SIZE error"); res = ioctl(outfd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { fprintf(stderr, ME "sg driver prior to 3.x.y\n"); goto file_err; } } } else if (FT_DEV_NULL & *out_typep) outfd = -1; /* don't bother opening */ else { if (! (FT_RAW & *out_typep)) { flags = O_WRONLY | O_CREAT; if (ofp->direct) flags |= O_DIRECT; if (ofp->excl) flags |= O_EXCL; if (ofp->dsync) flags |= O_SYNC; if (ofp->append) flags |= O_APPEND; if ((outfd = open(outf, flags, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", outf); perror(ebuff); goto file_err; } } else { flags = O_WRONLY; if (ofp->direct) flags |= O_DIRECT; if (ofp->excl) flags |= O_EXCL; if (ofp->dsync) flags |= O_SYNC; if ((outfd = open(outf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for raw writing", outf); perror(ebuff); goto file_err; } } if (verbose) fprintf(stderr, " %s output, flags=0x%x\n", ((O_CREAT & flags) ? "create" : "open"), flags); if (seek > 0) { off64_t offset = seek; offset *= blk_sz; /* could exceed 32 bits here! */ if (lseek64(outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to required position on %s", outf); perror(ebuff); goto file_err; } if (verbose) fprintf(stderr, " >> seek: lseek64 SEEK_SET, " "byte offset=0x%" PRIx64 "\n", (uint64_t)offset); } } if (ofp->flock) { res = flock(outfd, LOCK_EX | LOCK_NB); if (res < 0) { close(outfd); snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %s " "failed", outf); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return outfd; file_err: return -SG_LIB_FILE_ERROR; other_err: return -SG_LIB_CAT_OTHER; } int main(int argc, char * argv[]) { int64_t skip = 0; int64_t seek = 0; int64_t out2_off = 0; int ibs = 0; int obs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int bpt_given = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; int in_type = FT_OTHER; char outf[INOUTF_SZ]; char out2f[INOUTF_SZ]; int out_type = FT_OTHER; int out2_type = FT_OTHER; int dio_incomplete = 0; int cdbsz_given = 0; int do_sync = 0; int blocks = 0; int res, k, t, buf_sz, dio_tmp, first, blocks_per; int infd, outfd, out2fd, retries_tmp, blks_read; int bytes_read, bytes_of2, bytes_of; unsigned char * wrkBuff; unsigned char * wrkPos; int64_t in_num_sect = -1; int64_t out_num_sect = -1; int in_sect_sz, out_sect_sz; char ebuff[EBUFF_SZ]; int sparse_skip = 0; int penult_sparse_skip = 0; int penult_blocks = 0; int ret = 0; inf[0] = '\0'; outf[0] = '\0'; out2f[0] = '\0'; iflag.cdbsz = DEF_SCSI_CDBSZ; oflag.cdbsz = DEF_SCSI_CDBSZ; if (argc < 2) { fprintf(stderr, "Won't default both IFILE to stdin _and_ OFILE to stdout\n"); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } for (k = 1; k < argc; k++) { if (argv[k]) { strncpy(str, argv[k], STR_SZ); str[STR_SZ - 1] = '\0'; } else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (0 == strncmp(key, "app", 3)) { iflag.append = sg_get_num(buf); oflag.append = iflag.append; } else if (0 == strcmp(key, "blk_sgio")) { iflag.sgio = sg_get_num(buf); oflag.sgio = iflag.sgio; } else if (0 == strcmp(key, "bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { fprintf(stderr, ME "bad argument to 'bpt='\n"); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key, "bs")) { blk_sz = sg_get_num(buf); if (-1 == blk_sz) { fprintf(stderr, ME "bad argument to 'bs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "cdbsz")) { iflag.cdbsz = sg_get_num(buf); oflag.cdbsz = iflag.cdbsz; cdbsz_given = 1; } else if (0 == strcmp(key, "coe")) { iflag.coe = sg_get_num(buf); oflag.coe = iflag.coe; } else if (0 == strcmp(key, "coe_limit")) { coe_limit = sg_get_num(buf); if (-1 == coe_limit) { fprintf(stderr, ME "bad argument to 'coe_limit='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "conv")) { if (process_conv(buf, &iflag, &oflag)) { fprintf(stderr, ME "bad argument to 'conv='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if (-1LL == dd_count) { fprintf(stderr, ME "bad argument to 'count='\n"); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key, "dio")) { oflag.dio = sg_get_num(buf); iflag.dio = oflag.dio; } else if (0 == strcmp(key, "fua")) { t = sg_get_num(buf); oflag.fua = (t & 1) ? 1 : 0; iflag.fua = (t & 2) ? 1 : 0; } else if (0 == strcmp(key, "ibs")) ibs = sg_get_num(buf); else if (strcmp(key, "if") == 0) { if ('\0' != inf[0]) { fprintf(stderr, "Second IFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(inf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &iflag)) { fprintf(stderr, ME "bad argument to 'iflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "obs")) obs = sg_get_num(buf); else if (0 == strcmp(key, "odir")) { iflag.direct = sg_get_num(buf); oflag.direct = iflag.direct; } else if (strcmp(key, "of") == 0) { if ('\0' != outf[0]) { fprintf(stderr, "Second OFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(outf, buf, INOUTF_SZ); } else if (strcmp(key, "of2") == 0) { if ('\0' != out2f[0]) { fprintf(stderr, "Second OFILE2 argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(out2f, buf, INOUTF_SZ); } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &oflag)) { fprintf(stderr, ME "bad argument to 'oflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "retries")) { iflag.retries = sg_get_num(buf); oflag.retries = iflag.retries; if (-1 == iflag.retries) { fprintf(stderr, ME "bad argument to 'retries='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "seek")) { seek = sg_get_llnum(buf); if (-1LL == seek) { fprintf(stderr, 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) { fprintf(stderr, ME "bad argument to 'skip='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "sync")) do_sync = sg_get_num(buf); else if (0 == strcmp(key, "time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "verb", 4)) verbose = sg_get_num(buf); else if ((0 == strncmp(key, "--help", 7)) || (0 == strncmp(key, "-h", 2)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if ((0 == strncmp(key, "--vers", 6)) || (0 == strcmp(key, "-V"))) { fprintf(stderr, ME "%s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized option '%s'\n", key); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (blk_sz <= 0) { blk_sz = DEF_BLOCK_SIZE; fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", blk_sz); } if ((ibs && (ibs != blk_sz)) || (obs && (obs != blk_sz))) { fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { fprintf(stderr, "skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if ((oflag.append > 0) && (seek > 0)) { fprintf(stderr, "Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (bpt < 1) { fprintf(stderr, "bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } if (iflag.sparse) fprintf(stderr, "sparse flag ignored for iflag\n"); /* defaulting transfer size to 128*2048 for CD/DVDs is too large for the block layer in lk 2.6 and results in an EIO on the SG_IO ioctl. So reduce it in that case. */ if ((blk_sz >= 2048) && (0 == bpt_given)) bpt = DEF_BLOCKS_PER_2048TRANSFER; #ifdef SG_DEBUG fprintf(stderr, ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", inf, skip, outf, seek, dd_count); #endif install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); infd = STDIN_FILENO; outfd = STDOUT_FILENO; iflag.pdt = -1; oflag.pdt = -1; if (inf[0] && ('-' != inf[0])) { infd = open_if(inf, skip, bpt, &iflag, &in_type, verbose); if (infd < 0) return -infd; } if (outf[0] && ('-' != outf[0])) { outfd = open_of(outf, seek, bpt, &oflag, &out_type, verbose); if (outfd < -1) return -outfd; } if (out2f[0]) { out2_type = dd_filetype(out2f); if ((out2fd = open(out2f, O_WRONLY | O_CREAT, 0666)) < 0) { res = errno; snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", out2f); perror(ebuff); return res; } } else out2fd = -1; if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { fprintf(stderr, "Can't have both 'if' as stdin _and_ 'of' as stdout\n"); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if (oflag.sparse) { if (STDOUT_FILENO == outfd) { fprintf(stderr, "oflag=sparse needs seekable output file\n"); return SG_LIB_SYNTAX_ERROR; } } if ((dd_count < 0) || ((verbose > 0) && (0 == dd_count))) { in_num_sect = -1; in_sect_sz = -1; if (FT_SG & in_type) { res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention (readcap in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "Aborted command (readcap in), continuing\n"); res = scsi_read_capacity(infd, &in_num_sect, &in_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) fprintf(stderr, "read capacity not supported on %s\n", inf); else if (res == SG_LIB_CAT_NOT_READY) fprintf(stderr, "read capacity failed on %s - not " "ready\n", inf); else fprintf(stderr, "Unable to read capacity on %s\n", inf); in_num_sect = -1; } else if (in_sect_sz != blk_sz) fprintf(stderr, ">> warning: block size on %s confusion: " "bs=%d, device claims=%d\n", inf, blk_sz, in_sect_sz); } else if (FT_BLOCK & in_type) { if (0 != read_blkdev_capacity(infd, &in_num_sect, &in_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (blk_sz != in_sect_sz) { fprintf(stderr, "block size on %s confusion: bs=%d, " "device claims=%d\n", inf, blk_sz, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > skip) in_num_sect -= skip; out_num_sect = -1; out_sect_sz = -1; if (FT_SG & out_type) { res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention (readcap out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { fprintf(stderr, "Aborted command (readcap out), continuing\n"); res = scsi_read_capacity(outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) fprintf(stderr, "read capacity not supported on %s\n", outf); else fprintf(stderr, "Unable to read capacity on %s\n", outf); out_num_sect = -1; } else if (blk_sz != out_sect_sz) fprintf(stderr, ">> warning: block size on %s confusion: " "bs=%d, device claims=%d\n", outf, blk_sz, out_sect_sz); } else if (FT_BLOCK & out_type) { if (0 != read_blkdev_capacity(outfd, &out_num_sect, &out_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", outf); out_num_sect = -1; } else if (blk_sz != out_sect_sz) { fprintf(stderr, "block size on %s confusion: bs=%d, " "device claims=%d\n", outf, blk_sz, out_sect_sz); out_num_sect = -1; } } if (out_num_sect > seek) out_num_sect -= seek; #ifdef SG_DEBUG fprintf(stderr, "Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect, out_num_sect); #endif if (dd_count < 0) { if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } } if (dd_count < 0) { fprintf(stderr, "Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! cdbsz_given) { if ((FT_SG & in_type) && (MAX_SCSI_CDBSZ != iflag.cdbsz) && (((dd_count + skip) > UINT_MAX) || (bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'if')\n"); iflag.cdbsz = MAX_SCSI_CDBSZ; } if ((FT_SG & out_type) && (MAX_SCSI_CDBSZ != oflag.cdbsz) && (((dd_count + seek) > UINT_MAX) || (bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'of')\n"); oflag.cdbsz = MAX_SCSI_CDBSZ; } } if (iflag.dio || iflag.direct || oflag.direct || (FT_RAW & in_type) || (FT_RAW & out_type)) { size_t psz; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif #ifdef HAVE_POSIX_MEMALIGN { int err; err = posix_memalign((void **)&wrkBuff, psz, blk_sz * bpt); if (err) { fprintf(stderr, "posix_memalign: error [%d] out of memory?\n", err); return SG_LIB_CAT_OTHER; } wrkPos = wrkBuff; } #else wrkBuff = (unsigned char*)malloc(blk_sz * bpt + psz); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory for raw\n"); return SG_LIB_CAT_OTHER; } wrkPos = (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & (~(psz - 1))); #endif } else { wrkBuff = (unsigned char*)malloc(blk_sz * bpt); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory\n"); return SG_LIB_CAT_OTHER; } wrkPos = wrkBuff; } blocks_per = bpt; #ifdef SG_DEBUG fprintf(stderr, "Start of loop, count=%" PRId64 ", blocks_per=%d\n", dd_count, blocks_per); #endif if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = 1; } req_count = dd_count; /* <<< main loop that does the copy >>> */ while (dd_count > 0) { bytes_read = 0; bytes_of = 0; bytes_of2 = 0; penult_sparse_skip = sparse_skip; penult_blocks = penult_sparse_skip ? blocks : 0; sparse_skip = 0; blocks = (dd_count > blocks_per) ? blocks_per : dd_count; if (FT_SG & in_type) { dio_tmp = iflag.dio; res = sg_read(infd, wrkPos, blocks, skip, blk_sz, &iflag, &dio_tmp, &blks_read); if (-2 == res) { /* ENOMEM, find what's available+try that */ if (ioctl(infd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { perror("RESERVED_SIZE ioctls failed"); ret = res; break; } if (buf_sz < MIN_RESERVED_SIZE) buf_sz = MIN_RESERVED_SIZE; blocks_per = (buf_sz + blk_sz - 1) / blk_sz; if (blocks_per < blocks) { blocks = blocks_per; fprintf(stderr, "Reducing read to %d blocks per " "loop\n", blocks_per); res = sg_read(infd, wrkPos, blocks, skip, blk_sz, &iflag, &dio_tmp, &blks_read); } } if (res) { fprintf(stderr, "sg_read failed,%s at or after lba=%" PRId64 " [0x%" PRIx64 "]\n", ((-2 == res) ? " try reducing bpt," : ""), skip, skip); ret = res; break; } else { if (blks_read < blocks) { dd_count = 0; /* force exit after write */ blocks = blks_read; } in_full += blocks; if (iflag.dio && (0 == dio_tmp)) dio_incomplete++; } } else { while (((res = read(infd, wrkPos, blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "read(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "reading, skip=%" PRId64 " ", skip); perror(ebuff); ret = -1; break; } else if (res < blocks * blk_sz) { dd_count = 0; blocks = res / blk_sz; if ((res % blk_sz) > 0) { blocks++; in_partial++; } } bytes_read = res; in_full += blocks; } if (0 == blocks) break; /* nothing read so leave loop */ if (out2f[0]) { while (((res = write(out2fd, wrkPos, blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "write to of2: count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "writing to of2, seek=%" PRId64 " ", seek); perror(ebuff); ret = -1; break; } bytes_of2 = res; out2_off += res; } if ((oflag.sparse) && (dd_count > blocks) && (! (FT_DEV_NULL & out_type))) { if (NULL == zeros_buff) { zeros_buff = (unsigned char *)malloc(blocks * blk_sz); if (NULL == zeros_buff) { fprintf(stderr, "zeros_buff malloc failed\n"); ret = -1; break; } memset(zeros_buff, 0, blocks * blk_sz); } if (0 == memcmp(wrkPos, zeros_buff, blocks * blk_sz)) sparse_skip = 1; } if (sparse_skip) { if (FT_SG & out_type) { out_sparse += blocks; if (verbose > 2) fprintf(stderr, "sparse bypassing sg_write: seek " "blk=%" PRId64 ", offset blks=%d\n", seek, blocks); } else if (FT_DEV_NULL & out_type) ; else { off64_t offset = blocks * blk_sz; off64_t off_res; if (verbose > 2) fprintf(stderr, "sparse bypassing write: seek=%" PRId64 ", rel offset=%" PRId64 "\n", (seek * blk_sz), (int64_t)offset); off_res = lseek64(outfd, offset, SEEK_CUR); if (off_res < 0) { fprintf(stderr, "sparse tried to bypass write: seek=%" PRId64 ", rel offset=%" PRId64 " but ...\n", (seek * blk_sz), (int64_t)offset); perror("lseek64 on output"); ret = SG_LIB_FILE_ERROR; break; } else if (verbose > 4) fprintf(stderr, "oflag=sparse lseek64 result=%" PRId64 "\n", (int64_t)off_res); out_sparse += blocks; } } else if (FT_SG & out_type) { dio_tmp = oflag.dio; retries_tmp = oflag.retries; first = 1; while (1) { ret = sg_write(outfd, wrkPos, blocks, seek, blk_sz, &oflag, &dio_tmp); if (0 == ret) break; if ((SG_LIB_CAT_NOT_READY == ret) || (SG_LIB_SYNTAX_ERROR == ret)) break; else if ((-2 == ret) && first) { /* ENOMEM: find what's available and try that */ if (ioctl(outfd, SG_GET_RESERVED_SIZE, &buf_sz) < 0) { perror("RESERVED_SIZE ioctls failed"); break; } if (buf_sz < MIN_RESERVED_SIZE) buf_sz = MIN_RESERVED_SIZE; blocks_per = (buf_sz + blk_sz - 1) / blk_sz; if (blocks_per < blocks) { blocks = blocks_per; fprintf(stderr, "Reducing write to %d blocks per " "loop\n", blocks); } else break; } else if ((SG_LIB_CAT_UNIT_ATTENTION == ret) && first) { if (--max_uas > 0) fprintf(stderr, "Unit attention, continuing (w)\n"); else { fprintf(stderr, "Unit attention, too many (w)\n"); break; } } else if ((SG_LIB_CAT_ABORTED_COMMAND == ret) && first) { if (--max_aborted > 0) fprintf(stderr, "Aborted command, continuing (w)\n"); else { fprintf(stderr, "Aborted command, too many (w)\n"); break; } } else if (ret < 0) break; else if (retries_tmp > 0) { fprintf(stderr, ">>> retrying a sgio write, " "lba=0x%" PRIx64 "\n", (uint64_t)seek); --retries_tmp; ++num_retries; if (unrecovered_errs > 0) --unrecovered_errs; } else break; first = 0; } if (0 != ret) { fprintf(stderr, "sg_write failed,%s seek=%" PRId64 "\n", ((-2 == ret) ? " try reducing bpt," : ""), seek); break; } else { out_full += blocks; if (oflag.dio && (0 == dio_tmp)) dio_incomplete++; } } else if (FT_DEV_NULL & out_type) out_full += blocks; /* act as if written out without error */ else { while (((res = write(outfd, wrkPos, blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "write(unix): count=%d, res=%d\n", blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "writing, seek=%" PRId64 " ", seek); perror(ebuff); ret = -1; break; } else if (res < blocks * blk_sz) { fprintf(stderr, "output file probably full, seek=%" PRId64 " ", seek); blocks = res / blk_sz; out_full += blocks; if ((res % blk_sz) > 0) out_partial++; ret = -1; break; } else { out_full += blocks; bytes_of = res; } } #ifdef HAVE_POSIX_FADVISE { int rt, in_valid, out2_valid, out_valid; in_valid = ((FT_OTHER == in_type) || (FT_BLOCK == in_type)); out2_valid = ((FT_OTHER == out2_type) || (FT_BLOCK == out2_type)); out_valid = ((FT_OTHER == out_type) || (FT_BLOCK == out_type)); if (iflag.nocache && (bytes_read > 0) && in_valid) { rt = posix_fadvise(infd, 0, (skip * blk_sz) + bytes_read, POSIX_FADV_DONTNEED); // rt = posix_fadvise(infd, (skip * blk_sz), bytes_read, // POSIX_FADV_DONTNEED); // rt = posix_fadvise(infd, 0, 0, POSIX_FADV_DONTNEED); if (rt) /* returns error as result */ fprintf(stderr, "posix_fadvise on read, skip=" "%" PRId64 " ,err=%d\n", skip, rt); } if ((oflag.nocache & 2) && (bytes_of2 > 0) && out2_valid) { rt = posix_fadvise(out2fd, 0, 0, POSIX_FADV_DONTNEED); if (rt) fprintf(stderr, "posix_fadvise on of2, seek=" "%" PRId64 " ,err=%d\n", seek, rt); } if ((oflag.nocache & 1) && (bytes_of > 0) && out_valid) { rt = posix_fadvise(outfd, 0, 0, POSIX_FADV_DONTNEED); if (rt) fprintf(stderr, "posix_fadvise on output, seek=" "%" PRId64 " ,err=%d\n", seek, rt); } } #endif if (dd_count > 0) dd_count -= blocks; skip += blocks; seek += blocks; } /* end of main loop that does the copy ... */ if (ret && penult_sparse_skip && (penult_blocks > 0)) { /* if error and skipped last output due to sparse ... */ if ((FT_SG & out_type) || (FT_DEV_NULL & out_type)) ; else { /* ... try writing to extend ofile to length prior to error */ while (((res = write(outfd, zeros_buff, penult_blocks * blk_sz)) < 0) && (EINTR == errno)) ; if (verbose > 2) fprintf(stderr, "write(unix, sparse after error): count=%d, " "res=%d\n", penult_blocks * blk_sz, res); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "writing(sparse after error), " "seek=%" PRId64 " ", seek); perror(ebuff); } } } if (do_time) calc_duration_throughput(0); if (do_sync) { if (FT_SG & out_type) { fprintf(stderr, ">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 1, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention (out, sync cache), " "continuing\n"); res = sg_ll_sync_cache_10(outfd, 0, 0, 0, 0, 0, 0, 0); } if (0 != res) fprintf(stderr, "Unable to synchronize cache\n"); } } free(wrkBuff); if (zeros_buff) free(zeros_buff); if (STDIN_FILENO != infd) close(infd); if (! ((STDOUT_FILENO == outfd) || (FT_DEV_NULL & out_type))) close(outfd); if (0 != dd_count) { fprintf(stderr, "Some error occurred,"); if (0 == ret) ret = SG_LIB_CAT_OTHER; } print_stats(""); if (dio_incomplete) { int fd; char c; fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", dio_incomplete); if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", sum_of_resids); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_emc_trespass.c0000664000175000017500000001353612335513125016474 0ustar douggdougg/* The program allows the user to send a trespass command to change the * LUN ownership from one Service-Processor to this one on an EMC * CLARiiON and potentially other devices. * * Copyright (C) 2004-2014 Lars Marowsky-Bree * * Based on sg_start.c; credits from there also apply. * Minor modifications for sg_lib, D. Gilbert 2004/10/19 * * 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. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "0.19 20140516"; static int debug = 0; #define TRESPASS_PAGE 0x22 static int do_trespass(int fd, int hr, int short_cmd) { unsigned char long_trespass_pg[] = { 0, 0, 0, 0, 0, 0, 0, 0x00, TRESPASS_PAGE, /* Page code */ 0x09, /* Page length - 2 */ 0x81, /* Trespass code + Honor reservation * bit */ 0xff, 0xff, /* Trespass target */ 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ }; unsigned char short_trespass_pg[] = { 0, 0, 0, 0, TRESPASS_PAGE, /* Page code */ 0x02, /* Page length - 2 */ 0x81, /* Trespass code + Honor reservation * bit */ 0xff, /* Trespass target */ }; int res; char b[80]; if (hr) { /* override Trespass code + Honor reservation bit */ short_trespass_pg[6] = 0x01; long_trespass_pg[10] = 0x01; } if (short_cmd) res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, short_trespass_pg, sizeof(short_trespass_pg), 1, (debug ? 2 : 0)); else res = sg_ll_mode_select10(fd, 1 /* pf */, 0 /* sp */, long_trespass_pg, sizeof(long_trespass_pg), 1, (debug ? 2 : 0)); switch (res) { case 0: if (debug) fprintf(stderr, "%s trespass successful\n", short_cmd ? "short" : "long"); break; case SG_LIB_CAT_INVALID_OP: case SG_LIB_CAT_ILLEGAL_REQ: fprintf(stderr, "%s form trepass page failed, try again %s " "'-s' option\n", short_cmd ? "short" : "long", short_cmd ? "without" : "with"); break; case SG_LIB_CAT_NOT_READY: fprintf(stderr, "device not ready\n"); break; case SG_LIB_CAT_UNIT_ATTENTION: fprintf(stderr, "unit attention\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, debug); fprintf(stderr, "%s trespass failed: %s\n", (short_cmd ? "short" : "long"), b); break; } return res; } void usage () { fprintf(stderr, "Usage: sg_emc_trespass [-d] [-hr] [-s] " " [-V] DEVICE\n" " Change ownership of a LUN from another SP to this one.\n" " EMC CLARiiON CX-/AX-family + FC5300/FC4500/FC4700.\n" " -d : output debug\n" " -hr: Set Honor Reservation bit\n" " -s : Send Short Trespass Command page (default: long)\n" " (for FC series)\n" " -V: print version string then exit\n" " DEVICE sg or block device (latter in lk 2.6 or lk 3 " "series)\n" " Example: sg_emc_trespass /dev/sda\n"); exit (1); } int main(int argc, char * argv[]) { char **argptr; char * file_name = 0; int k, fd; int hr = 0; int short_cmd = 0; int ret = 0; if (argc < 2) usage (); for (k = 1; k < argc; ++k) { argptr = argv + k; if (!strcmp (*argptr, "-d")) ++debug; else if (!strcmp (*argptr, "-s")) short_cmd = 1; else if (!strcmp (*argptr, "-hr")) hr = 1; else if (!strcmp (*argptr, "-V")) { printf("Version string: %s\n", version_str); exit(0); } else if (*argv[k] == '-') { fprintf(stderr, "Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { fprintf(stderr, "too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { usage(); return SG_LIB_SYNTAX_ERROR; } fd = open(file_name, O_RDWR | O_NONBLOCK); if (fd < 0) { fprintf(stderr, "Error trying to open %s\n", file_name); perror(""); usage(); return SG_LIB_FILE_ERROR; } ret = do_trespass(fd, hr, short_cmd); close (fd); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_referrals.c0000664000175000017500000002442412335161436015773 0ustar douggdougg/* * Copyright (c) 2010-2014 Hannes Reinecke. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* * A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT REFERRALS command to the given * SCSI device. */ static const char * version_str = "1.04 20150515"; /* sbc4r01 */ #define MAX_REFER_BUFF_LEN (1024 * 1024) #define DEF_REFER_BUFF_LEN 256 #define TPGS_STATE_OPTIMIZED 0x0 #define TPGS_STATE_NONOPTIMIZED 0x1 #define TPGS_STATE_STANDBY 0x2 #define TPGS_STATE_UNAVAILABLE 0x3 #define TPGS_STATE_LB_DEPENDENT 0x4 #define TPGS_STATE_OFFLINE 0xe /* SPC-4 rev 9 */ #define TPGS_STATE_TRANSITIONING 0xf static unsigned char referralBuff[DEF_REFER_BUFF_LEN]; static unsigned char * referralBuffp = referralBuff; static const char *decode_tpgs_state(const int st) { switch (st) { case TPGS_STATE_OPTIMIZED: return "active/optimized"; break; case TPGS_STATE_NONOPTIMIZED: return "active/non optimized"; break; case TPGS_STATE_STANDBY: return "standby"; break; case TPGS_STATE_UNAVAILABLE: return "unavailable"; break; case TPGS_STATE_LB_DEPENDENT: return "logical block dependent"; break; case TPGS_STATE_OFFLINE: return "offline"; break; case TPGS_STATE_TRANSITIONING: return "transitioning between states"; break; default: return "unknown"; break; } } static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"lba", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"one-segment", no_argument, 0, 's'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_referrals [--help] [--hex] [--lba=LBA] [--maxlen=LEN]\n" " [--one-segment] [--raw] [--readonly] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" " --lba=LBA|-l LBA starting LBA (logical block address) " "(def: 0)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> %d bytes)\n", DEF_REFER_BUFF_LEN ); fprintf(stderr, " --one-segment|-s return information about the specified " "segment only\n" " --raw|-r output in binary\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT REFERRALS command (SBC-3)\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Decodes given user data referral segment descriptor * the number of blocks and returns the number of bytes processed, * -1 for error. */ static int decode_referral_desc(const unsigned char * ucp, int bytes) { int j, n; uint64_t first, last; if (NULL == ucp) return -1; if (bytes < 20) return -1; first = ((uint64_t)ucp[4] << 56) | ((uint64_t)ucp[5] << 48) | ((uint64_t)ucp[6] << 40) | ((uint64_t)ucp[7] << 32) | ((uint64_t)ucp[8] << 24) | ((uint64_t)ucp[9] << 16) | ((uint64_t)ucp[10] << 8) | (uint64_t)ucp[11]; last = ((uint64_t)ucp[12] << 56) | ((uint64_t)ucp[13] << 48) | ((uint64_t)ucp[14] << 40) | ((uint64_t)ucp[15] << 32) | ((uint64_t)ucp[16] << 24) | ((uint64_t)ucp[17] << 16) | ((uint64_t)ucp[18] << 8) | (uint64_t)ucp[19]; printf(" target port descriptors: %d\n", ucp[3]); printf(" user data segment: first lba %" PRIu64 ", last lba %" PRIu64 "\n", first, last); n = 20; bytes -= n; for (j = 0; j < ucp[3]; j++) { if (bytes < 4) return -1; printf(" target port descriptor %d:\n", j); printf(" port group %x state (%s)\n", (ucp[n+2] << 8) | (ucp[n+3]), decode_tpgs_state(ucp[n] & 0xf)); n += 4; bytes -= 4; } return n; } int main(int argc, char * argv[]) { int sg_fd, k, res, c, rlen; int do_hex = 0; int do_one_segment = 0; int o_readonly = 0; int64_t ll; uint64_t lba = 0; int maxlen = DEF_REFER_BUFF_LEN; int do_raw = 0; int verbose = 0; int desc = 0; const char * device_name = NULL; const unsigned char * ucp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hHl:m:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } lba = (uint64_t)ll; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_REFER_BUFF_LEN)) { fprintf(stderr, "argument to '--maxlen' should be %d or " "less\n", MAX_REFER_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 's': ++do_one_segment; break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "No DEVICE argument given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (maxlen > DEF_REFER_BUFF_LEN) { referralBuffp = (unsigned char *)calloc(maxlen, 1); if (NULL == referralBuffp) { fprintf(stderr, "unable to allocate %d bytes on heap\n", maxlen); return SG_LIB_SYNTAX_ERROR; } } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); ret = SG_LIB_FILE_ERROR; goto free_buff; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto free_buff; } res = sg_ll_report_referrals(sg_fd, lba, do_one_segment, referralBuffp, maxlen, 1, verbose); ret = res; if (0 == res) { if (maxlen >= 4) /* * This is strictly speaking incorrect. However, the * spec reserved bytes 0 and 1, so some implementations * might want to use them to increase the number of * possible user segments. * And maybe someone takes a pity and updates the spec ... */ rlen = (referralBuffp[0] << 24) + (referralBuffp[1] << 16) + (referralBuffp[2] << 8) + referralBuffp[3] + 4; else rlen = maxlen; k = (rlen > maxlen) ? maxlen : rlen; if (do_raw) { dStrRaw((const char *)referralBuffp, k); goto the_end; } if (do_hex) { dStrHex((const char *)referralBuffp, k, 1); goto the_end; } if (maxlen < 4) { if (verbose) fprintf(stderr, "Exiting because allocation length (maxlen) " " less than 4\n"); goto the_end; } if ((verbose > 1) || (verbose && (rlen > maxlen))) { fprintf(stderr, "response length %d bytes\n", rlen); if (rlen > maxlen) fprintf(stderr, " ... which is greater than maxlen " "(allocation length %d), truncation\n", maxlen); } if (rlen > maxlen) rlen = maxlen; ucp = referralBuffp + 4; k = 0; printf("Report referrals:\n"); while (k < rlen - 4) { printf(" descriptor %d:\n", desc); res = decode_referral_desc(ucp + k, rlen - 4 - k); if (res < 0) { fprintf(stderr, "bad user data segment referral descriptor\n"); k = rlen - 4; break; } k += res; desc++; } } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Report Referrals command failed: %s\n", b); } the_end: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) ret = SG_LIB_FILE_ERROR; } free_buff: if (referralBuffp && (referralBuffp != referralBuff)) free(referralBuffp); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_sat_identify.c0000664000175000017500000004054712430315266016472 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* This program uses a ATA PASS-THROUGH SCSI command to package an * ATA IDENTIFY (PACKAGE) DEVICE command. It is based on the SCSI to * ATA Translation (SAT) drafts and standards. See http://www.t10.org * for drafts. SAT is a standard: SAT ANSI INCITS 431-2007 (draft prior * to that is sat-r09.pdf). SAT-2 is also a standard: SAT-2 ANSI INCITS * 465-2010 and the draft prior to that is sat2r09.pdf . The SAT-3 * project has started and the most recent draft is sat3r01.pdf . */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK comand */ #define SAT_ATA_PASS_THROUGH12_LEN 12 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d #define ATA_IDENTIFY_DEVICE 0xec #define ATA_IDENTIFY_PACKET_DEVICE 0xa1 #define ID_RESPONSE_LEN 512 #define DEF_TIMEOUT 20 #define EBUFF_SZ 256 static const char * version_str = "1.11 20141110"; static struct option long_options[] = { {"ck_cond", no_argument, 0, 'c'}, {"extend", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"len", required_argument, 0, 'l'}, {"ident", no_argument, 0, 'i'}, {"packet", no_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_sat_identify [--ck_cond] [--extend] [--help] [--hex] " "[--ident]\n" " [--len=16|12] [--packet] [--raw] " "[--readonly]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --ck_cond|-c sets ck_cond bit in cdb (def: 0)\n" " --extend|-e sets extend bit in cdb (def: 0)\n" " --help|-h print out usage message then exit\n" " --hex|-H output response in hex\n" " --ident|-i output WWN prefixed by 0x, if not available " "output\n" " 0x0000000000000000\n" " --len=16|12 | -l 16|12 cdb length: 16 or 12 bytes " "(default: 16)\n" " --packet|-p do IDENTIFY PACKET DEVICE (def: IDENTIFY " "DEVICE) command\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a ATA IDENTIFY (PACKET) DEVICE command via a SAT " "layer\n"); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static int do_identify_dev(int sg_fd, int do_packet, int cdb_len, int ck_cond, int extend, int do_indent, int do_hex, int do_raw, int verbose) { int ok, j, res, ret; /* Following for ATA READ/WRITE MULTIPLE (EXT) cmds, normally 0 */ int multiple_count = 0; int protocol = 4; /* PIO data-in */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> device's LB size */ int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks (if t_type=0) */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int got_fixsense = 0; /* got ATA result in fixed format sense */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char inBuff[ID_RESPONSE_LEN]; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; const unsigned short * usp; uint64_t ull; sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); ok = 0; if (SAT_ATA_PASS_THROUGH16_LEN == cdb_len) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[6] = 1; /* sector count */ aptCmdBlk[14] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); aptCmdBlk[1] = (multiple_count << 5) | (protocol << 1) | extend; aptCmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, aptCmdBlk, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ apt12CmdBlk[4] = 1; /* sector count */ apt12CmdBlk[9] = (do_packet ? ATA_IDENTIFY_PACKET_DEVICE : ATA_IDENTIFY_DEVICE); apt12CmdBlk[1] = (multiple_count << 5) | (protocol << 1); apt12CmdBlk[2] = (ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, cdb_len, DEF_TIMEOUT, inBuff, NULL /* doutp */, ID_RESPONSE_LEN, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, verbose); } if (0 == res) { ok = 1; if (verbose > 2) fprintf(stderr, "command completed with SCSI GOOD status\n"); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (verbose > 1) sg_print_sense("ATA pass through", sense_buffer, sb_sz, ((verbose > 2) ? 1 : 0)); if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d) not " "supported\n", cdb_len); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), bad " "field in cdb\n", cdb_len); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (0x72 == ssh.response_code) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (verbose) fprintf(stderr, "did not find ATA Return " "(sense) Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (0x70 == ssh.response_code) { got_fixsense = 1; break; } else { if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), " "unexpected response_code=0x%x\n", ssh.response_code, cdb_len); return SG_LIB_CAT_RECOVERED; } } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), Unit Attention " "detected\n", cdb_len); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), device not " "ready\n", cdb_len); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), medium or " "hardware error\n", cdb_len); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { fprintf(stderr, "Aborted command: protection " "information\n"); return SG_LIB_CAT_PROTECTION; } else { fprintf(stderr, "Aborted command: try again with%s '-p' " "option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: fprintf(stderr, "ATA PASS-THROUGH (%d): data protect, read " "only media?\n", cdb_len); return SG_LIB_CAT_DATA_PROTECT; default: if (verbose < 2) fprintf(stderr, "ATA PASS-THROUGH (%d), some sense " "data, use '-v' for more information\n", cdb_len); return SG_LIB_CAT_SENSE; } } else { fprintf(stderr, "CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { fprintf(stderr, "expected descriptor sense format, response " "code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { fprintf(stderr, "SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { fprintf(stderr, "Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { fprintf(stderr, "ATA pass through (%d) failed\n", cdb_len); if (verbose < 2) fprintf(stderr, " try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) fprintf(stderr, "Seem to have got ATA Result Descriptor but " "it was not indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { fprintf(stderr, "error indication in returned FIS: aborted " "command\n"); fprintf(stderr, " try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = 1; } if (got_fixsense) { if (0x4 & sense_buffer[3]) { /* Error is MSB of Info field */ fprintf(stderr, "error indication in returned FIS: aborted " "command\n"); fprintf(stderr, " try again with%s '-p' option\n", (do_packet ? "out" : "")); return SG_LIB_CAT_ABORTED_COMMAND; } ok = 1; } if (ok) { /* output result if it is available */ if (do_raw) dStrRaw((const char *)inBuff, 512); else if (0 == do_hex) { if (do_indent) { usp = (const unsigned short *)inBuff; ull = 0; for (j = 0; j < 4; ++j) { if (j > 0) ull <<= 16; ull |= usp[108 + j]; } printf("0x%016" PRIx64 "\n", ull); } else { printf("Response for IDENTIFY %sDEVICE ATA command:\n", (do_packet ? "PACKET " : "")); dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); } } else if (1 == do_hex) dStrHex((const char *)inBuff, 512, 0); else if (2 == do_hex) dWordHex((const unsigned short *)inBuff, 256, 0, sg_is_big_endian()); else if (3 == do_hex) /* '-HHH' suitable for "hdparm --Istdin" */ dWordHex((const unsigned short *)inBuff, 256, -2, sg_is_big_endian()); else /* '-HHHH' hex bytes only */ dStrHex((const char *)inBuff, 512, -1); } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, res; const char * device_name = NULL; int cdb_len = SAT_ATA_PASS_THROUGH16_LEN; int do_packet = 0; int do_hex = 0; int do_indent = 0; int do_raw = 0; int o_readonly = 0; int verbose = 0; int ck_cond = 0; /* set to 1 to read register(s) back */ int extend = 0; /* set to 1 to send 48 bit LBA with command */ int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "cehHil:prRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': ++ck_cond; break; case 'e': ++extend; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': ++do_indent; break; case 'l': cdb_len = sg_get_num(optarg); if (! ((cdb_len == 12) || (cdb_len == 16))) { fprintf(stderr, "argument to '--len' should be 12 or 16\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': ++do_packet; break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return 1; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose)) < 0) { fprintf(stderr, "error opening file: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } ret = do_identify_dev(sg_fd, do_packet, cdb_len, ck_cond, extend, do_indent, do_hex, do_raw, verbose); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_scan.c.win320000664000175000017500000006123512377503000015665 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* * This utility shows the relationship between various device names and * volumes in Windows OSes (Windows 2000, 2003, XP and Vista). There is * an optional scsi adapter scan. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "sg_lib.h" #ifdef _WIN32_WINNT #if _WIN32_WINNT < 0x0602 #undef _WIN32_WINNT #define _WIN32_WINNT 0x0602 #endif #else #define _WIN32_WINNT 0x0602 /* claim its W8 */ #endif #include "sg_pt_win32.h" static const char * version_str = "1.15 (win32) 20140827"; #define MAX_SCSI_ELEMS 1024 #define MAX_ADAPTER_NUM 64 #define MAX_PHYSICALDRIVE_NUM 512 #define MAX_CDROM_NUM 512 #define MAX_TAPE_NUM 512 #define MAX_HOLE_COUNT 8 // IOCTL_STORAGE_QUERY_PROPERTY #define FILE_DEVICE_MASS_STORAGE 0x0000002d #define IOCTL_STORAGE_BASE FILE_DEVICE_MASS_STORAGE #define FILE_ANY_ACCESS 0 // #define METHOD_BUFFERED 0 #define IOCTL_STORAGE_QUERY_PROPERTY \ CTL_CODE(IOCTL_STORAGE_BASE, 0x0500, METHOD_BUFFERED, FILE_ANY_ACCESS) #ifndef _DEVIOCTL_ typedef enum _STORAGE_BUS_TYPE { BusTypeUnknown = 0x00, BusTypeScsi = 0x01, BusTypeAtapi = 0x02, BusTypeAta = 0x03, BusType1394 = 0x04, BusTypeSsa = 0x05, BusTypeFibre = 0x06, BusTypeUsb = 0x07, BusTypeRAID = 0x08, BusTypeiScsi = 0x09, BusTypeSas = 0x0A, BusTypeSata = 0x0B, BusTypeSd = 0x0C, BusTypeMmc = 0x0D, BusTypeVirtual = 0xE, BusTypeFileBackedVirtual = 0xF, BusTypeMax, BusTypeMaxReserved = 0x7F } STORAGE_BUS_TYPE, *PSTORAGE_BUS_TYPE; typedef struct _STORAGE_DEVICE_DESCRIPTOR { ULONG Version; ULONG Size; UCHAR DeviceType; UCHAR DeviceTypeModifier; BOOLEAN RemovableMedia; BOOLEAN CommandQueueing; ULONG VendorIdOffset; /* 0 if not available */ ULONG ProductIdOffset; /* 0 if not available */ ULONG ProductRevisionOffset;/* 0 if not available */ ULONG SerialNumberOffset; /* -1 if not available ?? */ STORAGE_BUS_TYPE BusType; ULONG RawPropertiesLength; UCHAR RawDeviceProperties[1]; } STORAGE_DEVICE_DESCRIPTOR, *PSTORAGE_DEVICE_DESCRIPTOR; #endif typedef struct _STORAGE_DEVICE_UNIQUE_IDENTIFIER { ULONG Version; ULONG Size; ULONG StorageDeviceIdOffset; ULONG StorageDeviceOffset; ULONG DriveLayoutSignatureOffset; } STORAGE_DEVICE_UNIQUE_IDENTIFIER, *PSTORAGE_DEVICE_UNIQUE_IDENTIFIER; // Use CompareStorageDuids(PSTORAGE_DEVICE_UNIQUE_IDENTIFIER duid1, duid2) // to test for equality #ifndef _DEVIOCTL_ typedef enum _STORAGE_QUERY_TYPE { PropertyStandardQuery = 0, PropertyExistsQuery, PropertyMaskQuery, PropertyQueryMaxDefined } STORAGE_QUERY_TYPE, *PSTORAGE_QUERY_TYPE; typedef enum _STORAGE_PROPERTY_ID { StorageDeviceProperty = 0, StorageAdapterProperty, StorageDeviceIdProperty, StorageDeviceUniqueIdProperty, StorageDeviceWriteCacheProperty, StorageMiniportProperty, StorageAccessAlignmentProperty } STORAGE_PROPERTY_ID, *PSTORAGE_PROPERTY_ID; typedef struct _STORAGE_PROPERTY_QUERY { STORAGE_PROPERTY_ID PropertyId; STORAGE_QUERY_TYPE QueryType; UCHAR AdditionalParameters[1]; } STORAGE_PROPERTY_QUERY, *PSTORAGE_PROPERTY_QUERY; #endif ///////////////////////////////////////////////////////////////////////////// union STORAGE_DEVICE_DESCRIPTOR_DATA { STORAGE_DEVICE_DESCRIPTOR desc; char raw[256]; }; union STORAGE_DEVICE_UID_DATA { STORAGE_DEVICE_UNIQUE_IDENTIFIER desc; char raw[1060]; }; struct storage_elem { char name[32]; char volume_letters[32]; int qp_descriptor_valid; int qp_uid_valid; union STORAGE_DEVICE_DESCRIPTOR_DATA qp_descriptor; union STORAGE_DEVICE_UID_DATA qp_uid; }; static struct storage_elem * storage_arr; static int next_unused_elem = 0; static int verbose = 0; static struct option long_options[] = { {"bus", 0, 0, 'b'}, {"help", 0, 0, 'h'}, {"letter", 1, 0, 'l'}, {"verbose", 0, 0, 'v'}, {"scsi", 0, 0, 's'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: sg_scan [--bus] [--help] [--letter=VL] [--scsi] " "[--verbose] [--version]\n"); fprintf(stderr, " --bus|-b output bus type\n" " --help|-h output this usage message then exit\n" " --letter=VL|-l VL volume letter (e.g. 'F' for F:) " "to match\n" " --scsi|-s show SCSI adapter (tuple) scan\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Scan for storage and related device names\n"); } static char * get_err_str(DWORD err, int max_b_len, char * b) { LPVOID lpMsgBuf; int k, num, ch; if (max_b_len < 2) { if (1 == max_b_len) b[0] = '\0'; return b; } memset(b, 0, max_b_len); FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); num = lstrlen((LPCTSTR)lpMsgBuf); if (num < 1) return b; num = (num < max_b_len) ? num : (max_b_len - 1); for (k = 0; k < num; ++k) { ch = *((LPCTSTR)lpMsgBuf + k); if ((ch >= 0x0) && (ch < 0x7f)) b[k] = ch & 0x7f; else b[k] = '?'; } return b; } static const char * get_bus_type(int bt) { switch (bt) { case BusTypeUnknown: return "Unkno"; case BusTypeScsi: return "Scsi "; case BusTypeAtapi: return "Atapi"; case BusTypeAta: return "Ata "; case BusType1394: return "1394 "; case BusTypeSsa: return "Ssa "; case BusTypeFibre: return "Fibre"; case BusTypeUsb: return "Usb "; case BusTypeRAID: return "RAID "; case BusTypeiScsi: return "iScsi"; case BusTypeSas: return "Sas "; case BusTypeSata: return "Sata "; case BusTypeSd: return "Sd "; case BusTypeMmc: return "Mmc "; case BusTypeVirtual: return "Virt "; case BusTypeFileBackedVirtual: return "FBVir"; case BusTypeMax: return "Max "; default: return "_unkn"; } } static int query_dev_property(HANDLE hdevice, union STORAGE_DEVICE_DESCRIPTOR_DATA * data) { DWORD num_out, err; char b[256]; STORAGE_PROPERTY_QUERY query = {StorageDeviceProperty, PropertyStandardQuery, {0} }; memset(data, 0, sizeof(*data)); if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) { if (verbose > 2) { err = GetLastError(); fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(Devprop) failed, " "Error=%u %s\n", (unsigned int)err, get_err_str(err, sizeof(b), b)); } return -ENOSYS; } if (verbose > 3) fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevProp) " "num_out=%u\n", (unsigned int)num_out); return 0; } static int query_dev_uid(HANDLE hdevice, union STORAGE_DEVICE_UID_DATA * data) { DWORD num_out, err; char b[256]; STORAGE_PROPERTY_QUERY query = {StorageDeviceUniqueIdProperty, PropertyStandardQuery, {0} }; memset(data, 0, sizeof(*data)); num_out = 0; query.QueryType = PropertyExistsQuery; if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), NULL, 0, &num_out, NULL)) { if (verbose > 2) { err = GetLastError(); fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid(exists)) " "failed, Error=%u %s\n", (unsigned int)err, get_err_str(err, sizeof(b), b)); } if (verbose > 3) fprintf(stderr, " num_out=%u\n", (unsigned int)num_out); /* interpret any error to mean this property doesn't exist */ return 0; } query.QueryType = PropertyStandardQuery; if (! DeviceIoControl(hdevice, IOCTL_STORAGE_QUERY_PROPERTY, &query, sizeof(query), data, sizeof(*data), &num_out, NULL)) { if (verbose > 2) { err = GetLastError(); fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid) failed, " "Error=%u %s\n", (unsigned int)err, get_err_str(err, sizeof(b), b)); } return -ENOSYS; } if (verbose > 3) fprintf(stderr, " IOCTL_STORAGE_QUERY_PROPERTY(DevUid) num_out=%u\n", (unsigned int)num_out); return 0; } /* Updates storage_arr based on sep. Returns 1 if update occurred, 0 if * no update occured. */ static int check_devices(const struct storage_elem * sep) { int k, j; struct storage_elem * sarr = storage_arr; for (k = 0; k < next_unused_elem; ++k, ++sarr) { if ('\0' == sarr->name[0]) continue; if (sep->qp_uid_valid && sarr->qp_uid_valid) { if (0 == memcmp(&sep->qp_uid, &sarr->qp_uid, sizeof(sep->qp_uid))) { for (j = 0; j < (int)sizeof(sep->volume_letters); ++j) { if ('\0' == sarr->volume_letters[j]) { sarr->volume_letters[j] = sep->name[0]; break; } } return 1; } } else if (sep->qp_descriptor_valid && sarr->qp_descriptor_valid) { if (0 == memcmp(&sep->qp_descriptor, &sarr->qp_descriptor, sizeof(sep->qp_descriptor))) { for (j = 0; j < (int)sizeof(sep->volume_letters); ++j) { if ('\0' == sarr->volume_letters[j]) { sarr->volume_letters[j] = sep->name[0]; break; } } return 1; } } } return 0; } static int enum_scsi_adapters(void) { int k, j; int hole_count = 0; HANDLE fh; ULONG dummy; DWORD err; BYTE bus; BOOL success; char adapter_name[64]; char inqDataBuff[8192]; PSCSI_ADAPTER_BUS_INFO ai; char b[256]; for (k = 0; k < MAX_ADAPTER_NUM; ++k) { snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\SCSI%d:", k); fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (fh != INVALID_HANDLE_VALUE) { hole_count = 0; success = DeviceIoControl(fh, IOCTL_SCSI_GET_INQUIRY_DATA, NULL, 0, inqDataBuff, sizeof(inqDataBuff), &dummy, NULL); if (success) { PSCSI_BUS_DATA pbd; PSCSI_INQUIRY_DATA pid; int num_lus, off; ai = (PSCSI_ADAPTER_BUS_INFO)inqDataBuff; for (bus = 0; bus < ai->NumberOfBusses; bus++) { pbd = ai->BusData + bus; num_lus = pbd->NumberOfLogicalUnits; off = pbd->InquiryDataOffset; for (j = 0; j < num_lus; ++j) { if ((off < (int)sizeof(SCSI_ADAPTER_BUS_INFO)) || (off > ((int)sizeof(inqDataBuff) - (int)sizeof(SCSI_INQUIRY_DATA)))) break; pid = (PSCSI_INQUIRY_DATA)(inqDataBuff + off); snprintf(b, sizeof(b) - 1, "SCSI%d:%d,%d,%d ", k, pid->PathId, pid->TargetId, pid->Lun); printf("%-15s", b); snprintf(b, sizeof(b) - 1, "claimed=%d pdt=%xh %s ", pid->DeviceClaimed, pid->InquiryData[0] % 0x3f, ((0 == pid->InquiryData[4]) ? "dubious" : "")); printf("%-26s", b); printf("%.8s %.16s %.4s\n", pid->InquiryData + 8, pid->InquiryData + 16, pid->InquiryData + 32); off = pid->NextInquiryDataOffset; } } } else { err = GetLastError(); fprintf(stderr, "%s: IOCTL_SCSI_GET_INQUIRY_DATA failed " "err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); } CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) fprintf(stderr, "%s: in use by other process (sharing " "violation [34])\n", adapter_name); else if (verbose > 3) fprintf(stderr, "%s: CreateFile failed err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); if (++hole_count >= MAX_HOLE_COUNT) break; } } return 0; } static int enum_volumes(char letter) { int k; HANDLE fh; char adapter_name[64]; struct storage_elem tmp_se; if (verbose > 2) fprintf(stderr, "%s: enter\n", __FUNCTION__ ); for (k = 0; k < 24; ++k) { memset(&tmp_se, 0, sizeof(tmp_se)); snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\%c:", 'C' + k); tmp_se.name[0] = 'C' + k; fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (fh != INVALID_HANDLE_VALUE) { if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0) fprintf(stderr, "%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = 1; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) fprintf(stderr, "%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = 1; if (('\0' == letter) || (letter == tmp_se.name[0])) check_devices(&tmp_se); CloseHandle(fh); } } return 0; } static int enum_pds(void) { int k; int hole_count = 0; HANDLE fh; DWORD err; char adapter_name[64]; char b[256]; struct storage_elem tmp_se; if (verbose > 2) fprintf(stderr, "%s: enter\n", __FUNCTION__ ); for (k = 0; k < MAX_PHYSICALDRIVE_NUM; ++k) { memset(&tmp_se, 0, sizeof(tmp_se)); snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\PhysicalDrive%d", k); snprintf(tmp_se.name, sizeof(tmp_se.name), "PD%d", k); fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (fh != INVALID_HANDLE_VALUE) { if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0) fprintf(stderr, "%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = 1; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) fprintf(stderr, "%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = 1; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) fprintf(stderr, "%s: in use by other process (sharing " "violation [34])\n", adapter_name); else if (verbose > 3) fprintf(stderr, "%s: CreateFile failed err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); if (++hole_count >= MAX_HOLE_COUNT) break; } } return 0; } static int enum_cdroms(void) { int k; int hole_count = 0; HANDLE fh; DWORD err; char adapter_name[64]; char b[256]; struct storage_elem tmp_se; if (verbose > 2) fprintf(stderr, "%s: enter\n", __FUNCTION__ ); for (k = 0; k < MAX_CDROM_NUM; ++k) { memset(&tmp_se, 0, sizeof(tmp_se)); snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\CDROM%d", k); snprintf(tmp_se.name, sizeof(tmp_se.name), "CDROM%d", k); fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (fh != INVALID_HANDLE_VALUE) { if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0) fprintf(stderr, "%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = 1; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) fprintf(stderr, "%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = 1; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) fprintf(stderr, "%s: in use by other process (sharing " "violation [34])\n", adapter_name); else if (verbose > 3) fprintf(stderr, "%s: CreateFile failed err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); if (++hole_count >= MAX_HOLE_COUNT) break; } } return 0; } static int enum_tapes(void) { int k; int hole_count = 0; HANDLE fh; DWORD err; char adapter_name[64]; char b[256]; struct storage_elem tmp_se; if (verbose > 2) fprintf(stderr, "%s: enter\n", __FUNCTION__ ); for (k = 0; k < MAX_TAPE_NUM; ++k) { memset(&tmp_se, 0, sizeof(tmp_se)); snprintf(adapter_name, sizeof (adapter_name), "\\\\.\\TAPE%d", k); snprintf(tmp_se.name, sizeof(tmp_se.name), "TAPE%d", k); fh = CreateFile(adapter_name, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (fh != INVALID_HANDLE_VALUE) { if (query_dev_property(fh, &tmp_se.qp_descriptor) < 0) fprintf(stderr, "%s: query_dev_property failed\n", __FUNCTION__ ); else tmp_se.qp_descriptor_valid = 1; if (query_dev_uid(fh, &tmp_se.qp_uid) < 0) { if (verbose > 2) fprintf(stderr, "%s: query_dev_uid failed\n", __FUNCTION__ ); } else tmp_se.qp_uid_valid = 1; hole_count = 0; memcpy(&storage_arr[next_unused_elem++], &tmp_se, sizeof(tmp_se)); CloseHandle(fh); } else { err = GetLastError(); if (ERROR_SHARING_VIOLATION == err) fprintf(stderr, "%s: in use by other process (sharing " "violation [34])\n", adapter_name); else if (verbose > 3) fprintf(stderr, "%s: CreateFile failed err=%u\n\t%s", adapter_name, (unsigned int)err, get_err_str(err, sizeof(b), b)); if (++hole_count >= MAX_HOLE_COUNT) break; } } return 0; } static int sg_do_wscan(char letter, int show_bt, int scsi_scan) { int k, j, n; struct storage_elem * sp; if (scsi_scan < 2) { k = enum_pds(); if (k) return k; k = enum_cdroms(); if (k) return k; k = enum_tapes(); if (k) return k; k = enum_volumes(letter); if (k) return k; for (k = 0; k < next_unused_elem; ++k) { sp = storage_arr + k; if ('\0' == sp->name[0]) continue; printf("%-7s ", sp->name); n = strlen(sp->volume_letters); if (0 == n) printf(" "); else if (1 == n) printf("[%s] ", sp->volume_letters); else if (2 == n) printf("[%s] ", sp->volume_letters); else if (3 == n) printf("[%s] ", sp->volume_letters); else if (4 == n) printf("[%s] ", sp->volume_letters); else printf("[%4s+] ", sp->volume_letters); if (sp->qp_descriptor_valid) { if (show_bt) printf("<%s> ", get_bus_type(sp->qp_descriptor.desc.BusType)); j = sp->qp_descriptor.desc.VendorIdOffset; if (j > 0) printf("%s ", sp->qp_descriptor.raw + j); j = sp->qp_descriptor.desc.ProductIdOffset; if (j > 0) printf("%s ", sp->qp_descriptor.raw + j); j = sp->qp_descriptor.desc.ProductRevisionOffset; if (j > 0) printf("%s ", sp->qp_descriptor.raw + j); j = sp->qp_descriptor.desc.SerialNumberOffset; if (j > 0) printf("%s", sp->qp_descriptor.raw + j); printf("\n"); if (verbose > 2) dStrHexErr(sp->qp_descriptor.raw, 144, 0); } else printf("\n"); if ((verbose > 3) && sp->qp_uid_valid) { printf(" UID valid, in hex:\n"); dStrHexErr(sp->qp_uid.raw, sizeof(sp->qp_uid.raw), 1); } } } if (scsi_scan) { if (scsi_scan < 2) printf("\n"); enum_scsi_adapters(); } return 0; } int main(int argc, char * argv[]) { int c, ret; int vol_letter = 0; int show_bt = 0; int scsi_scan = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bhHl:svV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++show_bt; break; case 'h': case '?': usage(); return 0; case 'l': vol_letter = toupper(optarg[0]); if ((vol_letter < 'C') || (vol_letter > 'Z')) { fprintf(stderr, "'--letter=' expects a letter in the " "'C' to 'Z' range\n"); usage(); return SG_LIB_SYNTAX_ERROR; } break; case 's': ++scsi_scan; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } storage_arr = calloc(sizeof(struct storage_elem) * MAX_SCSI_ELEMS, 1); if (storage_arr) { ret = sg_do_wscan(vol_letter, show_bt, scsi_scan); free(storage_arr); } else { fprintf(stderr, "Failed to allocate storage_arr on heap\n"); ret = SG_LIB_SYNTAX_ERROR; } return ret; } sg3_utils-1.40/src/sg_rbuf.c0000664000175000017500000005035112326640175014744 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999-2014 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. * * This program uses the SCSI command READ BUFFER on the given * device, first to find out how big it is and then to read that * buffer (data mode, buffer id 0). */ #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_io_linux.h" #define RB_MODE_DESC 3 #define RB_MODE_DATA 2 #define RB_MODE_ECHO_DESC 0xb #define RB_MODE_ECHO_DATA 0xa #define RB_DESC_LEN 4 #define RB_DEF_SIZE (200*1024*1024) #define RB_OPCODE 0x3C #define RB_CMD_LEN 10 /* #define SG_DEBUG */ #ifndef SG_FLAG_MMAP_IO #define SG_FLAG_MMAP_IO 4 #endif static const char * version_str = "4.91 20140425"; static struct option long_options[] = { {"buffer", required_argument, 0, 'b'}, {"dio", no_argument, 0, 'd'}, {"echo", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"mmap", no_argument, 0, 'm'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"quick", no_argument, 0, 'q'}, {"size", required_argument, 0, 's'}, {"time", no_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_buffer; int do_dio; int do_echo; int do_help; int do_mmap; int do_quick; int64_t do_size; int do_time; int do_verbose; int do_version; const char * device_name; int opt_new; }; static void usage() { fprintf(stderr, "Usage: sg_rbuf [--buffer=EACH] [--dio] [--echo] " "[--help] [--mmap]\n" " [--quick] [--size=OVERALL] [--time] [--verbose] " "[--version]\n" " DEVICE\n"); fprintf(stderr, " where:\n" " --buffer=EACH|-b EACH buffer size to use (in bytes)\n" " --dio|-d requests dio ('-q' overrides it)\n" " --echo|-e use echo buffer (def: use data mode)\n" " --help|-h print usage message then exit\n" " --mmap|-m requests mmap-ed IO (overrides -q, -d)\n" " --quick|-q quick, don't xfer to user space\n"); fprintf(stderr, " --size=OVERALL|-s OVERALL total size to read (in bytes)\n" " default: 200 MiB\n" " --time|-t time the data transfer\n" " --verbose|-v increase verbosity (more debug)\n" " --version|-V print version string then exit\n\n" "Use SCSI READ BUFFER command (data or echo buffer mode, buffer " "id 0)\nrepeatedly\n"); } static void usage_old() { printf("Usage: sg_rbuf [-b=EACH_KIB] [-d] [-m] [-q] [-s=OVERALL_MIB] " "[-t] [-v] [-V]\n DEVICE\n"); printf(" where:\n"); printf(" -b=EACH_KIB num is buffer size to use (in KiB)\n"); printf(" -d requests dio ('-q' overrides it)\n"); printf(" -e use echo buffer (def: use data mode)\n"); printf(" -m requests mmap-ed IO (overrides -q, -d)\n"); printf(" -q quick, don't xfer to user space\n"); printf(" -s=OVERALL_MIB num is total size to read (in MiB) " "(default: 200 MiB)\n"); printf(" maximum total size is 4000 MiB\n"); printf(" -t time the data transfer\n"); printf(" -v increase verbosity (more debug)\n"); printf(" -V print version string then exit\n\n"); printf("Use SCSI READ BUFFER command (data or echo buffer mode, buffer " "id 0)\nrepeatedly\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; int64_t nn; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dehmNOqs:tvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': n = sg_get_num(optarg); if (n < 0) { fprintf(stderr, "bad argument to '--buffer'\n"); usage_for(optsp); return SG_LIB_SYNTAX_ERROR; } optsp->do_buffer = n; break; case 'd': ++optsp->do_dio; break; case 'e': ++optsp->do_echo; break; case 'h': case '?': ++optsp->do_help; break; case 'm': ++optsp->do_mmap; break; case 'N': break; /* ignore */ case 'O': optsp->opt_new = 0; return 0; case 'q': ++optsp->do_quick; break; case 's': nn = sg_get_llnum(optarg); if (nn < 0) { fprintf(stderr, "bad argument to '--size'\n"); usage_for(optsp); return SG_LIB_SYNTAX_ERROR; } optsp->do_size = nn; 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_for(optsp); 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_for(optsp); 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, num; int64_t nn; 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 'd': ++optsp->do_dio; break; case 'e': ++optsp->do_echo; break; case 'h': case '?': ++optsp->do_help; break; case 'm': ++optsp->do_mmap; break; case 'N': optsp->opt_new = 1; return 0; case 'O': break; case 'q': ++optsp->do_quick; break; case 't': ++optsp->do_time; break; case 'v': ++optsp->do_verbose; break; case 'V': ++optsp->do_version; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("b=", cp, 2)) { num = sscanf(cp + 2, "%d", &optsp->do_buffer); if ((1 != num) || (optsp->do_buffer <= 0)) { printf("Couldn't decode number after 'b=' option\n"); usage_for(optsp); return SG_LIB_SYNTAX_ERROR; } optsp->do_buffer *= 1024; } else if (0 == strncmp("s=", cp, 2)) { nn = sg_get_llnum(optarg); if (nn < 0) { printf("Couldn't decode number after 's=' option\n"); usage_for(optsp); return SG_LIB_SYNTAX_ERROR; } optsp->do_size = nn; optsp->do_size *= 1024 * 1024; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { fprintf(stderr, "Unrecognized option: %s\n", cp); usage_for(optsp); 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_for(optsp); 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, res, j; unsigned int k, num; unsigned char rbCmdBlk [RB_CMD_LEN]; unsigned char * rbBuff = NULL; void * rawp = NULL; unsigned char sense_buffer[32]; int buf_capacity = 0; int buf_size = 0; int64_t total_size = RB_DEF_SIZE; size_t psz; int dio_incomplete = 0; struct sg_io_hdr io_hdr; struct timeval start_tm, end_tm; #ifdef SG_DEBUG int clear = 1; #endif struct opts_t opts; struct opts_t * op; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif op = &opts; memset(op, 0, sizeof(opts)); res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { fprintf(stderr, "No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_buffer > 0) buf_size = op->do_buffer; if (op->do_size > 0) total_size = op->do_size; sg_fd = open(op->device_name, O_RDONLY | O_NONBLOCK); if (sg_fd < 0) { perror("device open error"); return SG_LIB_FILE_ERROR; } if (op->do_mmap) { op->do_dio = 0; op->do_quick = 0; } if (NULL == (rawp = malloc(512))) { printf("out of memory (query)\n"); return SG_LIB_CAT_OTHER; } rbBuff = (unsigned char *)rawp; memset(rbCmdBlk, 0, RB_CMD_LEN); rbCmdBlk[0] = RB_OPCODE; rbCmdBlk[1] = op->do_echo ? RB_MODE_ECHO_DESC : RB_MODE_DESC; rbCmdBlk[8] = RB_DESC_LEN; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rbCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = RB_DESC_LEN; io_hdr.dxferp = rbBuff; io_hdr.cmdp = rbCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (op->do_verbose) { fprintf(stderr, " Read buffer (%sdescriptor) cdb: ", (op->do_echo ? "echo " : "")); for (k = 0; k < RB_CMD_LEN; ++k) fprintf(stderr, "%02x ", rbCmdBlk[k]); fprintf(stderr, "\n"); } /* do normal IO to find RB size (not dio or mmap-ed at this stage) */ if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror("SG_IO READ BUFFER descriptor error"); if (rawp) free(rawp); return SG_LIB_CAT_OTHER; } if (op->do_verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("READ BUFFER descriptor, continuing", &io_hdr, op->do_verbose > 1); /* fall through */ case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, op->do_verbose > 1); if (rawp) free(rawp); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } if (op->do_echo) { buf_capacity = (((0x1f & rbBuff[2]) << 8) | rbBuff[3]); printf("READ BUFFER reports: echo buffer capacity=%d\n", buf_capacity); } else { buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]); printf("READ BUFFER reports: buffer capacity=%d, offset " "boundary=%d\n", buf_capacity, (int)rbBuff[0]); } if (0 == buf_size) buf_size = buf_capacity; else if (buf_size > buf_capacity) { printf("Requested buffer size=%d exceeds reported capacity=%d\n", buf_size, buf_capacity); if (rawp) free(rawp); return SG_LIB_CAT_MALFORMED; } if (rawp) { free(rawp); rawp = NULL; } if (! op->do_dio) { k = buf_size; if (op->do_mmap && (0 != (k % psz))) k = ((k / psz) + 1) * psz; /* round up to page size */ res = ioctl(sg_fd, SG_SET_RESERVED_SIZE, &k); if (res < 0) perror("SG_SET_RESERVED_SIZE error"); } if (op->do_mmap) { rbBuff = (unsigned char *)mmap(NULL, buf_size, PROT_READ, MAP_SHARED, sg_fd, 0); if (MAP_FAILED == rbBuff) { if (ENOMEM == errno) { fprintf(stderr, "mmap() out of memory, try a smaller " "buffer size than %d bytes\n", buf_size); if (op->opt_new) fprintf(stderr, " [with '--buffer=EACH' where EACH " "is in bytes]\n"); else fprintf(stderr, " [with '-b=EACH' where EACH is in " "KiB]\n"); } else perror("error using mmap()"); return SG_LIB_CAT_OTHER; } } else { /* non mmap-ed IO */ rawp = (unsigned char *)malloc(buf_size + (op->do_dio ? psz : 0)); if (NULL == rawp) { printf("out of memory (data)\n"); return SG_LIB_CAT_OTHER; } /* perhaps use posix_memalign() instead */ if (op->do_dio) /* align to page boundary */ rbBuff= (unsigned char *)(((unsigned long)rawp + psz - 1) & (~(psz - 1))); else rbBuff = (unsigned char *)rawp; } num = total_size / buf_size; if (op->do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } /* main data reading loop */ for (k = 0; k < num; ++k) { memset(rbCmdBlk, 0, RB_CMD_LEN); rbCmdBlk[0] = RB_OPCODE; rbCmdBlk[1] = op->do_echo ? RB_MODE_ECHO_DATA : RB_MODE_DATA; rbCmdBlk[6] = 0xff & (buf_size >> 16); rbCmdBlk[7] = 0xff & (buf_size >> 8); rbCmdBlk[8] = 0xff & buf_size; #ifdef SG_DEBUG memset(rbBuff, 0, buf_size); #endif memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rbCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = buf_size; if (! op->do_mmap) io_hdr.dxferp = rbBuff; io_hdr.cmdp = rbCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ io_hdr.pack_id = k; if (op->do_mmap) io_hdr.flags |= SG_FLAG_MMAP_IO; else if (op->do_dio) io_hdr.flags |= SG_FLAG_DIRECT_IO; else if (op->do_quick) io_hdr.flags |= SG_FLAG_NO_DXFER; if (op->do_verbose > 1) { fprintf(stderr, " Read buffer (%sdata) cdb: ", (op->do_echo ? "echo " : "")); for (j = 0; j < RB_CMD_LEN; ++j) fprintf(stderr, "%02x ", rbCmdBlk[j]); fprintf(stderr, "\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { if (ENOMEM == errno) { fprintf(stderr, "SG_IO data: out of memory, try a smaller " "buffer size than %d bytes\n", buf_size); if (op->opt_new) fprintf(stderr, " [with '--buffer=EACH' where EACH " "is in bytes]\n"); else fprintf(stderr, " [with '-b=EACH' where EACH is in " "KiB]\n"); } else perror("SG_IO READ BUFFER data error"); if (rawp) free(rawp); return SG_LIB_CAT_OTHER; } if (op->do_verbose > 2) fprintf(stderr, " duration=%u ms\n", io_hdr.duration); /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr, op->do_verbose > 1); break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER data error", &io_hdr, op->do_verbose > 1); if (rawp) free(rawp); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } if (op->do_dio && ((io_hdr.info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) dio_incomplete = 1; /* flag that dio not done (completely) */ #ifdef SG_DEBUG if (clear) { for (j = 0; j < buf_size; ++j) { if (rbBuff[j] != 0) { clear = 0; break; } } } #endif } if ((op->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)buf_size * num; printf("time to read data from buffer was %d.%06d secs", (int)res_tm.tv_sec, (int)res_tm.tv_usec); if (a > 0.00001) { if (b > 511) printf(", %.2f MB/sec", b / (a * 1000000.0)); printf(", %.2f IOPS", num / a); } printf("\n"); } if (dio_incomplete) printf(">> direct IO requested but not done\n"); printf("Read %" PRId64 " MiB (actual: %" PRId64 " bytes), buffer " "size=%d KiB (%d bytes)\n", (total_size / (1024 * 1024)), (int64_t)num * buf_size, buf_size / 1024, buf_size); if (rawp) free(rawp); res = close(sg_fd); if (res < 0) { perror("close error"); return SG_LIB_FILE_ERROR; } #ifdef SG_DEBUG if (clear) printf("read buffer always zero\n"); else printf("read buffer non-zero\n"); #endif return (res >= 0) ? res : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_luns.c0000664000175000017500000006077012345113227014767 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI REPORT LUNS command to the given SCSI device * and decodes the response. */ static const char * version_str = "1.27 20140607"; #define MAX_RLUNS_BUFF_LEN (1024 * 1024) #define DEF_RLUNS_BUFF_LEN (1024 * 8) static struct option long_options[] = { {"decode", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, #ifdef SG_LIB_LINUX {"linux", no_argument, 0, 'l'}, #endif {"lu_cong", no_argument, 0, 'L'}, {"maxlen", required_argument, 0, 'm'}, {"quiet", no_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"select", required_argument, 0, 's'}, {"test", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { #ifdef SG_LIB_LINUX pr2serr("Usage: " "sg_luns [--decode] [--help] [--hex] [--linux] " "[--lu_cong]\n" " [--maxlen=LEN] [--quiet] [--raw] " "[--readonly]\n" " [--select=SR] [--verbose] [--version] " "DEVICE\n"); #else pr2serr("Usage: " "sg_luns [--decode] [--help] [--hex] [--lu_cong] " "[--maxlen=LEN]\n" " [--quiet] [--raw] [--readonly] " "[--select=SR]\n" " [--verbose] [--version] DEVICE\n"); #endif pr2serr(" or\n" " sg_luns --test=ALUN [--hex] [--lu_cong] [--verbose]\n" " where:\n" " --decode|-d decode all luns into component parts\n" " --help|-h print out usage message\n" " --hex|-H output response in hexadecimal; used " "twice\n" " shows decoded values in hex\n"); #ifdef SG_LIB_LINUX pr2serr(" --linux|-l show Linux integer lun after T10 " "representation\n"); #endif pr2serr(" --lu_cong decode as if LU_CONG is set; used " "twice:\n" " decode as if LU_CONG is clear\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> %d bytes)\n" " --quiet|-q output only ASCII hex lun values\n" " --raw|-r output response in binary\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --select=SR|-s SR select report SR (def: 0)\n" " 0 -> luns apart from 'well " "known' lus\n" " 1 -> only 'well known' " "logical unit numbers\n" " 2 -> all luns\n" " 0x10 -> administrative luns\n" " 0x11 -> admin luns + " "non-conglomerate luns\n" " 0x12 -> admin lun + its " "subsidiary luns\n" " --test=ALUN|-t ALUN decode ALUN and ignore most other " "options\n" " and DEVICE (apart from '-H')\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT LUNS command or decodes the given ALUN. " "When SR is\n0x10 or 0x11 DEVICE must be LUN 0 or REPORT LUNS " "well known logical unit;\nwhen SR is 0x12 DEVICE must be an " "administrative logical unit. When the\n--test=ALUN option is " "given, decodes ALUN rather than sending a REPORT\nLUNS " "command.\n", DEF_RLUNS_BUFF_LEN ); } /* Decoded according to SAM-5 rev 10. Note that one draft: BCC rev 0, * defines its own "bridge addressing method" in place of the SAM-3 * "logical addressing method". */ static void decode_lun(const char * leadin, const unsigned char * lunp, int lu_cong, int do_hex, int verbose) { int k, j, x, a_method, bus_id, target, lun, len_fld, e_a_method; int next_level, lu_cong_admin; unsigned char not_spec[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; char l_leadin[128]; char b[256]; uint64_t ull; if (0 == memcmp(lunp, not_spec, sizeof(not_spec))) { printf("%sLogical unit not specified\n", leadin); return; } lu_cong_admin = lu_cong; memset(l_leadin, 0, sizeof(l_leadin)); for (k = 0; k < 4; ++k, lunp += 2) { next_level = 0; strncpy(l_leadin, leadin, sizeof(l_leadin) - 3); if (k > 0) { if (lu_cong) { lu_cong_admin = 0; if ((0 == lunp[0]) && (0 == lunp[1])) { printf("%s>>>> Administrative LU\n", l_leadin); if (do_hex || verbose) printf(" since Subsidiary element is " "0x0000\n"); break; } else printf("%s>>Subsidiary element:\n", l_leadin); } else printf("%s>>%s level addressing:\n", l_leadin, ((1 == k) ? "Second" : ((2 == k) ? "Third" : "Fourth"))); strcat(l_leadin, " "); } else if (lu_cong) { printf("%s>>Administrative element:\n", l_leadin); strcat(l_leadin, " "); } a_method = (lunp[0] >> 6) & 0x3; switch (a_method) { case 0: /* peripheral device addressing method */ if (lu_cong) { snprintf(b, sizeof(b), "%sSimple lu addressing: ", l_leadin); x = ((lunp[0] & 0x3f) << 8) + lunp[1]; if (do_hex) printf("%s0x%04x\n", b, x); else printf("%s%d\n", b, x); if (lu_cong_admin) next_level = 1; } else { bus_id = lunp[0] & 0x3f; snprintf(b, sizeof(b), "%sPeripheral device addressing: ", l_leadin); if ((0 == bus_id) && (0 == verbose)) { if (do_hex) printf("%slun=0x%02x\n", b, lunp[1]); else printf("%slun=%d\n", b, lunp[1]); } else { if (do_hex) printf("%sbus_id=0x%02x, %s=0x%02x\n", b, bus_id, (bus_id ? "target" : "lun"), lunp[1]); else printf("%sbus_id=%d, %s=%d\n", b, bus_id, (bus_id ? "target" : "lun"), lunp[1]); } if (bus_id) next_level = 1; } break; case 1: /* flat space addressing method */ lun = ((lunp[0] & 0x3f) << 8) + lunp[1]; if (lu_cong) { printf("%sSince LU_CONG=1, unexpected Flat space " "addressing: lun=0x%04x\n", l_leadin, lun); break; } if (do_hex) printf("%sFlat space addressing: lun=0x%04x\n", l_leadin, lun); else printf("%sFlat space addressing: lun=%d\n", l_leadin, lun); break; case 2: /* logical unit addressing method */ target = (lunp[0] & 0x3f); bus_id = (lunp[1] >> 5) & 0x7; lun = lunp[1] & 0x1f; if (lu_cong) { printf("%sSince LU_CONG=1, unexpected lu addressing: " "bus_id=0x%x, target=0x%02x, lun=0x%02x\n", l_leadin, bus_id, target, lun); break; } if (do_hex) printf("%sLogical unit addressing: bus_id=0x%x, " "target=0x%02x, lun=0x%02x\n", l_leadin, bus_id, target, lun); else printf("%sLogical unit addressing: bus_id=%d, target=%d, " "lun=%d\n", l_leadin, bus_id, target, lun); break; case 3: /* extended logical unit + flat space addressing */ len_fld = (lunp[0] & 0x30) >> 4; e_a_method = lunp[0] & 0xf; x = lunp[1]; if ((0 == len_fld) && (1 == e_a_method)) { snprintf(b, sizeof(b), "well known logical unit"); switch (x) { case 1: printf("%sREPORT LUNS %s\n", l_leadin, b); break; case 2: printf("%sACCESS CONTROLS %s\n", l_leadin, b); break; case 3: printf("%sTARGET LOG PAGES %s\n", l_leadin, b); break; case 4: printf("%sSECURITY PROTOCOL %s\n", l_leadin, b); break; default: if (do_hex) printf("%s%s 0x%02x\n", l_leadin, b, x); else printf("%s%s %d\n", l_leadin, b, x); break; } } else if ((1 == len_fld) && (2 == e_a_method)) { x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3]; if (do_hex) printf("%sExtended flat space addressing: lun=0x%06x\n", l_leadin, x); else printf("%sExtended flat space addressing: lun=%d\n", l_leadin, x); } else if ((2 == len_fld) && (2 == e_a_method)) { ull = 0; for (j = 0; j < 5; ++j) { if (j > 0) ull <<= 8; ull |= lunp[1 + j]; } if (do_hex) printf("%sLong extended flat space addressing: " "lun=0x%010" PRIx64 "\n", l_leadin, ull); else printf("%sLong extended flat space addressing: " "lun=%" PRIu64 "\n", l_leadin, ull); } else if ((3 == len_fld) && (0xf == e_a_method)) printf("%sLogical unit _not_ specified addressing\n", l_leadin); else { if (len_fld < 2) { if (1 == len_fld) x = (lunp[1] << 16) + (lunp[2] << 8) + lunp[3]; if (do_hex) printf("%sExtended logical unit addressing: " "length=%d, e.a. method=%d, value=0x%06x\n", l_leadin, len_fld, e_a_method, x); else printf("%sExtended logical unit addressing: " "length=%d, e.a. method=%d, value=%d\n", l_leadin, len_fld, e_a_method, x); } else { ull = 0; x = (2 == len_fld) ? 5 : 7; for (j = 0; j < x; ++j) { if (j > 0) ull <<= 8; ull |= lunp[1 + j]; } if (do_hex) { printf("%sExtended logical unit addressing: " "length=%d, e. a. method=%d, ", l_leadin, len_fld, e_a_method); if (5 == len_fld) printf("value=0x%010" PRIx64 "\n", ull); else printf("value=0x%014" PRIx64 "\n", ull); } else printf("%sExtended logical unit addressing: " "length=%d, e. a. method=%d, value=%" PRIu64 "\n", l_leadin, len_fld, e_a_method, ull); } } break; default: printf("%s<>\n", l_leadin); break; } if (next_level) continue; if ((2 == a_method) && (k < 3) && (lunp[2] || lunp[3])) printf("%s<>\n", l_leadin); break; } } #ifdef SG_LIB_LINUX static void linux2t10_lun(uint64_t linux_lun, unsigned char t10_lun[]) { int k; unsigned int u; for (k = 0; k < 4; ++k, linux_lun >>= 16) { u = linux_lun & 0xffff; t10_lun[(2 * k) + 1] = u & 0xff; t10_lun[2 * k] = (u >> 8) & 0xff; } } static uint64_t t10_2linux_lun(const unsigned char t10_lun[]) { const unsigned char * cp; uint64_t res; res = (t10_lun[6] << 8) + t10_lun[7]; for (cp = t10_lun + 4; cp >= t10_lun; cp -= 2) { res <<= 16; res += (*cp << 8) + *(cp + 1); } return res; } /* Copy of t10_lun --> Linux unsigned int (i.e. 32 bit ) present in Linux * kernel, up to least lk 3.8.0, extended to 64 bits. * BEWARE: for sizeof(int==4) this function is BROKEN and is left here as * as example and may soon be removed. */ static uint64_t t10_2linux_lun64bitBR(const unsigned char t10_lun[]) { int i; uint64_t lun; lun = 0; for (i = 0; i < (int)sizeof(lun); i += 2) lun = lun | (((t10_lun[i] << 8) | t10_lun[i + 1]) << (i * 8)); return lun; } #endif /* SG_LIB_LINUX */ static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, k, m, off, res, c, list_len, len_cap, luns, trunc; int decode = 0; int do_hex = 0; #ifdef SG_LIB_LINUX int do_linux = 0; #endif int lu_cong = 0; int lu_cong_given = 0; int maxlen = 0; int do_quiet = 0; int do_raw = 0; int o_readonly = 0; int select_rep = 0; int verbose = 0; #ifdef SG_LIB_LINUX int test_linux_in = 0; int test_linux_out = 0; int test_linux_out2 = 0; #endif unsigned int h; const char * test_arg = NULL; const char * device_name = NULL; const char * cp; unsigned char lun_arr[8]; struct sg_simple_inquiry_resp sir; unsigned char * reportLunsBuff = NULL; int ret = 0; while (1) { int option_index = 0; #ifdef SG_LIB_LINUX c = getopt_long(argc, argv, "dhHlLm:qrRs:t:vV", long_options, &option_index); #else c = getopt_long(argc, argv, "dhHLm:qrRs:t:vV", long_options, &option_index); #endif if (c == -1) break; switch (c) { case 'd': decode = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; #ifdef SG_LIB_LINUX case 'l': ++do_linux; break; #endif case 'L': ++lu_cong; ++lu_cong_given; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_RLUNS_BUFF_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MAX_RLUNS_BUFF_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'q': ++do_quiet; break; case 'r': ++do_raw; break; case 'R': ++o_readonly; break; case 's': select_rep = sg_get_num(optarg); if ((select_rep < 0) || (select_rep > 255)) { pr2serr("bad argument to '--select', expect 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': test_arg = optarg; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (test_arg) { memset(lun_arr, 0, sizeof(lun_arr)); cp = test_arg; /* check for leading 'L' */ #ifdef SG_LIB_LINUX if ('L' == toupper(cp[0])) { uint64_t ull; if (1 != sscanf(cp + 1, " %" SCNu64, &ull)) { pr2serr("Unable to read Linux style LUN integer given to " "--test=\n"); return SG_LIB_SYNTAX_ERROR; } linux2t10_lun(ull, lun_arr); test_linux_in = 1; } else #endif { /* Check if trailing 'L' or 'W' */ m = strlen(cp); /* must be at least 1 char in test_arg */ #ifdef SG_LIB_LINUX if ('L' == toupper(cp[m - 1])) test_linux_out = 1; else if ('W' == toupper(cp[m - 1])) test_linux_out2 = 1; #endif if (('0' == cp[0]) && ('X' == toupper(cp[1]))) cp += 2; if (strchr(cp, ' ') || strchr(cp, '\t')) { for (k = 0; k < 8; ++k, cp += m) { if (1 != sscanf(cp, " %2x%n", &h, &m)) break; lun_arr[k] = h & 0xff; } } else { for (k = 0; k < 8; ++k, cp += 2) { if (1 != sscanf(cp, "%2x", &h)) break; lun_arr[k] = h & 0xff; } } if (0 == k) { pr2serr("expected a hex number, optionally prefixed by " "'0x'\n"); return SG_LIB_SYNTAX_ERROR; } } #ifdef SG_LIB_LINUX if (verbose || test_linux_in || test_linux_out2) #else if (verbose) #endif { printf("64 bit LUN in T10 preferred (hex) format: "); for (k = 0; k < 8; ++k) printf(" %02x", lun_arr[k]); printf("\n"); } #ifdef SG_LIB_LINUX if (test_linux_out) { if (do_hex > 1) printf("Linux 'word flipped' integer LUN representation: " "0x%016" PRIx64 "\n", t10_2linux_lun(lun_arr)); else if (do_hex) printf("Linux 'word flipped' integer LUN representation: 0x%" PRIx64 "\n", t10_2linux_lun(lun_arr)); else printf("Linux 'word flipped' integer LUN representation: %" PRIu64 "\n", t10_2linux_lun(lun_arr)); } else if (test_linux_out2) { if (do_hex > 1) printf("Linux internal 64 bit LUN representation: 0x%016" PRIx64 "\n", t10_2linux_lun64bitBR(lun_arr)); else if (do_hex) printf("Linux internal 64 bit LUN representation: 0x%" PRIx64 "\n", t10_2linux_lun64bitBR(lun_arr)); else printf("Linux internal 64 bit LUN representation: %" PRIu64 "\n", t10_2linux_lun64bitBR(lun_arr)); } #endif printf("Decoded LUN:\n"); decode_lun(" ", lun_arr, (lu_cong % 2), do_hex, verbose); return 0; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (decode && (! lu_cong_given)) { /* check if LU_CONG set in standard INQUIRY response */ res = sg_simple_inquiry(sg_fd, &sir, 0, verbose); ret = res; if (res) { pr2serr("fetching standard INQUIRY response failed\n"); goto the_end; } lu_cong = !!(0x40 & sir.byte_1); if (verbose && lu_cong) pr2serr("LU_CONG bit set in standard INQUIRY response\n"); } if (0 == maxlen) maxlen = DEF_RLUNS_BUFF_LEN; reportLunsBuff = (unsigned char *)calloc(1, maxlen); if (NULL == reportLunsBuff) { pr2serr("unable to malloc %d bytes\n", maxlen); return SG_LIB_CAT_OTHER; } trunc = 0; res = sg_ll_report_luns(sg_fd, select_rep, reportLunsBuff, maxlen, 1, verbose); ret = res; if (0 == res) { list_len = (reportLunsBuff[0] << 24) + (reportLunsBuff[1] << 16) + (reportLunsBuff[2] << 8) + reportLunsBuff[3]; len_cap = list_len + 8; if (len_cap > maxlen) len_cap = maxlen; if (do_raw) { dStrRaw((const char *)reportLunsBuff, len_cap); goto the_end; } if (1 == do_hex) { dStrHex((const char *)reportLunsBuff, len_cap, 1); goto the_end; } luns = (list_len / 8); if (0 == do_quiet) printf("Lun list length = %d which imples %d lun entr%s\n", list_len, luns, ((1 == luns) ? "y" : "ies")); if ((list_len + 8) > maxlen) { luns = ((maxlen - 8) / 8); trunc = 1; pr2serr(" <>\n", luns, ((1 == luns) ? "" : "s")); } if (verbose > 1) { pr2serr("\nOutput response in hex\n"); dStrHexErr((const char *)reportLunsBuff, (trunc ? maxlen : list_len + 8), 1); } for (k = 0, off = 8; k < luns; ++k, off += 8) { if (0 == do_quiet) { if (0 == k) printf("Report luns [select_report=0x%x]:\n", select_rep); printf(" "); } for (m = 0; m < 8; ++m) printf("%02x", reportLunsBuff[off + m]); #ifdef SG_LIB_LINUX if (do_linux) { uint64_t lin_lun; lin_lun = t10_2linux_lun(reportLunsBuff + off); if (do_hex > 1) printf(" [0x%" PRIx64 "]", lin_lun); else printf(" [%" PRIu64 "]", lin_lun); } #endif printf("\n"); if (decode) decode_lun(" ", reportLunsBuff + off, (lu_cong % 2), do_hex, verbose); } } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Report Luns command not supported (support mandatory in " "SPC-3)\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("Report Luns, aborted command\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Report Luns command has bad field in cdb\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Report Luns command: %s\n", b); } the_end: if (reportLunsBuff) free(reportLunsBuff); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_decode_sense.c0000664000175000017500000003626412266311060016424 0ustar douggdougg/* * Copyright (c) 2010-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" static const char * version_str = "1.06 20140117"; #define MAX_SENSE_LEN 1024 /* max descriptor format actually: 256+8 */ static struct option long_options[] = { {"binary", required_argument, 0, 'b'}, {"file", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"nospace", no_argument, 0, 'n'}, {"status", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"write", required_argument, 0, 'w'}, {0, 0, 0, 0}, }; struct opts_t { int do_binary; const char * fname; int do_file; int do_help; int do_hex; int no_space; int do_status; int sstatus; int do_verbose; int do_version; const char * wfname; unsigned char sense[MAX_SENSE_LEN + 4]; const char * no_space_str; int sense_len; }; static char concat_buff[1024]; static void usage() { fprintf(stderr, "Usage: " "sg_decode_sense [--binary=FN] [--file=FN] [--help] [--hex] " "[--nospace]\n" " [--status=SS] [--verbose] [--version] " "[--write=WFN]\n" " [H1 H2 H3 ...]\n" " where:\n" " --binary=FN|-b FN FN is a file name to read sense " "data in\n" " binary from. If FN is '-' then read " "from stdin\n" " --file=FN|-f FN FN is a file name from which to read " "sense data\n" " in ASCII hexadecimal. Interpret '-' " "as stdin\n" " --help|-h print out usage message\n" " --hex|-H used together with --write=WFN, to " "write out\n" " C language style ASCII hex (instead " "of binary)\n" " --nospace|-n no spaces or other separators between " "pairs of\n" " hex digits (e.g. '3132330A')\n" " --status=SS |-s SS SCSI status value in hex\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --write=WFN |-w WFN write sense data in binary to WFN, " "create if\n" " required else truncate prior to " "writing\n\n" "Decodes SCSI sense data given on the command line as a sequence " "of\nhexadecimal bytes (H1 H2 H3 ...) . Alternatively the sense " "data can\nbe in a binary file or in a file containing ASCII " "hexadecimal.\n" ); } static int process_cl(struct opts_t *optsp, int argc, char *argv[]) { int c; unsigned int ui; char * opt; char *endptr; long val; while (1) { c = getopt_long(argc, argv, "b:f:hHns:vVw:", long_options, NULL); if (c == -1) break; switch (c) { case 'b': if (optsp->fname) { fprintf(stderr, "expect only one '--binary=FN' or " "'--file=FN' option\n"); return SG_LIB_SYNTAX_ERROR; } ++optsp->do_binary; optsp->fname = optarg; break; case 'f': if (optsp->fname) { fprintf(stderr, "expect only one '--binary=FN' or " "'--file=FN' option\n"); return SG_LIB_SYNTAX_ERROR; } ++optsp->do_file; optsp->fname = optarg; break; case 'h': case '?': optsp->do_help = 1; return 0; case 'H': ++optsp->do_hex; break; case 'n': ++optsp->no_space; break; case 's': if (1 != sscanf(optarg, "%x", &ui)) { fprintf(stderr, "'--status=SS' expects a byte value\n"); return SG_LIB_SYNTAX_ERROR; } if (ui > 0xff) { fprintf(stderr, "'--status=SS' byte value exceeds FF\n"); return SG_LIB_SYNTAX_ERROR; } ++optsp->do_status; optsp->sstatus = ui; break; case 'v': ++optsp->do_verbose; break; case 'V': optsp->do_version = 1; return 0; case 'w': optsp->wfname = optarg; break; default: return SG_LIB_SYNTAX_ERROR; } } while (optind < argc) { opt = argv[optind++]; if (optsp->no_space) { if (optsp->no_space_str) { if ('\0' == concat_buff[0]) { if (strlen(optsp->no_space_str) > sizeof(concat_buff)) { fprintf(stderr, "'--nospace' concat_buff overflow\n"); return SG_LIB_SYNTAX_ERROR; } strcpy(concat_buff, optsp->no_space_str); } if ((strlen(concat_buff) + strlen(opt)) >= sizeof(concat_buff)) { fprintf(stderr, "'--nospace' concat_buff overflow\n"); return SG_LIB_SYNTAX_ERROR; } if (optsp->do_version) fprintf(stderr, "'--nospace' and found whitespace so " "concatenate\n"); strcat(concat_buff, opt); optsp->no_space_str = concat_buff; } else optsp->no_space_str = opt; continue; } val = strtol(opt, &endptr, 16); if (*opt == '\0' || *endptr != '\0' || val < 0x00 || val > 0xff) { fprintf(stderr, "Invalid byte '%s'\n", opt); return SG_LIB_SYNTAX_ERROR; } if (optsp->sense_len > MAX_SENSE_LEN) { fprintf(stderr, "sense data too long (max. %d bytes)\n", MAX_SENSE_LEN); return SG_LIB_SYNTAX_ERROR; } optsp->sense[optsp->sense_len++] = (unsigned char)val; } return 0; } /* Read ASCII hex bytes from fname (a file named '-' taken as stdin). * There should be either one entry per line or a comma, space or tab * separated list of bytes. If no_space is set then a string of ACSII hex * digits is expected, 2 per byte. Everything from and including a '#' * on a line is ignored. Returns 0 if ok, or 1 if error. */ static int f2hex_arr(const char * fname, int no_space, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int fn_len, in_len, k, j, m, split_line; unsigned int h; const char * lcp; FILE * fp; char line[512]; char carry_over[4]; int off = 0; if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; fn_len = strlen(fname); if (0 == fn_len) return 1; if ((1 == fn_len) && ('-' == fname[0])) /* read from stdin */ fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { fprintf(stderr, "Unable to open %s for reading\n", fname); return 1; } } carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { fprintf(stderr, "f2hex_arr: carry_over error ['%s'] " "around line %d\n", carry_over, j + 1); goto bad; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { fprintf(stderr, "f2hex_arr: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto bad; } if (no_space) { for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1)); ++k, lcp += 2) { if (1 != sscanf(lcp, "%2x", &h)) { fprintf(stderr, "f2hex_arr: bad hex number in line %d, " "pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if ((off + k) >= max_arr_len) { fprintf(stderr, "f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; off += k; } else { for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "f2hex_arr: hex number larger than " "0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { fprintf(stderr, "f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } fprintf(stderr, "f2hex_arr: error in line %d, at pos " "%d\n", j + 1, (int)(lcp - line + 1)); goto bad; } } off += (k + 1); } } *mp_arr_len = off; if (stdin != fp) fclose(fp); return 0; bad: if (stdin != fp) fclose(fp); return 1; } static void write2wfn(FILE * fp, struct opts_t * optsp) { int k, n; size_t s; char b[128]; if (optsp->do_hex) { for (k = 0, n = 0; k < optsp->sense_len; ++k) { n += sprintf(b + n, "0x%02x,", optsp->sense[k]); if (15 == (k % 16)) { b[n] = '\n'; s = fwrite(b, 1, n + 1, fp); n = 0; } } if (n > 0) { b[n] = '\n'; s = fwrite(b, 1, n + 1, fp); } } else { s = fwrite(optsp->sense, 1, optsp->sense_len, fp); if ((int)s != optsp->sense_len) fprintf(stderr, "only able to write %d of %d bytes to %s\n", (int)s, optsp->sense_len, optsp->wfname); } } int main(int argc, char *argv[]) { int k; int ret = 0; unsigned int ui; size_t s; struct opts_t opts; char b[2048]; FILE * fp = NULL; const char * cp; memset(&opts, 0, sizeof(opts)); memset(b, 0, sizeof(b)); ret = process_cl(&opts, argc, argv); if (ret != 0) { usage(); return ret; } else if (opts.do_help) { usage(); return 0; } else if (opts.do_version) { fprintf(stderr, "version: %s\n", version_str); return 0; } if (opts.do_status) { sg_get_scsi_status_str(opts.sstatus, sizeof(b) - 1, b); printf("SCSI status: %s\n", b); } if ((0 == opts.sense_len) && opts.no_space_str) { if (opts.do_verbose > 2) fprintf(stderr, "no_space str: %s\n", opts.no_space_str); cp = opts.no_space_str; for (k = 0; isxdigit(cp[k]) && isxdigit(cp[k + 1]); k += 2) { if (1 != sscanf(cp + k, "%2x", &ui)) { fprintf(stderr, "bad no_space hex string: %s\n", cp); return SG_LIB_SYNTAX_ERROR; } opts.sense[opts.sense_len++] = (unsigned char)ui; } } if ((0 == opts.sense_len) && (! opts.do_binary) && (! opts.do_file)) { if (opts.do_status) return 0; fprintf(stderr, ">> Need sense data on the command line or in a " "file\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (opts.sense_len && (opts.do_binary || opts.do_file)) { fprintf(stderr, ">> Need sense data on command line or in a file, " "not both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (opts.do_binary && opts.do_file) { fprintf(stderr, ">> Either a binary file or a ASCII hexadecimal, " "file not both\n\n"); return SG_LIB_SYNTAX_ERROR; } if (opts.do_binary) { fp = fopen(opts.fname, "r"); if (NULL == fp) { fprintf(stderr, "unable to open file: %s\n", opts.fname); return SG_LIB_SYNTAX_ERROR; } s = fread(opts.sense, 1, MAX_SENSE_LEN, fp); fclose(fp); if (0 == s) { fprintf(stderr, "read nothing from file: %s\n", opts.fname); return SG_LIB_SYNTAX_ERROR; } opts.sense_len = s; } else if (opts.do_file) { ret = f2hex_arr(opts.fname, opts.no_space, opts.sense, &opts.sense_len, MAX_SENSE_LEN); if (ret) { fprintf(stderr, "unable to decode ASCII hex from file: %s\n", opts.fname); return SG_LIB_SYNTAX_ERROR; } } if (opts.sense_len) { if (opts.wfname) { if ((fp = fopen(opts.wfname, "w"))) { write2wfn(fp, &opts); fclose(fp); } else { perror("open"); fprintf(stderr, "trying to write to %s\n", opts.wfname); } } sg_get_sense_str(NULL, opts.sense, opts.sense_len, opts.do_verbose, sizeof(b) - 1, b); printf("%s\n", b); } return 0; } sg3_utils-1.40/src/sg_write_buffer.c0000664000175000017500000004467312430315266016477 0ustar douggdougg/* * Copyright (c) 2006-2014 Luben Tuikov and Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ /* * This utility issues the SCSI WRITE BUFFER command to the given device. */ static const char * version_str = "1.18 20141107"; /* spc4r37 */ #define ME "sg_write_buffer: " #define DEF_XFER_LEN (8 * 1024 * 1024) #define EBUFF_SZ 256 #define WRITE_BUFFER_CMD 0x3b #define WRITE_BUFFER_CMDLEN 10 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 120 /* 120 seconds, 2 minutes */ static struct option long_options[] = { {"bpw", required_argument, 0, 'b'}, {"help", no_argument, 0, 'h'}, {"id", required_argument, 0, 'i'}, {"in", required_argument, 0, 'I'}, {"length", required_argument, 0, 'l'}, {"mode", required_argument, 0, 'm'}, {"offset", required_argument, 0, 'o'}, {"raw", no_argument, 0, 'r'}, {"skip", required_argument, 0, 's'}, {"specific", required_argument, 0, 'S'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_write_buffer [--bpw=CS] [--help] [--id=ID] [--in=FILE]\n" " [--length=LEN] [--mode=MO] " "[--offset=OFF] [--raw]\n" " [--skip=SKIP] [--specific=MS] " "[--verbose] [--version]\n" " DEVICE\n" " where:\n" " --bpw=CS|-b CS CS is chunk size: bytes per write " "buffer\n" " command (def: 0 -> as many as " "possible)\n" " --help|-h print out usage message then exit\n" " --id=ID|-i ID buffer identifier (0 (default) to " "255)\n" " --in=FILE|-I FILE read from FILE ('-I -' read " "from stdin)\n" " --length=LEN|-l LEN length in bytes to write; may be " "deduced from\n" " FILE\n" " --mode=MO|-m MO write buffer mode, MO is number or " "acronym\n" " (def: 0 -> 'combined header and " "data' (obs))\n" " --offset=OFF|-o OFF buffer offset (unit: bytes, def: 0)\n" " --raw|-r read from stdin (same as '-I -')\n" " --skip=SKIP|-s SKIP bytes in file FILE to skip before " "reading\n" " --specific=MS|-S MS mode specific value; 3 bit field " "(0 to 7)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs one or more SCSI WRITE BUFFER commands. Use '-m xxx' " "to list\navailable modes. A chunk size of 4 KB ('--bpw=4k') " "seems to work well.\nExample: sg_write_buffer -b 4k -I xxx.lod " "-m 7 /dev/sg3\n" ); } #define MODE_HEADER_DATA 0 #define MODE_VENDOR 1 #define MODE_DATA 2 #define MODE_DNLD_MC 4 #define MODE_DNLD_MC_SAVE 5 #define MODE_DNLD_MC_OFFS 6 #define MODE_DNLD_MC_OFFS_SAVE 7 #define MODE_ECHO_BUFFER 0x0A #define MODE_DNLD_MC_EV_OFFS_DEFER 0x0D #define MODE_DNLD_MC_OFFS_DEFER 0x0E #define MODE_ACTIVATE_MC 0x0F #define MODE_EN_EX_ECHO 0x1A #define MODE_DIS_EX 0x1B #define MODE_DNLD_ERR_HISTORY 0x1C struct mode_s { const char *mode_string; int mode; const char *comment; }; static struct mode_s mode_arr[] = { {"hd", MODE_HEADER_DATA, "combined header and data " "(obsolete)"}, {"vendor", MODE_VENDOR, "vendor specific"}, {"data", MODE_DATA, "data"}, {"dmc", MODE_DNLD_MC, "download microcode and activate"}, {"dmc_save", MODE_DNLD_MC_SAVE, "download microcode, save and " "activate"}, {"dmc_offs", MODE_DNLD_MC_OFFS, "download microcode with offsets " "and activate"}, {"dmc_offs_save", MODE_DNLD_MC_OFFS_SAVE, "download microcode with " "offsets, save and\n\t\t\t\tactivate"}, {"echo", MODE_ECHO_BUFFER, "write data to echo buffer"}, {"dmc_offs_ev_defer", MODE_DNLD_MC_EV_OFFS_DEFER, "download " "microcode with offsets, select\n\t\t\t\tactivation event, " "save and defer activation"}, {"dmc_offs_defer", MODE_DNLD_MC_OFFS_DEFER, "download microcode " "with offsets, save and\n\t\t\t\tdefer activation"}, {"activate_mc", MODE_ACTIVATE_MC, "activate deferred microcode"}, {"en_ex", MODE_EN_EX_ECHO, "enable expander communications " "protocol and\n\t\t\t\techo buffer (obsolete)"}, {"dis_ex", MODE_DIS_EX, "disable expander communications " "protocol\n\t\t\t\t(obsolete)"}, {"deh", MODE_DNLD_ERR_HISTORY, "download application client " "error history "}, {NULL, 0, NULL}, }; static void print_modes(void) { const struct mode_s * mp; pr2serr("The modes parameter argument can be numeric (hex or decimal)\n" "or symbolic:\n"); for (mp = mode_arr; mp->mode_string; ++mp) { pr2serr(" %2d (0x%02x) %-18s%s\n", mp->mode, mp->mode, mp->mode_string, mp->comment); } pr2serr("\nAdditionally '--bpw=,act' does a activate deferred " "microcode after\nsuccessful dmc_offs_defer and " "dmc_offs_ev_defer mode downloads.\n"); } /* <<<< This function will be moved to the library in the future >>> */ /* Invokes a SCSI WRITE BUFFER command (SPC). Return of 0 -> * success, SG_LIB_CAT_INVALID_OP -> invalid opcode, * SG_LIB_CAT_ILLEGAL_REQ -> bad field in cdb, SG_LIB_CAT_UNIT_ATTENTION, * SG_LIB_CAT_NOT_READY -> device not ready, SG_LIB_CAT_ABORTED_COMMAND, * -1 -> other failure */ static int sg_ll_write_buffer_v2(int sg_fd, int mode, int m_specific, int buffer_id, int buffer_offset, void * paramp, int param_len, int noisy, int verbose) { int k, res, ret, sense_cat; unsigned char wbufCmdBlk[WRITE_BUFFER_CMDLEN] = {WRITE_BUFFER_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; wbufCmdBlk[1] = (unsigned char)(mode & 0x1f); wbufCmdBlk[1] |= (unsigned char)((m_specific & 0x7) << 5); wbufCmdBlk[2] = (unsigned char)(buffer_id & 0xff); wbufCmdBlk[3] = (unsigned char)((buffer_offset >> 16) & 0xff); wbufCmdBlk[4] = (unsigned char)((buffer_offset >> 8) & 0xff); wbufCmdBlk[5] = (unsigned char)(buffer_offset & 0xff); wbufCmdBlk[6] = (unsigned char)((param_len >> 16) & 0xff); wbufCmdBlk[7] = (unsigned char)((param_len >> 8) & 0xff); wbufCmdBlk[8] = (unsigned char)(param_len & 0xff); if (verbose) { pr2serr(" Write buffer cmd: "); for (k = 0; k < WRITE_BUFFER_CMDLEN; ++k) pr2serr("%02x ", wbufCmdBlk[k]); pr2serr("\n"); if ((verbose > 1) && paramp && param_len) { pr2serr(" Write buffer parameter list%s:\n", ((param_len > 256) ? " (first 256 bytes)" : "")); dStrHexErr((const char *)paramp, ((param_len > 256) ? 256 : param_len), -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("write buffer: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, wbufCmdBlk, sizeof(wbufCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)paramp, param_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "write buffer", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { int sg_fd, infd, res, c, len, k, n, got_stdin; int bpw = 0; int bpw_then_activate = 0; int do_help = 0; int wb_id = 0; int wb_len = 0; int wb_len_given = 0; int wb_mode = 0; int wb_offset = 0; int wb_skip = 0; int wb_mspec = 0; int verbose = 0; const char * device_name = NULL; const char * file_name = NULL; unsigned char * dop = NULL; char * cp; const struct mode_s * mp; char ebuff[EBUFF_SZ]; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:hi:I:l:m:o:rs:S:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': bpw = sg_get_num(optarg); if (bpw < 0) { pr2serr("argument to '--bpw' should be in a positive " "number\n"); return SG_LIB_SYNTAX_ERROR; } if ((cp = strchr(optarg, ','))) { if (0 == strncmp("act", cp + 1, 3)) ++bpw_then_activate; } break; case 'h': case '?': ++do_help; break; case 'i': wb_id = sg_get_num(optarg); if ((wb_id < 0) || (wb_id > 255)) { pr2serr("argument to '--id' should be in the range 0 to " "255\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': file_name = optarg; break; case 'l': wb_len = sg_get_num(optarg); if (wb_len < 0) { pr2serr("bad argument to '--length'\n"); return SG_LIB_SYNTAX_ERROR; } wb_len_given = 1; break; case 'm': if (isdigit(*optarg)) { wb_mode = sg_get_num(optarg); if ((wb_mode < 0) || (wb_mode > 31)) { pr2serr("argument to '--mode' should be in the range 0 " "to 31\n"); return SG_LIB_SYNTAX_ERROR; } } else { len = strlen(optarg); for (mp = mode_arr; mp->mode_string; ++mp) { if (0 == strncmp(mp->mode_string, optarg, len)) { wb_mode = mp->mode; break; } } if (! mp->mode_string) { print_modes(); return SG_LIB_SYNTAX_ERROR; } } break; case 'o': wb_offset = sg_get_num(optarg); if (wb_offset < 0) { pr2serr("bad argument to '--offset'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': file_name = "-"; break; case 's': wb_skip = sg_get_num(optarg); if (wb_skip < 0) { pr2serr("bad argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': wb_mspec = sg_get_num(optarg); if ((wb_mspec < 0) || (wb_mspec > 7)) { pr2serr("expected argument to '--specific' to be 0 to 7\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': pr2serr(ME "version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (do_help) { if (do_help > 1) { usage(); pr2serr("\n"); print_modes(); } else usage(); return 0; } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((wb_len > 0) && (bpw > wb_len)) { pr2serr("trim chunk size (CS) to be the same as LEN\n"); bpw = wb_len; } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (verbose > 4) pr2serr("Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (file_name || (wb_len > 0)) { if (0 == wb_len) wb_len = DEF_XFER_LEN; if (NULL == (dop = (unsigned char *)malloc(wb_len))) { pr2serr(ME "out of memory\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } memset(dop, 0xff, wb_len); if (file_name) { got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0; if (got_stdin) { if (wb_skip > 0) { pr2serr("Can't skip on stdin\n"); ret = SG_LIB_FILE_ERROR; goto err_out; } infd = STDIN_FILENO; } else { if ((infd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); if (wb_skip > 0) { if (lseek(infd, wb_skip, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to " "required position on %s", file_name); perror(ebuff); close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } } } res = read(infd, dop, wb_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); if (! got_stdin) close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } if (res < wb_len) { if (wb_len_given) { pr2serr("tried to read %d bytes from %s, got %d bytes\n", wb_len, file_name, res); pr2serr("pad with 0xff bytes and continue\n"); } else { if (verbose) { pr2serr("tried to read %d bytes from %s, got %d " "bytes\n", wb_len, file_name, res); pr2serr("will write %d bytes", res); if ((bpw > 0) && (bpw < wb_len)) pr2serr(", %d bytes per WRITE BUFFER command\n", bpw); else pr2serr("\n"); } wb_len = res; } } if (! got_stdin) close(infd); } } res = 0; if (bpw > 0) { for (k = 0; k < wb_len; k += n) { n = wb_len - k; if (n > bpw) n = bpw; if (verbose) pr2serr("sending write buffer, mode=0x%x, mspec=%d, id=%d, " " offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id, wb_offset + k, n); res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset + k, dop + k, n, 1, verbose); if (res) break; } if (bpw_then_activate) { if (verbose) pr2serr("sending Activate deferred microcode [0xf]\n"); res = sg_ll_write_buffer_v2(sg_fd, MODE_ACTIVATE_MC, 0, 0, 0, NULL, 0, 1, verbose); } } else { if (verbose) pr2serr("sending single write buffer, mode=0x%x, mpsec=%d, " "id=%d, offset=%d, len=%d\n", wb_mode, wb_mspec, wb_id, wb_offset, wb_len); res = sg_ll_write_buffer_v2(sg_fd, wb_mode, wb_mspec, wb_id, wb_offset, dop, wb_len, 1, verbose); } if (0 != res) { char b[80]; ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Write buffer failed: %s\n", b); } err_out: if (dop) free(dop); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_start.c0000664000175000017500000004354412335513125015143 0ustar douggdougg/* * Copyright (C) 1999-2013 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. Start/Stop parameter by Kurt Garloff , 6/2000 Sync cache parameter by Kurt Garloff , 1/2001 Guard block device answering sg's ioctls. 12/2002 Convert to SG_IO ioctl so can use sg or block devices in 2.6.* 3/2003 This utility was written for the Linux 2.4 kernel series. It now builds for the Linux 2.6 and 3 kernel series and various other Operating Systems. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "0.59 20130507"; /* sbc3r14; mmc6r01a */ static struct option long_options[] = { {"eject", 0, 0, 'e'}, {"fl", 1, 0, 'f'}, {"help", 0, 0, 'h'}, {"immed", 0, 0, 'i'}, {"load", 0, 0, 'l'}, {"loej", 0, 0, 'L'}, {"mod", 1, 0, 'm'}, {"noflush", 0, 0, 'n'}, {"new", 0, 0, 'N'}, {"old", 0, 0, 'O'}, {"pc", 1, 0, 'p'}, {"readonly", 0, 0, 'r'}, {"start", 0, 0, 's'}, {"stop", 0, 0, 'S'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_eject; int do_fl; int do_help; int do_immed; int do_load; int do_loej; int do_mod; int do_noflush; int do_readonly; int do_pc; int do_start; int do_stop; int do_verbose; int do_version; const char * device_name; int opt_new; }; static void usage() { fprintf(stderr, "Usage: sg_start [--eject] [--fl=FL] [--help] " "[--immed] [--load] [--loej]\n" " [--mod=PC_MOD] [--noflush] [--pc=PC] " "[--readonly]\n" " [--start] [--stop] [--verbose] " "[--version] DEVICE\n" " where:\n" " --eject|-e stop unit then eject the medium\n" " --fl=FL|-f FL format layer number (mmc5)\n" " --help|-h print usage message then exit\n" " --immed|-i device should return control after " "receiving cdb,\n" " default action is to wait until action " "is complete\n" " --load|-l load medium then start the unit\n" " --loej|-L load or eject, corresponds to LOEJ bit " "in cdb;\n" " load when START bit also set, else " "eject\n" " --mod=PC_MOD|-m PC_MOD power condition modifier " "(def: 0) (sbc)\n" " --noflush|-n no flush prior to operation that limits " "access (sbc)\n" " --pc=PC|-p PC power condition: 0 (default) -> no " "power condition,\n" " 1 -> active, 2 -> idle, 3 -> standby, " "5 -> sleep (mmc)\n" " --readonly|-r open DEVICE read-only (def: read-write)\n" " recommended if DEVICE is ATA disk\n" " --start|-s start unit, corresponds to START bit " "in cdb,\n" " default (START=1) if no other options " "given\n" " --stop|-S stop unit (e.g. spin down disk)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n\n" " Example: 'sg_start --stop /dev/sdb' stops unit\n" " 'sg_start --eject /dev/scd0' stops unit and " "ejects medium\n\n" "Performs a SCSI START STOP UNIT command\n" ); } static void usage_old() { fprintf(stderr, "Usage: sg_start [0] [1] [--eject] [--fl=FL] " "[-i] [--imm=0|1]\n" " [--load] [--loej] [--mod=PC_MOD] " "[--noflush] [--pc=PC]\n" " [--readonly] [--start] [--stop] [-v] [-V]\n" " DEVICE\n" " where:\n" " 0 stop unit (e.g. spin down a disk or a " "cd/dvd)\n" " 1 start unit (e.g. spin up a disk or a " "cd/dvd)\n" " --eject stop then eject the medium\n" " --fl=FL format layer number (mmc5)\n" " -i return immediately (same as '--imm=1')\n" " --imm=0|1 0->await completion(def), 1->return " "immediately\n" " --load load then start the medium\n" " --loej load the medium if '-start' option is " "also given\n" " or stop unit and eject\n" " --mod=PC_MOD power condition modifier " "(def: 0) (sbc)\n" " --noflush no flush prior to operation that limits " "access (sbc)\n" " --pc=PC power condition (in hex, default 0 -> no " "power condition)\n" " 1 -> active, 2 -> idle, 3 -> standby, " "5 -> sleep (mmc)\n" " --readonly|-r open DEVICE read-only (def: read-write)\n" " recommended if DEVICE is ATA disk\n" " --start start unit (same as '1'), default " "action\n" " --stop stop unit (same as '0')\n" " -v verbose (print out SCSI commands)\n" " -V print version string then exit\n\n" " Example: 'sg_start --stop /dev/sdb' stops unit\n" " 'sg_start --eject /dev/scd0' stops unit and " "ejects medium\n\n" "Performs a SCSI START STOP UNIT command\n" ); } static int process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c, n, err; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ef:hilLm:nNOp:rsSvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'e': ++op->do_eject; ++op->do_loej; break; case 'f': n = sg_get_num(optarg); if ((n < 0) || (n > 3)) { fprintf(stderr, "bad argument to '--fl='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } ++op->do_loej; ++op->do_start; op->do_fl = n; break; case 'h': case '?': ++op->do_help; break; case 'i': ++op->do_immed; break; case 'l': ++op->do_load; ++op->do_loej; break; case 'L': ++op->do_loej; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 15)) { fprintf(stderr, "bad argument to '--mod='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_mod = n; break; case 'n': ++op->do_noflush; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': n = sg_get_num(optarg); if ((n < 0) || (n > 15)) { fprintf(stderr, "bad argument to '--pc='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_pc = n; break; case 'r': ++op->do_readonly; break; case 's': ++op->do_start; break; case 'S': ++op->do_stop; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } err = 0; for (; optind < argc; ++optind) { if (1 == strlen(argv[optind])) { if (0 == strcmp("0", argv[optind])) { ++op->do_stop; continue; } else if (0 == strcmp("1", argv[optind])) { ++op->do_start; continue; } } if (NULL == op->device_name) op->device_name = argv[optind]; else { fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); ++err; } } if (err) { usage(); return SG_LIB_SYNTAX_ERROR; } else return 0; } static int process_cl_old(struct opts_t * op, int argc, char * argv[]) { int k, jmp_out, plen, num; int ambigu = 0; int startstop = -1; unsigned int u; 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 'i': if ('\0' == *(cp + 1)) op->do_immed = 1; else jmp_out = 1; break; case 'r': ++op->do_readonly; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case 'h': case '?': ++op->do_help; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case '-': ++cp; --plen; jmp_out = 1; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp(cp, "eject", 5)) { op->do_loej = 1; if (startstop == 1) ambigu = 1; else startstop = 0; } else if (0 == strncmp("fl=", cp, 3)) { num = sscanf(cp + 3, "%x", &u); if (1 != num) { fprintf(stderr, "Bad value after 'fl=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } startstop = 1; op->do_loej = 1; op->do_fl = u; } else if (0 == strncmp("imm=", cp, 4)) { num = sscanf(cp + 4, "%x", &u); if ((1 != num) || (u > 1)) { fprintf(stderr, "Bad value after 'imm=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->do_immed = u; } else if (0 == strncmp(cp, "load", 4)) { op->do_loej = 1; if (startstop == 0) ambigu = 1; else startstop = 1; } else if (0 == strncmp(cp, "loej", 4)) op->do_loej = 1; else if (0 == strncmp("pc=", cp, 3)) { num = sscanf(cp + 3, "%x", &u); if ((1 != num) || (u > 15)) { fprintf(stderr, "Bad value after after 'pc=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->do_pc = u; } else if (0 == strncmp("mod=", cp, 4)) { num = sscanf(cp + 3, "%x", &u); if (1 != num) { fprintf(stderr, "Bad value after 'mod=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->do_mod = u; } else if (0 == strncmp(cp, "noflush", 7)) { op->do_noflush = 1; } else if (0 == strncmp(cp, "start", 5)) { if (startstop == 0) ambigu = 1; else startstop = 1; } else if (0 == strncmp(cp, "stop", 4)) { if (startstop == 1) ambigu = 1; else startstop = 0; } else if (0 == strncmp(cp, "old", 3)) ; else if (jmp_out) { fprintf(stderr, "Unrecognized option: %s\n", cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp("0", cp)) { if (1 == startstop) ambigu = 1; else startstop = 0; } else if (0 == strcmp("1", cp)) { if (0 == startstop) ambigu = 1; else startstop = 1; } else if (0 == op->device_name) op->device_name = cp; else { fprintf(stderr, "too many arguments, got: %s, not " "expecting: %s\n", op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } if (ambigu) { fprintf(stderr, "please, only one of 0, 1, --eject, " "--load, --start or --stop\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } else if (0 == startstop) ++op->do_stop; else if (1 == startstop) ++op->do_start; } return 0; } static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } int main(int argc, char * argv[]) { int fd, res; int ret = 0; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->do_fl = -1; /* only when >= 0 set FL bit */ res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (op->do_start && op->do_stop) { fprintf(stderr, "Ambiguous to give both '--start' and '--stop'\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_load && op->do_eject) { fprintf(stderr, "Ambiguous to give both '--load' and '--eject'\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_load) op->do_start = 1; else if ((op->do_eject) || (op->do_stop)) op->do_start = 0; else if (op->opt_new && op->do_loej && (0 == op->do_start)) op->do_start = 1; /* --loej alone in new interface is load */ else if ((0 == op->do_loej) && (-1 == op->do_fl) && (0 == op->do_pc)) op->do_start = 1; /* default action is to start when no other active options */ if (0 == op->device_name) { fprintf(stderr, "No DEVICE argument given\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (op->do_fl >= 0) { if (op->do_start == 0) { fprintf(stderr, "Giving '--fl=FL' with '--stop' (or " "'--eject') is invalid\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_pc > 0) { fprintf(stderr, "Giving '--fl=FL' with '--pc=PC' " "when PC is non-zero is invalid\n"); return SG_LIB_SYNTAX_ERROR; } } fd = sg_cmds_open_device(op->device_name, op->do_readonly, op->do_verbose); if (fd < 0) { fprintf(stderr, "Error trying to open %s: %s\n", op->device_name, safe_strerror(-fd)); return SG_LIB_FILE_ERROR; } res = 0; if (op->do_fl >= 0) res = sg_ll_start_stop_unit(fd, op->do_immed, op->do_fl, 0 /* pc */, 1 /* fl */, 1 /* loej */, 1 /*start */, 1 /* noisy */, op->do_verbose); else if (op->do_pc > 0) res = sg_ll_start_stop_unit(fd, op->do_immed, op->do_mod, op->do_pc, op->do_noflush, 0, 0, 1, op->do_verbose); else res = sg_ll_start_stop_unit(fd, op->do_immed, 0, 0, op->do_noflush, op->do_loej, op->do_start, 1, op->do_verbose); ret = res; if (res) { if (op->do_verbose < 2) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); fprintf(stderr, "%s\n", b); } fprintf(stderr, "START STOP UNIT command failed\n"); } res = sg_cmds_close_device(fd); if ((res < 0) && (0 == ret)) return SG_LIB_FILE_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_scan.c.linux0000664000175000017500000004360412142450532016063 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999 - 2013 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. * * This program scans the "sg" device space (ie actual + simulated SCSI * generic devices). Optionally sg_scan can be given other device names * to scan (in place of the sg devices). * Options: -a alpha scan: scan /dev/sga,b,c, .... * -i do SCSI inquiry on device (implies -w) * -n numeric scan: scan /dev/sg0,1,2, .... * -V output version string and exit * -w open writable (new driver opens readable unless -i) * -x extra information output * * By default this program will look for /dev/sg0 first (i.e. numeric scan) * * Note: This program is written to work under both the original and * the new sg driver. * * F. Jansen - modification to extend beyond 26 sg devices. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_io_linux.h" static const char * version_str = "4.10 20130507"; #define ME "sg_scan: " #define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ #define INQ_REPLY_LEN 36 #define INQ_CMD_LEN 6 #define MAX_ERRORS 4 #define EBUFF_SZ 256 #define FNAME_SZ 64 #define PRESENT_ARRAY_SIZE 8192 static const char * sysfs_sg_dir = "/sys/class/scsi_generic"; static int * gen_index_arr; typedef struct my_scsi_idlun { /* why can't userland see this structure ??? */ int dev_id; int host_unique_id; } My_scsi_idlun; typedef struct my_sg_scsi_id { int host_no; /* as in "scsi" where 'n' is one of 0, 1, 2 etc */ int channel; int scsi_id; /* scsi id of target device */ int lun; int scsi_type; /* TYPE_... defined in scsi/scsi.h */ short h_cmd_per_lun;/* host (adapter) maximum commands per lun */ short d_queue_depth;/* device (or adapter) maximum queue length */ int unused1; /* probably find a good use, set 0 for now */ int unused2; /* ditto */ } My_sg_scsi_id; int sg3_inq(int sg_fd, unsigned char * inqBuff, int do_extra); int scsi_inq(int sg_fd, unsigned char * inqBuff); int try_ata_identity(const char * file_namep, int ata_fd, int do_inq); static unsigned char inqCmdBlk[INQ_CMD_LEN] = {0x12, 0, 0, 0, INQ_REPLY_LEN, 0}; void usage() { printf("Usage: sg_scan [-a] [-i] [-n] [-v] [-V] [-w] [-x] " "[DEVICE]*\n"); printf(" where:\n"); printf(" -a do alpha scan (ie sga, sgb, sgc)\n"); printf(" -i do SCSI INQUIRY, output results\n"); printf(" -n do numeric scan (ie sg0, sg1...) [default]\n"); printf(" -v increase verbosity\n"); printf(" -V output version string then exit\n"); printf(" -w force open with read/write flag\n"); printf(" -x extra information output about queuing\n"); printf(" DEVICE name of device\n"); } static int scandir_select(const struct dirent * s) { int k; if (1 == sscanf(s->d_name, "sg%d", &k)) { if ((k >= 0) && (k < PRESENT_ARRAY_SIZE)) { gen_index_arr[k] = 1; return 1; } } return 0; } static int sysfs_sg_scan(const char * dir_name) { struct dirent ** namelist; int num, k; num = scandir(dir_name, &namelist, scandir_select, NULL); if (num < 0) return -errno; for (k = 0; k < num; ++k) free(namelist[k]); free(namelist); return num; } void make_dev_name(char * fname, int k, int do_numeric) { char buff[FNAME_SZ]; int big,little; strcpy(fname, "/dev/sg"); if (do_numeric) { snprintf(buff, sizeof(buff), "%d", k); strcat(fname, buff); } else { if (k < 26) { buff[0] = 'a' + (char)k; buff[1] = '\0'; strcat(fname, buff); } else if (k <= 255) { /* assumes sequence goes x,y,z,aa,ab,ac etc */ big = k/26; little = k - (26 * big); big = big - 1; buff[0] = 'a' + (char)big; buff[1] = 'a' + (char)little; buff[2] = '\0'; strcat(fname, buff); } else strcat(fname, "xxxx"); } } int main(int argc, char * argv[]) { int sg_fd, res, k, j, f, plen, jmp_out; unsigned char inqBuff[INQ_REPLY_LEN]; int do_numeric = NUMERIC_SCAN_DEF; int do_inquiry = 0; int do_extra = 0; int verbose = 0; int writeable = 0; int num_errors = 0; int num_silent = 0; int sg_ver3 = -1; int eacces_err = 0; char fname[FNAME_SZ]; char * file_namep; char ebuff[EBUFF_SZ]; My_scsi_idlun my_idlun; int host_no; int flags; int emul = -1; int has_file_args = 0; int has_sysfs_sg = 0; const int max_file_args = PRESENT_ARRAY_SIZE; const char * cp; struct stat a_stat; if (NULL == (gen_index_arr = (int *)calloc(max_file_args + 1, sizeof(int)))) { printf(ME "Out of memory\n"); return SG_LIB_CAT_OTHER; } for (k = 1, j = 0; 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 'a': do_numeric = 0; break; case 'h': case '?': printf("Scan sg device names and optionally do an " "INQUIRY\n\n"); usage(); return 0; case 'i': do_inquiry = 1; break; case 'n': do_numeric = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "Version string: %s\n", version_str); exit(0); case 'w': writeable = 1; break; case 'x': do_extra = 1; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (jmp_out) { fprintf(stderr, "Unrecognized option: %s\n", cp); usage(); return SG_LIB_SYNTAX_ERROR; } } else { if (j < max_file_args) { has_file_args = 1; gen_index_arr[j++] = k; } else { printf("Too many command line arguments\n"); return SG_LIB_SYNTAX_ERROR; } } } if ((! has_file_args) && (stat(sysfs_sg_dir, &a_stat) >= 0) && (S_ISDIR(a_stat.st_mode))) has_sysfs_sg = sysfs_sg_scan(sysfs_sg_dir); flags = O_NONBLOCK | (writeable ? O_RDWR : O_RDONLY); for (k = 0, res = 0, j = 0, sg_fd = -1; (k < max_file_args) && (has_file_args || (num_errors < MAX_ERRORS)); ++k, res = ((sg_fd >= 0) ? close(sg_fd) : 0)) { if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "Error closing %s ", fname); perror(ebuff); return SG_LIB_FILE_ERROR; } if (has_file_args) { if (gen_index_arr[j]) file_namep = argv[gen_index_arr[j++]]; else break; } else if (has_sysfs_sg) { if (0 == gen_index_arr[k]) { sg_fd = -1; continue; } make_dev_name(fname, k, 1); file_namep = fname; } else { make_dev_name(fname, k, do_numeric); file_namep = fname; } sg_fd = open(file_namep, flags); if (sg_fd < 0) { if (EBUSY == errno) { printf("%s: device busy (O_EXCL lock), skipping\n", file_namep); continue; } else if ((ENODEV == errno) || (ENOENT == errno) || (ENXIO == errno)) { if (verbose) fprintf(stderr, "Unable to open: %s, errno=%d\n", file_namep, errno); ++num_errors; ++num_silent; continue; } else { if (EACCES == errno) eacces_err = 1; snprintf(ebuff, EBUFF_SZ, ME "Error opening %s ", file_namep); perror(ebuff); ++num_errors; continue; } } res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun); if (res < 0) { res = try_ata_identity(file_namep, sg_fd, do_inquiry); if (res == 0) continue; snprintf(ebuff, EBUFF_SZ, ME "device %s failed on scsi+ata " "ioctl, skip", file_namep); perror(ebuff); ++num_errors; continue; } res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "device %s failed on scsi " "ioctl(2), skip", file_namep); perror(ebuff); ++num_errors; continue; } res = ioctl(sg_fd, SG_EMULATED_HOST, &emul); if (res < 0) emul = -1; printf("%s: scsi%d channel=%d id=%d lun=%d", file_namep, host_no, (my_idlun.dev_id >> 16) & 0xff, my_idlun.dev_id & 0xff, (my_idlun.dev_id >> 8) & 0xff); if (1 == emul) printf(" [em]"); #if 0 printf(", huid=%d", my_idlun.host_unique_id); #endif if (! has_file_args) { My_sg_scsi_id m_id; /* compatible with sg_scsi_id_t in sg.h */ res = ioctl(sg_fd, SG_GET_SCSI_ID, &m_id); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "device %s failed " "SG_GET_SCSI_ID ioctl(4), skip", file_namep); perror(ebuff); ++num_errors; continue; } /* printf(" type=%d", m_id.scsi_type); */ if (do_extra) printf(" cmd_per_lun=%hd queue_depth=%hd\n", m_id.h_cmd_per_lun, m_id.d_queue_depth); else printf("\n"); } else printf("\n"); if (do_inquiry) { if (-1 == sg_ver3) { sg_ver3 = 0; if ((ioctl(sg_fd, SG_GET_VERSION_NUM, &f) >= 0) && (f >= 30000)) sg_ver3 = 1; } if (1 == sg_ver3) res = sg3_inq(sg_fd, inqBuff, do_extra); } } if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors) && (! has_file_args)) { printf("Stopping because there are too many error\n"); if (eacces_err) printf(" root access may be required\n"); } return 0; } int sg3_inq(int sg_fd, unsigned char * inqBuff, int do_extra) { struct sg_io_hdr io_hdr; unsigned char sense_buffer[32]; int ok, err, sg_io; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); memset(inqBuff, 0, INQ_REPLY_LEN); inqBuff[0] = 0x7f; io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(inqCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = INQ_REPLY_LEN; io_hdr.dxferp = inqBuff; io_hdr.cmdp = inqCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 20000; /* 20000 millisecs == 20 seconds */ ok = 1; sg_io = 0; if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { if ((err = scsi_inq(sg_fd, inqBuff)) < 0) { perror(ME "Inquiry SG_IO + SCSI_IOCTL_SEND_COMMAND ioctl error"); return 1; } else if (err) { printf(ME "SCSI_IOCTL_SEND_COMMAND ioctl error=0x%x\n", err); return 1; } } else { sg_io = 1; /* now for the error processing */ switch (sg_err_category3(&io_hdr)) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("Inquiry, continuing", &io_hdr, 1); /* fall through */ case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ ok = 0; sg_chk_n_print3("INQUIRY command error", &io_hdr, 1); break; } } if (ok) { /* output result if it is available */ char * p = (char *)inqBuff; printf(" %.8s %.16s %.4s ", p + 8, p + 16, p + 32); printf("[rmb=%d cmdq=%d pqual=%d pdev=0x%x] ", !!(p[1] & 0x80), !!(p[7] & 2), (p[0] & 0xe0) >> 5, (p[0] & 0x1f)); if (do_extra && sg_io) printf("dur=%ums\n", io_hdr.duration); else printf("\n"); } return 0; } struct lscsi_ioctl_command { unsigned int inlen; /* _excluding_ scsi command length */ unsigned int outlen; unsigned char data[1]; /* was 0 but that's not ISO C!! */ /* on input, scsi command starts here then opt. data */ }; /* fallback INQUIRY using scsi mid-level's SCSI_IOCTL_SEND_COMMAND ioctl */ int scsi_inq(int sg_fd, unsigned char * inqBuff) { int res; unsigned char buff[512]; struct lscsi_ioctl_command * sicp = (struct lscsi_ioctl_command *)buff; memset(buff, 0, sizeof(buff)); sicp->inlen = 0; sicp->outlen = INQ_REPLY_LEN; memcpy(sicp->data, inqCmdBlk, INQ_CMD_LEN); res = ioctl(sg_fd, SCSI_IOCTL_SEND_COMMAND, sicp); if (0 == res) memcpy(inqBuff, sicp->data, INQ_REPLY_LEN); return res; } /* Following code permits ATA IDENTIFY commands to be performed on ATA non "Packet Interface" devices (e.g. ATA disks). GPL-ed code borrowed from smartmontools (smartmontools.sf.net). Copyright (C) 2002-4 Bruce Allen */ #ifndef ATA_IDENTIFY_DEVICE #define ATA_IDENTIFY_DEVICE 0xec #endif #ifndef HDIO_DRIVE_CMD #define HDIO_DRIVE_CMD 0x031f #endif /* Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled * word* are NOT used. */ struct ata_identify_device { unsigned short words000_009[10]; unsigned char serial_no[20]; unsigned short words020_022[3]; unsigned char fw_rev[8]; unsigned char model[40]; unsigned short words047_079[33]; unsigned short major_rev_num; unsigned short minor_rev_num; unsigned short command_set_1; unsigned short command_set_2; unsigned short command_set_extension; unsigned short cfs_enable_1; unsigned short word086; unsigned short csf_default; unsigned short words088_255[168]; }; /* Copies n bytes (or n-1 if n is odd) from in to out, but swaps adjacents * bytes. */ void swapbytes(char *out, const char *in, size_t n) { size_t k; if (n > 1) { for (k = 0; k < (n - 1); k += 2) { out[k] = in[k + 1]; out[k + 1] = in[k]; } } } /* Copies in to out, but removes leading and trailing whitespace. */ void trim(char *out, const char *in) { int k, first, last; /* Find the first non-space character (maybe none). */ first = -1; for (k = 0; in[k]; k++) { if (! isspace((int)in[k])) { first = k; break; } } if (first == -1) { /* There are no non-space characters. */ out[0] = '\0'; return; } /* Find the last non-space character. */ for (k = strlen(in) - 1; k >= first && isspace((int)in[k]); k--) ; last = k; strncpy(out, in + first, last - first + 1); out[last - first + 1] = '\0'; } /* Convenience function for formatting strings from ata_identify_device */ void formatdriveidstring(char *out, const char *in, int n) { char tmp[65]; n = n > 64 ? 64 : n; swapbytes(tmp, in, n); tmp[n] = '\0'; trim(out, tmp); } /* Function for printing ASCII byte-swapped strings, skipping white * space. Please note that this is needed on both big- and * little-endian hardware. */ void printswap(char *output, char *in, unsigned int n) { formatdriveidstring(output, in, n); if (*output) printf("%.*s ", (int)n, output); else printf("%.*s ", (int)n, "[No Information Found]\n"); } #define ATA_IDENTIFY_BUFF_SZ sizeof(struct ata_identify_device) #define HDIO_DRIVE_CMD_OFFSET 4 int ata_command_interface(int device, char *data) { unsigned char buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET]; int retval; buff[0] = ATA_IDENTIFY_DEVICE; buff[3] = 1; /* We are now doing the HDIO_DRIVE_CMD type ioctl. */ if ((retval = ioctl(device, HDIO_DRIVE_CMD, buff))) return retval; /* if the command returns data, copy it back */ memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ); return 0; } int try_ata_identity(const char * file_namep, int ata_fd, int do_inq) { struct ata_identify_device ata_ident; char model[64]; char serial[64]; char firm[64]; int res; res = ata_command_interface(ata_fd, (char *)&ata_ident); if (res) return res; printf("%s: ATA device\n", file_namep); if (do_inq) { printf(" "); printswap(model, (char *)ata_ident.model, 40); printswap(serial, (char *)ata_ident.serial_no, 20); printswap(firm, (char *)ata_ident.fw_rev, 8); printf("\n"); } return res; } sg3_utils-1.40/src/sg_write_verify.c0000664000175000017500000005035712430315266016526 0ustar douggdougg/* * Copyright (c) 2014 Douglas Gilbert * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. * * This program issues the SCSI command WRITE AND VERIFY to a given SCSI * device. It sends the command with the logical block address passed as the * LBA argument, for the given number of blocks. The number of bytes sent is * supplied separately, either by the size of the given file (IF) or * explicitly with ILEN. * * This code was contributed by Bruno Goncalves */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_cmds_basic.h" static const char * version_str = "1.05 20141107"; #define ME "sg_write_verify: " #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define WRITE_VERIFY10_CMD 0x2e #define WRITE_VERIFY10_CMDLEN 10 #define WRITE_VERIFY16_CMD 0x8e #define WRITE_VERIFY16_CMDLEN 16 #define WRPROTECT_MASK (0x7) #define WRPROTECT_SHIFT (5) #define DEF_TIMEOUT_SECS 60 static struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"bytchk", required_argument, 0, 'b'}, {"dpo", no_argument, 0, 'd'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"ilen", required_argument, 0, 'I'}, {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"num", required_argument, 0, 'n'}, {"repeat", no_argument, 0, 'R'}, {"timeout", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wrprotect", required_argument, 0, 'w'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_write_verify [--16] [--bytchk=BC] [--dpo] [--group=GN] " "[--help]\n" " [--ilen=IL] [--in=IF] --lba=LBA " "[--num=NUM]\n" " [--repeat] [--timeout=TO] [--verbose] " "[--version]\n" " [--wrprotect=WPR] DEVICE\n" " where:\n" " --16|-S do WRITE AND VERIFY(16) (default: 10)\n" " --bytchk=BC|-b BC set BYTCHK field (default: 0)\n" " --dpo|-d set DPO bit (default: 0)\n" " --group=GN|-g GN GN is group number (default: 0)\n" " --help|-h print out usage message\n" " --ilen=IL| -I IL input (file) length in bytes, becomes " "data-out\n" " buffer length (def: deduced from IF " "size)\n" " --in=IF|-i IF IF is a file containing the data to " "be written\n" " --lba=LBA|-l LBA LBA of the first block to write " "and verify;\n" " no default, must be given\n" " --num=NUM|-n NUM number of logical blocks to write and " "verify\n" " --repeat|-R while IF still has data to read, send " "another\n" " command, bumping LBA with up to NUM " "blocks again\n" " --timeout=TO|-t TO command timeout in seconds (def: 60)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --wrprotect|-w WPR WPR is the WRPROTECT field value " "(def: 0)\n\n" "Performs a SCSI WRITE AND VERIFY (10 or 16) command on DEVICE, " "startings\nat LBA for NUM logical blocks. More commands " "performed only if '--repeat'\noption given. Data to be written " "is fetched from the IF file.\n" ); } /* Invokes a SCSI WRITE AND VERIFY according with CDB. Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int run_scsi_transaction(int sg_fd, const unsigned char *cdbp, int cdb_len, unsigned char *dop, int do_len, int timeout, int verbose) { int res, k, sense_cat, ret; unsigned char sense_b[SENSE_BUFF_LEN]; int noisy = 1; struct sg_pt_base * ptvp; char b[32]; snprintf(b, sizeof(b), "Write and verify(%d)", cdb_len); if (verbose) { fprintf(stderr, " %s cmd: ", b); for (k = 0; k < cdb_len; ++k) fprintf(stderr, "%02x ", cdbp[k]); fprintf(stderr, "\n"); if ((verbose > 2) && dop && do_len) { fprintf(stderr, " Data out buffer [%d bytes]:\n", do_len); dStrHexErr((const char *)dop, do_len, -1); } } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(stderr, "%s: out of memory\n", b); return -1; } set_scsi_pt_cdb(ptvp, cdbp, cdb_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, dop, do_len); res = do_scsi_pt(ptvp, sg_fd, timeout, verbose); ret = sg_cmds_process_resp(ptvp, b, res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: /* write or verify failed */ { int valid, slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) fprintf(stderr, "Medium or hardware error starting at " "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; case SG_LIB_CAT_PROTECTION: /* PI failure */ case SG_LIB_CAT_MISCOMPARE: /* only in bytchk=1 case */ default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } /* Invokes a SCSI WRITE AND VERIFY (10) command (SBC). Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_write_verify10(int sg_fd, int wrprotect, int dpo, int bytchk, unsigned int lba, int num_lb, int group, unsigned char *dop, int do_len, int timeout, int verbose) { int ret; unsigned char wv_cdb[WRITE_VERIFY10_CMDLEN]; memset(wv_cdb, 0, WRITE_VERIFY10_CMDLEN); wv_cdb[0] = WRITE_VERIFY10_CMD; wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT); if (dpo) wv_cdb[1] |= 0x10; if (bytchk) wv_cdb[1] |= ((bytchk & 0x3) << 1); wv_cdb[2] = (lba >> 24) & 0xff; wv_cdb[3] = (lba >> 16) & 0xff; wv_cdb[4] = (lba >> 8) & 0xff; wv_cdb[5] = lba & 0xff; wv_cdb[6] = group & 0x1f; wv_cdb[7] = (num_lb >> 8) & 0xff; wv_cdb[8] = num_lb & 0xff; ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len, timeout, verbose); return ret; } /* Invokes a SCSI WRITE AND VERIFY (16) command (SBC). Returns 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_write_verify16(int sg_fd, int wrprotect, int dpo, int bytchk, uint64_t llba, int num_lb, int group, unsigned char *dop, int do_len, int timeout, int verbose) { int ret; unsigned char wv_cdb[WRITE_VERIFY16_CMDLEN]; memset(wv_cdb, 0, sizeof(wv_cdb)); wv_cdb[0] = WRITE_VERIFY16_CMD; wv_cdb[1] = ((wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT); if (dpo) wv_cdb[1] |= 0x10; if (bytchk) wv_cdb[1] |= ((bytchk & 0x3) << 1); wv_cdb[2] = (llba >> 56) & 0xff; wv_cdb[3] = (llba >> 48) & 0xff; wv_cdb[4] = (llba >> 40) & 0xff; wv_cdb[5] = (llba >> 32) & 0xff; wv_cdb[6] = (llba >> 24) & 0xff; wv_cdb[7] = (llba >> 16) & 0xff; wv_cdb[8] = (llba >> 8) & 0xff; wv_cdb[9] = llba & 0xff; wv_cdb[10] = (num_lb >> 24) & 0xff; wv_cdb[11] = (num_lb >> 16) & 0xff; wv_cdb[12] = (num_lb >> 8) & 0xff; wv_cdb[13] = num_lb & 0xff; wv_cdb[14] = group & 0x1f; ret = run_scsi_transaction(sg_fd, wv_cdb, sizeof(wv_cdb), dop, do_len, timeout, verbose); return ret; } static int open_if(const char * fn, int got_stdin) { int fd; if (got_stdin) fd = STDIN_FILENO; else { fd = open(fn, O_RDONLY); if (fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", fn, safe_strerror(errno)); return -SG_LIB_FILE_ERROR; } } if (sg_set_binary_mode(fd) < 0) { perror("sg_set_binary_mode"); return -SG_LIB_FILE_ERROR; } return fd; } int main(int argc, char * argv[]) { int sg_fd, res, c, n, first_time; unsigned char * wvb = NULL; void * wrkBuff = NULL; int dpo = 0; int bytchk = 0; int group = 0; int do_16 = 0; int given_do_16 = 0; uint64_t llba = 0; int lba_given = 0; uint32_t num_lb = 1; uint32_t snum_lb = 1; int repeat = 0; int timeout = DEF_TIMEOUT_SECS; int verbose = 0; int64_t ll; int wrprotect = 0; const char * device_name = NULL; const char * ifnp; int has_filename = 0; int ilen = -1; int ifd = -1; int ret = 1; int b_p_lb = 512; int tnum_lb_wr = 0; char cmd_name[32]; ifnp = ""; /* keep MinGW quiet */ while (1) { int option_index = 0; c = getopt_long(argc, argv, "b:dg:hi:I:l:n:RSt:w:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': /* Only bytchk=0 and =1 are meaningful for this command in * sbc4r02 (not =2 nor =3) but that may change in the future. */ bytchk = sg_get_num(optarg); if ((bytchk < 0) || (bytchk > 3)) { fprintf(stderr, "argument to '--bytchk' expected to be 0 " "to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'd': dpo = 1; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 31)) { fprintf(stderr, "argument to '--group' expected to be 0 " "to 31\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': ifnp = optarg; has_filename = 1; break; case 'I': ilen = sg_get_num(optarg); if (-1 == ilen) { fprintf(stderr, "bad argument to '--ilen'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'l': if (lba_given) { fprintf(stderr, "must have one and only one '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } ll = sg_get_llnum(optarg); if (ll < 0) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; ++lba_given; break; case 'n': n = sg_get_num(optarg); if (-1 == n) { fprintf(stderr, "bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_lb = (uint32_t)n; break; case 'R': ++repeat; break; case 'S': do_16 = 1; given_do_16 = 1; break; case 't': timeout = sg_get_num(optarg); if (timeout < 1) { fprintf(stderr, "bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'w': wrprotect = sg_get_num(optarg); if ((wrprotect < 0) || (wrprotect > 7)) { fprintf(stderr, "wrprotect (%d) is out of range ( < %d)\n", wrprotect, 7); return SG_LIB_SYNTAX_ERROR; } break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (! lba_given) { fprintf(stderr, "need a --lba=LBA option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (repeat) { if (! has_filename) { fprintf(stderr, "with '--repeat' need '--in=IF' option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (ilen < 1) { fprintf(stderr, "with '--repeat' need '--ilen=ILEN' option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else { b_p_lb = ilen / num_lb; if (b_p_lb < 64) { fprintf(stderr, "calculated %d bytes per logical block, " "too small\n", b_p_lb); usage(); return SG_LIB_SYNTAX_ERROR; } } } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if ((0 == do_16) && (llba > UINT_MAX)) do_16 = 1; if ((0 == do_16) && (num_lb > 0xffff)) do_16 = 1; snprintf(cmd_name, sizeof(cmd_name), "Write and verify(%d)", (do_16 ? 16 : 10)); if (verbose && (0 == given_do_16) && do_16) fprintf(stderr, "Switching to %s because LBA or NUM too large\n", cmd_name); if (verbose) { fprintf(stderr, "Issue %s to device %s\n\tilen=%d", cmd_name, device_name, ilen); if (ilen > 0) fprintf(stderr, " [0x%x]", ilen); fprintf(stderr, ", lba=%" PRIu64 " [0x%" PRIx64 "]\n\twrprotect=%d, " "dpo=%d, bytchk=%d, group=%d, repeat=%d\n", llba, llba, wrprotect, dpo, bytchk, group, repeat); } first_time = 1; do { if (first_time) { //If a file with data to write has been provided if (has_filename) { struct stat a_stat; if ((1 == strlen(ifnp)) && ('-' == ifnp[0])) { ifd = STDIN_FILENO; ifnp = ""; if (verbose > 1) fprintf(stderr, "Reading input data from stdin\n"); } else { ifd = open_if(ifnp, 0); if (ifd < 0) { ret = -ifd; goto err_out; } } if (ilen < 1) { if (fstat(ifd, &a_stat) < 0) { fprintf(stderr, "Could not fstat(%s)\n", ifnp); goto err_out; } if (! S_ISREG(a_stat.st_mode)) { fprintf(stderr, "Cannot determine IF size, please " "give '--ilen='\n"); goto err_out; } ilen = (int)a_stat.st_size; if (ilen < 1) { fprintf(stderr, "%s file size too small\n", ifnp); goto err_out; } else if (verbose) fprintf(stderr, "Using file size of %d bytes\n", ilen); } if (NULL == (wrkBuff = malloc(ilen))) { fprintf(stderr, ME "out of memory\n"); ret = SG_LIB_CAT_OTHER; goto err_out; } wvb = (unsigned char *)wrkBuff; res = read(ifd, wvb, ilen); if (res < 0) { fprintf(stderr, "Could not read from %s", ifnp); goto err_out; } if (res < ilen) { fprintf(stderr, "Read only %d bytes (expected %d) from " "%s\n", res, ilen, ifnp); if (repeat) fprintf(stderr, "Will scale subsequent pieces when " "repeat=1, but this is first\n"); goto err_out; } } else { if (ilen < 1) { if (verbose) fprintf(stderr, "Default write length to %d*%d=%d " "bytes\n", num_lb, 512, 512 * num_lb); ilen = 512 * num_lb; } if (NULL == (wrkBuff = malloc(ilen))) { fprintf(stderr, ME "out of memory\n"); ret = SG_LIB_CAT_OTHER; goto err_out; } wvb = (unsigned char *)wrkBuff; /* Not sure about this: default contents to 0xff bytes */ memset(wrkBuff, 0xff, ilen); } first_time = 0; snum_lb = num_lb; } else { /* repeat=1, first_time=0, must be reading file */ llba += snum_lb; res = read(ifd, wvb, ilen); if (res < 0) { fprintf(stderr, "Could not read from %s", ifnp); goto err_out; } else { if (verbose > 1) fprintf(stderr, "Subsequent read from %s got %d bytes\n", ifnp, res); if (0 == res) break; if (res < ilen) { snum_lb = (uint32_t)(res / b_p_lb); n = res % b_p_lb; if (0 != n) fprintf(stderr, ">>> warning: ignoring last %d " "bytes of %s\n", n, ifnp); if (snum_lb < 1) break; } } } if (do_16) res = sg_ll_write_verify16(sg_fd, wrprotect, dpo, bytchk, llba, snum_lb, group, wvb, ilen, timeout, verbose); else res = sg_ll_write_verify10(sg_fd, wrprotect, dpo, bytchk, (unsigned int)llba, snum_lb, group, wvb, ilen, timeout, verbose); ret = res; if (repeat && (0 == ret)) tnum_lb_wr += snum_lb; if (ret || (snum_lb != num_lb)) break; } while (repeat); err_out: if (repeat) fprintf(stderr, "%d [0x%x] logical blocks written, in total\n", tnum_lb_wr, tnum_lb_wr); if (wrkBuff) free(wrkBuff); if ((ifd >= 0) && (STDIN_FILENO != ifd)) close(ifd); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } if (ret && (0 == verbose)) { if (SG_LIB_CAT_INVALID_OP == ret) fprintf(stderr, "%s command not supported\n", cmd_name); else if (ret > 0) fprintf(stderr, "%s, exit status %d\n", cmd_name, ret); else if (ret < 0) fprintf(stderr, "Some error occurred\n"); } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_prevent.c0000664000175000017500000001037712335513125015467 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program issues the SCSI PREVENT ALLOW MEDIUM REMOVAL command to the * given SCSI device. */ static const char * version_str = "1.07 20140516"; #define ME "sg_prevent: " static struct option long_options[] = { {"allow", 0, 0, 'a'}, {"help", 0, 0, 'h'}, {"prevent", 1, 0, 'p'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_prevent [--allow] [--help] [--prevent=PC] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --allow|-a allow media removal\n" " --help|-h print usage message then exit\n" " --prevent=PC|-p PC prevent code value (def: 1 -> " "prevent)\n" " 0 -> allow, 1 -> prevent\n" " 2 -> persistent allow, 3 -> " "persistent prevent\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI PREVENT ALLOW MEDIUM REMOVAL command\n" ); } int main(int argc, char * argv[]) { int sg_fd, res, c; int allow = 0; int prevent = -1; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ahp:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': allow = 1; break; case 'h': case '?': usage(); return 0; case 'p': prevent = sg_get_num(optarg); if ((prevent < 0) || (prevent > 3)) { fprintf(stderr, "bad argument to '--prevent'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (allow && (prevent >= 0)) { fprintf(stderr, "can't give both '--allow' and '--prevent='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (allow) prevent = 0; else if (prevent < 0) prevent = 1; /* default is to prevent, as utility name suggests */ sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } res = sg_ll_prevent_allow(sg_fd, prevent, 1, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Prevent allow medium removal: %s\n", b); } res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_senddiag.c0000664000175000017500000007051312407706337015571 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem * Copyright (C) 2003-2014 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. This program issues the SCSI SEND DIAGNOSTIC command and in one case the SCSI RECEIVE DIAGNOSTIC command to list supported diagnostic pages. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ #include "sg_unaligned.h" static const char * version_str = "0.44 20140919"; #define ME "sg_senddiag: " #define DEF_ALLOC_LEN (1024 * 4) static struct option long_options[] = { {"doff", no_argument, 0, 'd'}, {"extdur", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"list", no_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"page", required_argument, 0, 'P'}, {"pf", no_argument, 0, 'p'}, {"raw", required_argument, 0, 'r'}, {"selftest", required_argument, 0, 's'}, {"test", no_argument, 0, 't'}, {"uoff", no_argument, 0, 'u'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_doff; int do_extdur; int do_help; int do_hex; int do_list; int maxlen; int page_code; int do_pf; int do_raw; int do_selftest; int do_deftest; int do_uoff; int do_verbose; int do_version; const char * device_name; const char * raw_arg; int opt_new; }; static void usage() { printf("Usage: sg_senddiag [--doff] [--extdur] [--help] [--hex] " "[--list]\n" " [--maxlen=LEN] [--page=PG] [--pf] " "[--raw=H,H...]\n" " [--selftest=ST] [--test] [--uoff] " "[--verbose] [--version]\n" " [DEVICE]\n" " where:\n" " --doff|-d device online (def: 0, only with '--test')\n" " --extdur|-e duration of an extended self-test (from mode " "page 0xa)\n" " --help|-h print usage message then exit\n" " --hex|-H output in hex\n" " --list|-l list supported page codes (with or without " "DEVICE)\n" " --maxlen=LEN|-m LEN parameter list length or maximum " "allocation\n" " length (default: 4096 bytes)\n" " --page=PG|-p PG do RECEIVE DIAGNOSTIC RESULTS only, set " "PCV\n" " --pf|-p set PF bit (def: 0)\n" " --raw=H,H...|-r H,H... sequence of hex bytes to form " "diag page to send\n" " --raw=-|-r - read stdin for sequence of bytes to send\n" " --selftest=ST|-s ST self-test code, default: 0 " "(inactive)\n" " 1->background short, 2->background " "extended\n" " 4->abort test\n" " 5->foreground short, 6->foreground " "extended\n" " --test|-t default self-test\n" " --uoff|-u unit offline (def: 0, only with '--test')\n" " --verbose|-v increase verbosity\n" " --version|-V output version string then exit\n\n" "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC " "RESULTS) command\n" ); } static void usage_old() { printf("Usage: sg_senddiag [-doff] [-e] [-h] [-H] [-l] [-pf]" " [-raw=H,H...]\n" " [-s=SF] [-t] [-uoff] [-v] [-V] " "[DEVICE]\n" " where:\n" " -doff device online (def: 0, only with '-t')\n" " -e duration of an extended self-test (from mode page " "0xa)\n" " -h output in hex\n" " -H output in hex (same as '-h')\n" " -l list supported page codes\n" " -pf set PF bit (def: 0)\n" " -raw=H,H... sequence of bytes to form diag page to " "send\n" " -raw=- read stdin for sequence of bytes to send\n" " -s=SF self-test code (def: 0)\n" " 1->background short, 2->background extended," " 4->abort test\n" " 5->foreground short, 6->foreground extended\n" " -t default self-test\n" " -uoff unit offline (def: 0, only with '-t')\n" " -v increase verbosity (print issued SCSI cmds)\n" " -V output version string\n" " -? output this usage message\n\n" "Performs a SCSI SEND DIAGNOSTIC (and/or a RECEIVE DIAGNOSTIC " "RESULTS) command\n" ); } static int process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c, n; while (1) { int option_index = 0; c = getopt_long(argc, argv, "dehHlm:NOpP:r:s:tuvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': op->do_doff = 1; break; case 'e': op->do_extdur = 1; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'l': ++op->do_list; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { fprintf(stderr, "bad argument to '--maxlen=' or greater " "than 65535 [0xffff]\n"); return SG_LIB_SYNTAX_ERROR; } op->maxlen = n; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': op->do_pf = 1; break; case 'P': n = sg_get_num(optarg); if ((n < 0) || (n > 0xff)) { fprintf(stderr, "bad argument to '--page=' or greater " "than 255 [0xff]\n"); return SG_LIB_SYNTAX_ERROR; } op->page_code = n; break; case 'r': op->raw_arg = optarg; op->do_raw = 1; break; case 's': n = sg_get_num(optarg); if ((n < 0) || (n > 7)) { fprintf(stderr, "bad argument to '--selftest='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->do_selftest = n; break; case 't': op->do_deftest = 1; break; case 'u': op->do_uoff = 1; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->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 * op, int argc, char * argv[]) { int k, jmp_out, plen, num; unsigned int u; 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 'd': if (0 == strncmp("doff", cp, 4)) { op->do_doff = 1; cp += 3; plen -= 3; } else jmp_out = 1; break; case 'e': op->do_extdur = 1; break; case 'h': case 'H': ++op->do_hex; break; case 'l': ++op->do_list; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case 'p': if (0 == strncmp("pf", cp, 2)) { op->do_pf = 1; ++cp; --plen; } else jmp_out = 1; break; case 't': op->do_deftest = 1; break; case 'u': if (0 == strncmp("uoff", cp, 4)) { op->do_uoff = 1; cp += 3; plen -= 3; } else jmp_out = 1; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case '?': ++op->do_help; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("raw=", cp, 4)) { op->raw_arg = cp + 4; op->do_raw = 1; } else if (0 == strncmp("s=", cp, 2)) { num = sscanf(cp + 2, "%x", &u); if ((1 != num) || (u > 7)) { printf("Bad page code after '-s=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->do_selftest = u; } else if (0 == strncmp("-old", cp, 5)) ; else if (jmp_out) { fprintf(stderr, "Unrecognized option: %s\n", cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == op->device_name) op->device_name = cp; else { fprintf(stderr, "too many arguments, got: %s, not expecting: " "%s\n", op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } return 0; } static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } /* Return of 0 -> success, otherwise see sg_ll_send_diag() */ static int do_senddiag(int sg_fd, int sf_code, int pf_bit, int sf_bit, int devofl_bit, int unitofl_bit, void * outgoing_pg, int outgoing_len, int noisy, int verbose) { int long_duration = 0; if ((0 == sf_bit) && ((5 == sf_code) || (6 == sf_code))) long_duration = 1; /* foreground self-tests */ return sg_ll_send_diag(sg_fd, sf_code, pf_bit, sf_bit, devofl_bit, unitofl_bit, long_duration, outgoing_pg, outgoing_len, noisy, verbose); } /* Get expected extended self-test time from mode page 0xa (for '-e') */ static int do_modes_0a(int sg_fd, void * resp, int mx_resp_len, int noisy, int mode6, int verbose) { int res; if (mode6) res = sg_ll_mode_sense6(sg_fd, 1 /* dbd */, 0 /* pc */, 0xa /* page */, 0, resp, mx_resp_len, noisy, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, 1 /* dbd */, 0, 0xa, 0, resp, mx_resp_len, noisy, verbose); if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Mode sense (%s): %s\n", (mode6 ? "6" : "10"), b); } return res; } /* Read hex numbers from command line (comma separated list) or from */ /* stdin (one per line, comma separated list or space separated list). */ /* Returns 0 if ok, or 1 if error. */ static int build_diag_page(const char * inp, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int in_len, k, j, m; unsigned int h; const char * lcp; char * cp; char * c2p; if ((NULL == inp) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *mp_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ char line[512]; char carry_over[4]; int off = 0; int split_line; carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), stdin)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { fprintf(stderr, "build_diag_page: carry_over error " "['%s'] around line %d\n", carry_over, j + 1); return 1; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { fprintf(stderr, "build_diag_page: syntax error at " "line %d, pos %d\n", j + 1, m + k + 1); return 1; } for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "build_diag_page: hex number " "larger than 0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { fprintf(stderr, "build_diag_page: array length " "exceeded\n"); return 1; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } fprintf(stderr, "build_diag_page: error in " "line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } } off += (k + 1); } *mp_arr_len = off; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { fprintf(stderr, "build_diag_page: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "build_diag_page: hex number larger " "than 0xff at pos %d\n", (int)(lcp - inp + 1)); return 1; } mp_arr[k] = h; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { fprintf(stderr, "build_diag_page: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *mp_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_diag_page: array length exceeded\n"); return 1; } } return 0; } struct page_code_desc { int page_code; const char * desc; }; static struct page_code_desc pc_desc_arr[] = { {0x0, "Supported diagnostic pages"}, {0x1, "Configuration (SES)"}, {0x2, "Enclosure status/control (SES)"}, {0x3, "Help text (SES)"}, {0x4, "String In/Out (SES)"}, {0x5, "Threshold In/Out (SES)"}, {0x6, "Array Status/Control (SES, obsolete)"}, {0x7, "Element descriptor (SES)"}, {0x8, "Short enclosure status (SES)"}, {0x9, "Enclosure busy (SES-2)"}, {0xa, "Additional (device) element status (SES-2)"}, {0xb, "Subenclosure help text (SES-2)"}, {0xc, "Subenclosure string In/Out (SES-2)"}, {0xd, "Supported SES diagnostic pages (SES-2)"}, {0xe, "Download microcode diagnostic pages (SES-2)"}, {0xf, "Subenclosure nickname diagnostic pages (SES-2)"}, {0x3f, "Protocol specific (SAS transport)"}, {0x40, "Translate address (direct access)"}, {0x41, "Device status (direct access)"}, {0x42, "Rebuild assist (direct access)"}, /* sbc3r31 */ }; static const char * find_page_code_desc(int page_num) { int k; int num = sizeof(pc_desc_arr) / sizeof(pc_desc_arr[0]); const struct page_code_desc * pcdp = &pc_desc_arr[0]; for (k = 0; k < num; ++k, ++pcdp) { if (page_num == pcdp->page_code) return pcdp->desc; else if (page_num < pcdp->page_code) return NULL; } return NULL; } static void list_page_codes() { int k; int num = sizeof(pc_desc_arr) / sizeof(pc_desc_arr[0]); const struct page_code_desc * pcdp = &pc_desc_arr[0]; printf("Page_Code Description\n"); for (k = 0; k < num; ++k, ++pcdp) printf(" 0x%02x %s\n", pcdp->page_code, (pcdp->desc ? pcdp->desc : "")); } int main(int argc, char * argv[]) { int sg_fd, k, num, rsp_len, res, rsp_buff_size, pg; int read_in_len = 0; int ret = 0; struct opts_t opts; struct opts_t * op; unsigned char * rsp_buff = NULL; const char * cp; unsigned char * read_in = NULL; op = &opts; memset(op, 0, sizeof(opts)); op->maxlen = DEF_ALLOC_LEN; op->page_code = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { if (op->opt_new) usage(); else usage_old(); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } rsp_buff_size = op->maxlen; if (NULL == op->device_name) { if (op->do_list) { list_page_codes(); return 0; } fprintf(stderr, "No DEVICE argument given\n"); if (op->opt_new) usage(); else usage_old(); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { read_in = (unsigned char *)calloc(op->maxlen, 1); if (NULL == read_in) { fprintf(stderr, "unable to allocate %d bytes\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (build_diag_page(op->raw_arg, read_in, &read_in_len, sizeof(read_in))) { if (op->opt_new) { printf("Bad sequence after '--raw=' option\n"); usage(); } else { printf("Bad sequence after '-raw=' option\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } } if ((op->do_doff || op->do_uoff) && (! op->do_deftest)) { if (op->opt_new) { printf("setting --doff or --uoff only useful when -t is set\n"); usage(); } else { printf("setting -doff or -uoff only useful when -t is set\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if ((op->do_selftest > 0) && op->do_deftest) { if (op->opt_new) { printf("either set --selftest=SF or --test (not both)\n"); usage(); } else { printf("either set -s=SF or -t (not both)\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { if ((op->do_selftest > 0) || op->do_deftest || op->do_extdur || op->do_list) { if (op->opt_new) { printf("'--raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage(); } else { printf("'-raw=' cannot be used with self-tests, '-e' or " "'-l'\n"); usage_old(); } return SG_LIB_SYNTAX_ERROR; } if (! op->do_pf) { if (op->opt_new) printf(">>> warning, '--pf' probably should be used with " "'--raw='\n"); else printf(">>> warning, '-pf' probably should be used with " "'-raw='\n"); } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->do_verbose > 4) fprintf(stderr, "Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); if (op->maxlen >= 16384) scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif if ((sg_fd = sg_cmds_open_device(op->device_name, 0 /* rw */, op->do_verbose)) < 0) { fprintf(stderr, ME "error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } rsp_buff = (unsigned char *)calloc(op->maxlen, 1); if (NULL == rsp_buff) { fprintf(stderr, "unable to allocate %d bytes (2)\n", op->maxlen); return SG_LIB_CAT_OTHER; } if (op->do_extdur) { res = do_modes_0a(sg_fd, rsp_buff, 32, 1, 0, op->do_verbose); if (0 == res) { /* Assume mode sense(10) response without block descriptors */ num = sg_get_unaligned_be16(rsp_buff) - 6; if (num >= 0xc) { int secs; secs = sg_get_unaligned_be16(rsp_buff + 18); #ifdef SG_LIB_MINGW printf("Expected extended self-test duration=%d seconds " "(%g minutes)\n", secs, secs / 60.0); #else printf("Expected extended self-test duration=%d seconds " "(%.2f minutes)\n", secs, secs / 60.0); #endif } else printf("Extended self-test duration not available\n"); } else { ret = res; printf("Extended self-test duration (mode page 0xa) failed\n"); goto err_out9; } } else if ((op->do_list) || (op->page_code >= 0x0)) { pg = op->page_code; if (pg < 0) res = do_senddiag(sg_fd, 0, 1 /* pf */, 0, 0, 0, rsp_buff, 4, 1, op->do_verbose); else res = 0; if (0 == res) { if (0 == sg_ll_receive_diag(sg_fd, (pg >= 0x0), ((pg >= 0x0) ? pg : 0), rsp_buff, rsp_buff_size, 1, op->do_verbose)) { rsp_len = sg_get_unaligned_be16(rsp_buff + 2) + 4; if (pg < 0x1) { printf("Supported diagnostic pages response:\n"); if (op->do_hex) dStrHex((const char *)rsp_buff, rsp_len, 1); else { for (k = 0; k < (rsp_len - 4); ++k) { cp = find_page_code_desc(rsp_buff[k + 4]); printf(" 0x%02x %s\n", rsp_buff[k + 4], (cp ? cp : "")); } } } else { cp = find_page_code_desc(pg); if (cp) printf("%s diagnostic page [0x%x] response in " "hex:\n", cp, pg); else printf("diagnostic page 0x%x response in hex:\n", pg); dStrHex((const char *)rsp_buff, rsp_len, 1); } } else { ret = res; fprintf(stderr, "RECEIVE DIAGNOSTIC RESULTS command " "failed\n"); goto err_out9; } } else { ret = res; goto err_out; } } else if (op->do_raw) { res = do_senddiag(sg_fd, 0, op->do_pf, 0, 0, 0, read_in, read_in_len, 1, op->do_verbose); if (res) { ret = res; goto err_out; } } else { res = do_senddiag(sg_fd, op->do_selftest, op->do_pf, op->do_deftest, op->do_doff, op->do_uoff, NULL, 0, 1, op->do_verbose); if (0 == res) { if ((5 == op->do_selftest) || (6 == op->do_selftest)) printf("Foreground self-test returned GOOD status\n"); else if (op->do_deftest && (! op->do_doff) && (! op->do_uoff)) printf("Default self-test returned GOOD status\n"); } else { ret = res; goto err_out; } } res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_SYNTAX_ERROR; return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; err_out: if (SG_LIB_CAT_UNIT_ATTENTION == res) fprintf(stderr, "SEND DIAGNOSTIC, unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "SEND DIAGNOSTIC, aborted command\n"); else if (SG_LIB_CAT_NOT_READY == res) fprintf(stderr, "SEND DIAGNOSTIC, device not " "ready\n"); else fprintf(stderr, "SEND DIAGNOSTIC command, failed\n"); err_out9: if (op->do_verbose < 2) fprintf(stderr, " try again with '-vv' for more information\n"); res = sg_cmds_close_device(sg_fd); if ((res < 0) && (0 == ret)) return SG_LIB_FILE_ERROR; if (read_in) free(read_in); if (rsp_buff) free(rsp_buff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_logs.c0000664000175000017500000060121212415077207014747 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2014 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. This program outputs information provided by a SCSI LOG SENSE command. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ static const char * version_str = "1.26 20141007"; /* spc4r37 + sbc4r02 */ #define MX_ALLOC_LEN (0xfffc) #define SHORT_RESP_LEN 128 #define SUPP_PAGES_LPAGE 0x0 #define BUFF_OVER_UNDER_LPAGE 0x1 #define WRITE_ERR_LPAGE 0x2 #define READ_ERR_LPAGE 0x3 #define READ_REV_ERR_LPAGE 0x4 #define VERIFY_ERR_LPAGE 0x5 #define NON_MEDIUM_LPAGE 0x6 #define LAST_N_ERR_LPAGE 0x7 #define FORMAT_STATUS_LPAGE 0x8 #define LAST_N_DEFERRED_LPAGE 0xb #define LB_PROV_LPAGE 0xc #define TEMPERATURE_LPAGE 0xd #define START_STOP_LPAGE 0xe #define APP_CLIENT_LPAGE 0xf #define SELF_TEST_LPAGE 0x10 #define SOLID_STATE_MEDIA_LPAGE 0x11 #define SAT_ATA_RESULTS_LPAGE 0x16 #define PROTO_SPECIFIC_LPAGE 0x18 #define STATS_LPAGE 0x19 #define PCT_LPAGE 0x1a #define TAPE_ALERT_LPAGE 0x2e #define IE_LPAGE 0x2f #define NOT_SPG_SUBPG 0x0 #define SUPP_SPGS_SUBPG 0xff #define LOW_GRP_STATS_SUBPG 0x1 #define HIGH_GRP_STATS_SUBPG 0x1f #define CACHE_STATS_SUBPG 0x20 #define PCB_STR_LEN 128 #define LOG_SENSE_PROBE_ALLOC_LEN 4 static unsigned char rsp_buff[MX_ALLOC_LEN + 4]; static struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"brief", no_argument, 0, 'b'}, {"control", required_argument, 0, 'c'}, {"filter", required_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", required_argument, 0, 'i'}, {"list", no_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"name", no_argument, 0, 'n'}, {"new", no_argument, 0, 'N'}, {"no_inq", no_argument, 0, 'x'}, {"old", no_argument, 0, 'O'}, {"page", required_argument, 0, 'p'}, {"paramp", required_argument, 0, 'P'}, {"pcb", no_argument, 0, 'q'}, {"ppc", no_argument, 0, 'Q'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'X'}, {"reset", no_argument, 0, 'R'}, {"sp", no_argument, 0, 's'}, {"select", no_argument, 0, 'S'}, {"temperature", no_argument, 0, 't'}, {"transport", no_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_all; int do_brief; int do_help; int do_hex; int do_list; int do_name; int do_pcb; int do_ppc; int do_raw; int o_readonly; int do_pcreset; int do_select; int do_sp; int do_temperature; int do_transport; int do_verbose; int do_version; int filter; int filter_given; int page_control; int maxlen; int pg_code; int subpg_code; int paramp; int opt_new; int no_inq; const char * device_name; const char * in_fn; }; #ifdef SG_LIB_WIN32 static int win32_spt_init_state = 0; static int win32_spt_curr_state = 0; #endif #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: sg_logs [--all] [--brief] [--control=PC] [--filter=PARC] " " [--help]\n" " [--hex] [--in=FN] [--list] [--no_inq] " "[--maxlen=LEN]\n" " [--name] [--page=PG[,SPG]] [--paramp=PP] [--pcb] " "[--ppc]\n" " [--raw] [--readonly] [--reset] [--select] " "[--sp]\n" " [--temperature] [--transport] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --all|-a fetch and decode all log pages\n" " use twice to fetch and decode all log pages " "and subpages\n" " --brief|-b shorten the output of some log pages\n" " --control=PC|-c PC page control(PC) (default: 1)\n" " 0: current threshhold, 1: current " "cumulative\n" " 2: default threshhold, 3: default " "cumulative\n" " --filter=PARC|-f PARC filter based on parameter code " "PARC\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex (default: decode if " "known)\n" " --in=FN|-i FN FN is a filename containing a log page " "in ASCII hex\n" " or binary if --raw also given. For LOG " "SELECT\n" " --list|-l list supported log page names (equivalent to " "'-p 0')\n" " use twice to list supported log page and " "subpage names\n" " --no_inq|-x no initial INQUIRY output (twice: no " "INQUIRY call)\n" " --maxlen=LEN|-m LEN max response length (def: 0 " "-> everything)\n" " when > 1 will request LEN bytes\n" " --name|-n decode some pages into multiple name=value " "lines\n" " --page=PG|-p PG page code (in decimal)\n" " --page=PG,SPG|-p PG,SPG\n" " page code plus subpage code (both default " "to 0)\n" " --paramp=PP|-P PP parameter pointer (decimal) (def: 0)\n" " --pcb|-q show parameter control bytes in decoded " "output\n"); pr2serr(" --ppc|-Q set the Parameter Pointer Control (PPC) bit " "(def: 0)\n" " --raw|-r output response in binary to stdout\n" " --readonly|-X open DEVICE read-only (def: first " "read-write then if\n" " fails try open again read-only)\n" " --reset|-R reset log parameters (takes PC and SP into " "account)\n" " (uses PCR bit in LOG SELECT)\n" " --select|-S perform LOG SELECT (def: LOG SENSE)\n" " --sp|-s set the Saving Parameters (SP) bit (def: 0)\n" " --temperature|-t decode temperature (log page 0xd or " "0x2f)\n" " --transport|-T decode transport (protocol specific port " "0x18) log page\n" " --verbose|-v increase verbosity\n" " --version|-V output version string then exit\n\n" "Performs a SCSI LOG SENSE (or LOG SELECT) command and decodes " "the response.\n"); } static void usage_old() { printf("Usage: sg_logs [-a] [-A] [-b] [-c=PC] [-f=PARC] [-h] [-H] " "[-i=FN]\n" " [-l] [-L] [-m=LEN] [-n] [-p=PG[,SPG]] " "[-paramp=PP]\n" " [-pcb] [-ppc] [-r] [-select] [-sp] [-t] [-T] " "[-v] [-V]\n" " [-x] [-X] [-?] DEVICE\n" " where:\n" " -a fetch and decode all log pages\n" " -A fetch and decode all log pages and subpages\n" " -b shorten the output of some log pages\n" " -c=PC page control(PC) (default: 1)\n" " 0: current threshhold, 1: current cumulative\n" " 2: default threshhold, 3: default cumulative\n" " -f=PARC filter based on parameter code PARC\n" " -h output in hex (default: decode if known)\n" " -H output in hex (same as '-h')\n" " -i=FN FN is a filename containing a log page " "in ASCII hex.\n" " For LOG SELECT\n" " -l list supported log page names (equivalent to " "'-p=0')\n" " -L list supported log page and subpages names " "(equivalent to\n" " '-p=0,ff')\n" " -m=LEN max response length (decimal) (def: 0 " "-> everything)\n" " -n decode some pages into multiple name=value " "lines\n" " -p=PG page code in hex (def: 0)\n" " -p=PG,SPG both in hex, (defs: 0,0)\n" " -paramp=PP (in hex) (def: 0)\n" " -pcb show parameter control bytes in decoded " "output\n"); printf(" -ppc set the Parameter Pointer Control (PPC) bit " "(def: 0)\n" " -r reset log parameters (takes PC and SP into " "account)\n" " (uses PCR bit in LOG SELECT)\n" " -select perform LOG SELECT (def: LOG SENSE)\n" " -sp set the Saving Parameters (SP) bit (def: 0)\n" " -t outputs temperature log page (0xd)\n" " -T outputs transport (protocol specific port) log " "page (0x18)\n" " -v increase verbosity\n" " -V output version string\n" " -x no initial INQUIRY output (twice: no INQUIRY call)\n" " -X open DEVICE read-only (def: first read-write then " "if fails\n" " try open again with read-only)\n" " -? output this usage message\n\n" "Performs a SCSI LOG SENSE (or LOG SELECT) command\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } /* Processes command line options according to new option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c, n, nn; char * cp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "aAbc:f:hHi:lLm:nNOp:P:qQrRsStTvVxX", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'b': ++op->do_brief; break; case 'c': n = sg_get_num(optarg); if ((n < 0) || (n > 3)) { pr2serr("bad argument to '--control='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->page_control = n; break; case 'f': n = sg_get_num(optarg); if ((n < 0) || (n > 0xffff)) { pr2serr("bad argument to '--filter='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->filter = n; ++op->filter_given; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': op->in_fn = optarg; break; case 'l': ++op->do_list; break; case 'L': op->do_list += 2; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (1 == n) || (n > 0xffff)) { pr2serr("bad argument to '--maxlen=', from 2 to 65535 " "(inclusive) expected\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->maxlen = n; break; case 'n': ++op->do_name; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': cp = strchr(optarg, ','); n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 63)) { pr2serr("Bad argument to '--page='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (cp) { nn = sg_get_num_nomult(cp + 1); if ((nn < 0) || (nn > 255)) { pr2serr("Bad second value in argument to '--page='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } else nn = 0; op->pg_code = n; op->subpg_code = nn; break; case 'P': n = sg_get_num(optarg); if (n < 0) { pr2serr("bad argument to '--paramp='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->paramp = n; break; case 'q': ++op->do_pcb; break; case 'Q': /* N.B. PPC bit obsoleted in SPC-4 rev 18 */ ++op->do_ppc; break; case 'r': ++op->do_raw; break; case 'R': ++op->do_pcreset; ++op->do_select; break; case 's': ++op->do_sp; break; case 'S': ++op->do_select; break; case 't': ++op->do_temperature; break; case 'T': ++op->do_transport; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case 'x': ++op->no_inq; break; case 'X': ++op->o_readonly; break; default: pr2serr("unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Processes command line options according to old option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int process_cl_old(struct opts_t * op, int argc, char * argv[]) { int k, jmp_out, plen, num, n; unsigned int u, uu; 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 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'b': ++op->do_brief; break; case 'h': case 'H': ++op->do_hex; break; case 'l': ++op->do_list; break; case 'L': op->do_list += 2; break; case 'n': ++op->do_name; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case 'r': op->do_pcreset = 1; op->do_select = 1; break; case 't': ++op->do_temperature; break; case 'T': ++op->do_transport; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case 'x': ++op->no_inq; break; case 'X': ++op->o_readonly; break; case '?': ++op->do_help; break; case '-': ++cp; jmp_out = 1; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("c=", cp, 2)) { num = sscanf(cp + 2, "%x", &u); if ((1 != num) || (u > 3)) { pr2serr("Bad page control after '-c=' option [0..3]\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->page_control = u; } else if (0 == strncmp("f=", cp, 2)) { n = sg_get_num(cp + 2); if ((n < 0) || (n > 0xffff)) { pr2serr("Bad argument after '-f=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->filter = n; ++op->filter_given; } else if (0 == strncmp("i=", cp, 2)) op->in_fn = cp + 2; else if (0 == strncmp("m=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 0) || (n > MX_ALLOC_LEN)) { pr2serr("Bad maximum response length after '-m=' " "option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->maxlen = n; } else if (0 == strncmp("p=", cp, 2)) { if (NULL == strchr(cp + 2, ',')) { num = sscanf(cp + 2, "%x", &u); if ((1 != num) || (u > 63)) { pr2serr("Bad page code value after '-p=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->pg_code = u; } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) { if (uu > 255) { pr2serr("Bad sub page code value after '-p=' " "option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->pg_code = u; op->subpg_code = uu; } else { pr2serr("Bad page code, subpage code sequence after " "'-p=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp("paramp=", cp, 7)) { num = sscanf(cp + 7, "%x", &u); if ((1 != num) || (u > 0xffff)) { pr2serr("Bad parameter pointer after '-paramp=' " "option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->paramp = u; } else if (0 == strncmp("pcb", cp, 3)) op->do_pcb = 1; else if (0 == strncmp("ppc", cp, 3)) op->do_ppc = 1; else if (0 == strncmp("select", cp, 6)) op->do_select = 1; else if (0 == strncmp("sp", cp, 2)) op->do_sp = 1; else if (0 == strncmp("old", cp, 3)) ; else if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == op->device_name) op->device_name = cp; else { pr2serr("too many arguments, got: %s, not expecting: %s\n", op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Process command line options. First check using new option format unless * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the * old option format to be checked first. Both new and old format can be * countermanded by a '-O' and '-N' options respectively. As soon as either * of these options is detected (when processing the other format), processing * stops and is restarted using the other format. Clear? */ static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Decode counter up to 8 chars long (big endian) into an uint64_t. * In the unlikely event that the counter is larger than 8 chars long * then take the last 8 chars. */ static uint64_t decode_count(const unsigned char * xp, int len) { int j; uint64_t ull; if (len > (int)sizeof(ull)) { xp += (len - sizeof(ull)); len = sizeof(ull); } ull = 0; for (j = 0; j < len; ++j) { if (j > 0) ull <<= 8; ull |= xp[j]; } return ull; } /* Read ASCII hex bytes or binary from fname (a file named '-' taken as * stdin). If reading ASCII hex then there should be either one entry per * line or a comma, space or tab separated list of bytes. If no_space is * set then a string of ACSII hex digits is expected, 2 per byte. Everything * from and including a '#' on a line is ignored. Returns 0 if ok, or 1 if * error. */ static int f2hex_arr(const char * fname, int as_binary, int no_space, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int fn_len, in_len, k, j, m, split_line, fd, has_stdin; unsigned int h; const char * lcp; FILE * fp; char line[512]; char carry_over[4]; int off = 0; if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; fn_len = strlen(fname); if (0 == fn_len) return 1; has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */ if (as_binary) { if (has_stdin) { fd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { fd = open(fname, O_RDONLY); if (fd < 0) { pr2serr("unable to open binary file %s: %s\n", fname, safe_strerror(errno)); return 1; } else if (sg_set_binary_mode(fd) < 0) perror("sg_set_binary_mode"); } k = read(fd, mp_arr, max_arr_len); if (k <= 0) { if (0 == k) pr2serr("read 0 bytes from binary file %s\n", fname); else pr2serr("read from binary file %s: %s\n", fname, safe_strerror(errno)); if (! has_stdin) close(fd); return 1; } *mp_arr_len = k; if (! has_stdin) close(fd); return 0; } else { /* So read the file as ASCII hex */ if (has_stdin) fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { pr2serr("Unable to open %s for reading\n", fname); return 1; } } } carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { pr2serr("f2hex_arr: carry_over error ['%s'] around line " "%d\n", carry_over, j + 1); goto bad; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("f2hex_arr: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto bad; } if (no_space) { for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1)); ++k, lcp += 2) { if (1 != sscanf(lcp, "%2x", &h)) { pr2serr("f2hex_arr: bad hex number in line %d, " "pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; off += k; } else { for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("f2hex_arr: hex number larger than " "0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("f2hex_arr: error in line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } } off += (k + 1); } } *mp_arr_len = off; if (stdin != fp) fclose(fp); return 0; bad: if (stdin != fp) fclose(fp); return 1; } /* Call LOG SENSE twice: the first time ask for 4 byte response to determine actual length of response; then a second time requesting the min(actual_len, mx_resp_len) bytes. If the calculated length for the second fetch is odd then it is incremented (perhaps should be made modulo 4 in the future for SAS). Returns 0 if ok, SG_LIB_CAT_INVALID_OP for log_sense not supported, SG_LIB_CAT_ILLEGAL_REQ for bad field in log sense command, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_UNIT_ATTENTION, SG_LIB_CAT_ABORTED_COMMAND and -1 for other errors. */ static int do_logs(int sg_fd, unsigned char * resp, int mx_resp_len, const struct opts_t * op) { int actual_len, res, vb; #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (0 == win32_spt_init_state) { if (win32_spt_curr_state) { if (mx_resp_len < 16384) { scsi_pt_win32_direct(0); win32_spt_curr_state = 0; } } else { if (mx_resp_len >= 16384) { scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT direct */); win32_spt_curr_state = 1; } } } #endif #endif memset(resp, 0, mx_resp_len); vb = op->do_verbose; if (op->maxlen > 1) actual_len = mx_resp_len; else { if ((res = sg_ll_log_sense(sg_fd, op->do_ppc, op->do_sp, op->page_control, op->pg_code, op->subpg_code, op->paramp, resp, LOG_SENSE_PROBE_ALLOC_LEN, 1 /* noisy */, vb))) return res; actual_len = (resp[2] << 8) + resp[3] + 4; if ((0 == op->do_raw) && (vb > 1)) { pr2serr(" Log sense (find length) response:\n"); dStrHexErr((const char *)resp, LOG_SENSE_PROBE_ALLOC_LEN, 1); pr2serr(" hence calculated response length=%d\n", actual_len); } if (op->pg_code != (0x3f & resp[0])) { if (vb) pr2serr("Page code does not appear in first byte of " "response so it's suspect\n"); if (actual_len > 0x40) { actual_len = 0x40; if (vb) pr2serr("Trim response length to 64 bytes due to " "suspect response format\n"); } } /* Some HBAs don't like odd transfer lengths */ if (actual_len % 2) actual_len += 1; if (actual_len > mx_resp_len) actual_len = mx_resp_len; } if ((res = sg_ll_log_sense(sg_fd, op->do_ppc, op->do_sp, op->page_control, op->pg_code, op->subpg_code, op->paramp, resp, actual_len, 1 /* noisy */, vb))) return res; if ((0 == op->do_raw) && (vb > 1)) { pr2serr(" Log sense response:\n"); dStrHexErr((const char *)resp, actual_len, 1); } return 0; } static void show_page_name(int pg_code, int subpg_code, struct sg_simple_inquiry_resp * inq_dat) { int done; char b[64]; memset(b, 0, sizeof(b)); /* first process log pages that do not depend on peripheral type */ if (NOT_SPG_SUBPG == subpg_code) snprintf(b, sizeof(b) - 1, " 0x%02x ", pg_code); else snprintf(b, sizeof(b) - 1, " 0x%02x,0x%02x ", pg_code, subpg_code); done = 1; if ((NOT_SPG_SUBPG == subpg_code) || (SUPP_SPGS_SUBPG == subpg_code)) { switch (pg_code) { case SUPP_PAGES_LPAGE: printf("%sSupported log pages", b); break; case BUFF_OVER_UNDER_LPAGE: printf("%sBuffer over-run/under-run", b); break; case WRITE_ERR_LPAGE: printf("%sError counters (write)", b); break; case READ_ERR_LPAGE: printf("%sError counters (read)", b); break; case READ_REV_ERR_LPAGE: printf("%sError counters (read reverse)", b); break; case VERIFY_ERR_LPAGE: printf("%sError counters (verify)", b); break; case NON_MEDIUM_LPAGE: printf("%sNon-medium errors", b); break; case LAST_N_ERR_LPAGE: printf("%sLast n error events", b); break; case LAST_N_DEFERRED_LPAGE: printf("%sLast n deferred errors or " "asynchronous events", b); break; case TEMPERATURE_LPAGE: printf("%sTemperature", b); break; case START_STOP_LPAGE: printf("%sStart-stop cycle counter", b); break; case APP_CLIENT_LPAGE: printf("%sApplication client", b); break; case SELF_TEST_LPAGE: printf("%sSelf-test results", b); break; case PROTO_SPECIFIC_LPAGE: printf("%sProtocol specific port", b); break; case STATS_LPAGE: printf("%sGeneral statistics and performance", b); break; case PCT_LPAGE: printf("%sPower condition transition", b); break; case IE_LPAGE: printf("%sInformational exceptions (SMART)", b); break; default: done = 0; break; } if (done) { if (SUPP_SPGS_SUBPG == subpg_code) printf(" and subpages\n"); else printf("\n"); return; } } /* There are not many log subpages currently */ if (STATS_LPAGE == pg_code) { if ((subpg_code >= LOW_GRP_STATS_SUBPG) && (subpg_code <= HIGH_GRP_STATS_SUBPG)) { printf("%sGroup statistics and performance (%d)\n", b, subpg_code); return; } else if (subpg_code == CACHE_STATS_SUBPG) { printf("%sCache memory statistics\n", b); return; } } if (0x15 == pg_code) { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: if (0 == subpg_code) { /* introduced: SBC-3 */ printf("%sBackground scan results\n", b); return; } else if (1 == subpg_code) { /* introduced: SBC-4 */ printf("%sPending defects\n", b); return; } break; default: break; } } if (subpg_code > 0) { printf("%s??\n", b); return; } done = 1; switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ { switch (pg_code) { case FORMAT_STATUS_LPAGE: /* introduced: SBC-2 */ printf("%sFormat status\n", b); break; case LB_PROV_LPAGE: /* 0xc introduced: SBC-3 */ printf("%sLogical block provisioning\n", b); break; /* case 0x15: has subpage in sbc4 */ case SOLID_STATE_MEDIA_LPAGE: /* 0x11 introduced: SBC-3 */ printf("%sSolid state media\n", b); break; case SAT_ATA_RESULTS_LPAGE: /* introduced: SAT-2 */ printf("%sATA pass-through results (sat)\n", b); break; case 0x17: /* introduced: SBC-2 */ printf("%sNon-volatile cache\n", b); break; case 0x30: printf("%sPerformance counters (Hitachi)\n", b); break; case 0x37: printf("%sCache (Seagate), Miscellaneous (Hitachi)\n", b); break; case 0x3e: printf("%sFactory (Seagate/Hitachi)\n", b); break; default: done = 0; break; } } break; case PDT_TAPE: case PDT_PRINTER: /* tape (streaming) and printer (obsolete) devices */ { switch (pg_code) { case 0xc: /* introduced: SSC-2 */ printf("%sSequential access device\n", b); break; case 0x11: /* introduced: SSC-3 */ printf("%sDT Device status\n", b); break; case 0x12: /* introduced: SSC-3 */ printf("%sTape alert response\n", b); break; case 0x13: /* introduced: SSC-3 */ printf("%sRequested recovery\n", b); break; case 0x14: /* introduced: SSC-3 */ printf("%sDevice statistics\n", b); break; case 0x16: /* introduced: SSC-3 */ printf("%sTape diagnostic\n", b); break; case 0x17: /* introduced: SSC-4 */ printf("%sVolume statistics\n", b); break; case 0x1b: /* introduced: SSC-4 */ printf("%sData compression\n", b); break; case 0x2d: /* introduced: SSC-3 */ printf("%sCurrent service information\n", b); break; case TAPE_ALERT_LPAGE: /* introduced: SSC-2 */ printf("%sTapeAlert\n", b); break; case 0x30: printf("%sTape usage (LTO-5 and 6 specific)\n", b); break; case 0x31: printf("%sTape capacity (LTO-5 and 6 specific)\n", b); break; case 0x32: printf("%sData compression (LTO-5 specific, LTO-6 use " "0x1b)\n", b); break; case 0x33: /* in LTO-6 this is 'Device Wellness' page */ printf("%sWrite errors (LTO-5 specific)\n", b); break; case 0x34: /* in LTO-6 this is Performance data page */ printf("%sRead forward errors (LTO-5 specific)\n", b); break; /* case 0x35: in LTO-6 this is DT Device Error page */ case 0x37: printf("%sPerformance characteristics (LTO-5 specific)\n", b); break; case 0x38: printf("%sBlocks/bytes transferred (LTO-5 specific)\n", b); break; case 0x39: printf("%sHost port 0 interface errors (LTO-5 specific)\n", b); break; case 0x3a: printf("%sDrive control verification (LTO-5 specific)\n", b); break; case 0x3b: printf("%sHost port 1 interface errors (LTO-5 specific)\n", b); break; case 0x3c: printf("%sDrive usage information (LTO-5 specific)\n", b); break; case 0x3d: printf("%sSubsystem statistics (LTO-5 specific)\n", b); break; /* case 0x3e: in LTO-6 this is Device Status page */ default: done = 0; break; } } break; case PDT_MCHANGER: /* medium changer type devices */ { switch (pg_code) { case 0x14: printf("%sMedia changer statistics (smc-3)\n", b); break; case 0x15: printf("%sElement statistics (smc-3)\n", b); break; case 0x16: printf("%sMedia changer diagnostic data (smc-3)\n", b); break; case 0x2e: printf("%sTapeAlert (smc-3)\n", b); break; default: done = 0; break; } } break; case PDT_ADC: /* Automation Device interface (ADC) */ { switch (pg_code) { case 0x11: printf("%sDT Device status (adc)\n", b); break; case 0x12: printf("%sTape alert response (adc)\n", b); break; case 0x13: printf("%sRequested recovery (adc)\n", b); break; case 0x14: printf("%sDevice statistics (adc)\n", b); break; case 0x15: printf("%sService buffers information (adc)\n", b); break; case 0x16: printf("%sTape diagnostic (adc)\n", b); break; default: done = 0; break; } } break; default: done = 0; break; } if (done) return; if (pg_code >= 0x30) printf("%s[unknown vendor specific page code]\n", b); else printf("%s??\n", b); } static void get_pcb_str(int pcb, char * outp, int maxoutlen) { char buff[PCB_STR_LEN]; int n; n = sprintf(buff, "du=%d [ds=%d] tsd=%d etc=%d ", ((pcb & 0x80) ? 1 : 0), ((pcb & 0x40) ? 1 : 0), ((pcb & 0x20) ? 1 : 0), ((pcb & 0x10) ? 1 : 0)); if (pcb & 0x10) n += sprintf(buff + n, "tmc=%d ", ((pcb & 0xc) >> 2)); #if 1 n += sprintf(buff + n, "format+linking=%d [0x%.2x]", pcb & 3, pcb); #else if (pcb & 0x1) n += sprintf(buff + n, "lbin=%d ", ((pcb & 0x2) >> 1)); n += sprintf(buff + n, "lp=%d [0x%.2x]", pcb & 0x1, pcb); #endif if (outp && (n < maxoutlen)) { memcpy(outp, buff, n); outp[n] = '\0'; } else if (outp && (maxoutlen > 0)) outp[0] = '\0'; } /* BUFF_OVER_UNDER_LPAGE [0x1] introduced: SPC-2 */ static void show_buffer_under_over_run_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pcb, pc; uint64_t count; unsigned char * ucp; const char * cp; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Buffer over-run/under-run page [0x1]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { cp = NULL; pl = ucp[3] + 4; count = (pl > 4) ? decode_count(ucp + 4, pl - 4) : 0; pc = (ucp[0] << 8) + ucp[1]; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0x0: cp = "under-run"; break; case 0x1: cp = "over-run"; break; case 0x2: cp = "transport under-run"; break; case 0x3: cp = "transport over-run"; break; case 0x4: cp = "transfer too slow, under-run"; break; case 0x5: cp = "transfer too slow, over-run"; break; case 0x20: cp = "command, under-run"; break; case 0x21: cp = "command, over-run"; break; case 0x22: cp = "command, transport under-run"; break; case 0x23: cp = "command, transport over-run"; break; case 0x24: cp = "command, transfer too slow, under-run"; break; case 0x25: cp = "command, transfer too slow, over-run"; break; case 0x40: cp = "I_T nexus, under-run"; break; case 0x41: cp = "I_T nexus, over-run"; break; case 0x42: cp = "I_T nexus, transport under-run"; break; case 0x43: cp = "I_T nexus, transport over-run"; break; case 0x44: cp = "I_T nexus, transfer too slow, under-run"; break; case 0x45: cp = "I_T nexus, transfer too slow, over-run"; break; case 0x80: cp = "time, under-run"; break; case 0x81: cp = "time, over-run"; break; case 0x82: cp = "time, transport under-run"; break; case 0x83: cp = "time, transport over-run"; break; case 0x84: cp = "time, transfer too slow, under-run"; break; case 0x85: cp = "time, transfer too slow, over-run"; break; default: printf(" undefined parameter code [0x%x], count = %" PRIu64 "", pc, count); break; } if (cp) printf(" %s = %" PRIu64 "", cp, count); if (op->do_pcb) { pcb = ucp[2]; get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* WRITE_ERR_LPAGE; READ_ERR_LPAGE; READ_REV_ERR_LPAGE; VERIFY_ERR_LPAGE */ /* [0x2, 0x3, 0x4, 0x5] introduced: SPC-3 */ static void show_error_counter_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb, pg_code; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; pg_code = resp[0] & 0x3f; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { switch(pg_code) { case WRITE_ERR_LPAGE: printf("Write error counter page [0x%x]\n", pg_code); break; case READ_ERR_LPAGE: printf("Read error counter page [0x%x]\n", pg_code); break; case READ_REV_ERR_LPAGE: printf("Read Reverse error counter page [0x%x]\n", pg_code); break; case VERIFY_ERR_LPAGE: printf("Verify error counter page [0x%x]\n", pg_code); break; default: pr2serr("expecting error counter page, got page = 0x%x\n", resp[0]); return; } } num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Errors corrected without substantial delay"); break; case 1: printf(" Errors corrected with possible delays"); break; case 2: printf(" Total rewrites or rereads"); break; case 3: printf(" Total errors corrected"); break; case 4: printf(" Total times correction algorithm processed"); break; case 5: printf(" Total bytes processed"); break; case 6: printf(" Total uncorrected errors"); break; case 0x8009: printf(" Track following errors [Hitachi]"); break; case 0x8015: printf(" Positioning errors [Hitachi]"); break; default: printf(" Reserved or vendor specific [0x%x]", pc); break; } printf(" = %" PRIu64 "", decode_count(ucp + 4, pl - 4)); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* NON_MEDIUM_LPAGE [0x6] introduced: SPC-2 */ static void show_non_medium_error_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Non-medium error page [0x6]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Non-medium error count"); break; default: if (pc <= 0x7fff) printf(" Reserved [0x%x]", pc); else printf(" Vendor specific [0x%x]", pc); break; } printf(" = %" PRIu64 "", decode_count(ucp + 4, pl - 4)); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* PCT_LPAGE [0x1a] introduced: SPC-4 */ static void show_power_condition_transitions_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Power condition transitions page [0x1a]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Accumulated transitions to active"); break; case 1: printf(" Accumulated transitions to idle_a"); break; case 2: printf(" Accumulated transitions to idle_b"); break; case 3: printf(" Accumulated transitions to idle_c"); break; case 8: printf(" Accumulated transitions to standby_z"); break; case 9: printf(" Accumulated transitions to standby_y"); break; default: printf(" Reserved [0x%x]", pc); } printf(" = %" PRIu64 "", decode_count(ucp + 4, pl - 4)); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* Tape usage: Vendor specific (LTO-5 and LTO-6): 0x30 */ static void show_tape_usage_log_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, extra, pc, pcb; unsigned int n; uint64_t ull; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed tape usage page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Tape usage page (LTO-5 and LTO-6 specific) [0x30]\n"); for (k = num; k > 0; k -= extra, ucp += extra) { pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; extra = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } ull = n = 0; switch (ucp[3]) { case 2: n = (ucp[4] << 8) | ucp[5]; break; case 4: n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; break; case 8: for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } break; } switch (pc) { case 0x01: if (extra == 8) printf(" Thread count: %u", n); break; case 0x02: if (extra == 12) printf(" Total data sets written: %" PRIu64, ull); break; case 0x03: if (extra == 8) printf(" Total write retries: %u", n); break; case 0x04: if (extra == 6) printf(" Total unrecovered write errors: %u", n); break; case 0x05: if (extra == 6) printf(" Total suspended writes: %u", n); break; case 0x06: if (extra == 6) printf(" Total fatal suspended writes: %u", n); break; case 0x07: if (extra == 12) printf(" Total data sets read: %" PRIu64, ull); break; case 0x08: if (extra == 8) printf(" Total read retries: %u", n); break; case 0x09: if (extra == 6) printf(" Total unrecovered read errors: %u", n); break; case 0x0a: if (extra == 6) printf(" Total suspended reads: %u", n); break; case 0x0b: if (extra == 6) printf(" Total fatal suspended reads: %u", n); break; default: printf(" unknown parameter code = 0x%x, contents in " "hex:\n", pc); dStrHex((const char *)ucp, extra, 1); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* Tape capacity: vendor specific (IBM): 0x31 */ static void show_tape_capacity_log_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, extra, pc, pcb; unsigned int n; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed tape capacity page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Tape capacity page (IBM specific) [0x31]\n"); for (k = num; k > 0; k -= extra, ucp += extra) { pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; extra = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } if (extra != 8) continue; n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; switch (pc) { case 0x01: printf(" Main partition remaining capacity (in MiB): %u", n); break; case 0x02: printf(" Alternate partition remaining capacity (in MiB): %u", n); break; case 0x03: printf(" Main partition maximum capacity (in MiB): %u", n); break; case 0x04: printf(" Alternate partition maximum capacity (in MiB): %u", n); break; default: printf(" unknown parameter code = 0x%x, contents in " "hex:\n", pc); dStrHex((const char *)ucp, extra, 1); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* Data compression: originally vendor specific 0x32 (IBM), then * ssc-4 standardizes it at 0x1b */ static void show_data_compression_log_page(unsigned char * resp, int len, const struct opts_t * op) { int k, j, pl, num, extra, pc, pcb, pg_code; uint64_t n; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; pg_code = resp[0] & 0x3f; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed data compression page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (0x1b == pg_code) printf("Data compression page (ssc-4) [0x1b]\n"); else printf("Data compression page (IBM specific) [0x%x]\n", pg_code); } for (k = num; k > 0; k -= extra, ucp += extra) { pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; pl = ucp[3]; extra = pl + 4; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } if ((0 == pl) || (pl > 8)) { printf("badly formed data compression log parameter\n"); printf(" parameter code = 0x%x, contents in hex:\n", pc); dStrHex((const char *)ucp, extra, 1); goto skip_para; } for (j = 0, n = 0; j < pl; ++j) { if (j > 0) n <<= 8; n |= ucp[4 + j]; } switch (pc) { case 0x00: printf(" Read compression ratio x100: %" PRIu64 , n); break; case 0x01: printf(" Write compression ratio x100: %" PRIu64 , n); break; case 0x02: printf(" Megabytes transferred to server: %" PRIu64 , n); break; case 0x03: printf(" Bytes transferred to server: %" PRIu64 , n); break; case 0x04: printf(" Megabytes read from tape: %" PRIu64 , n); break; case 0x05: printf(" Bytes read from tape: %" PRIu64 , n); break; case 0x06: printf(" Megabytes transferred from server: %" PRIu64 , n); break; case 0x07: printf(" Bytes transferred from server: %" PRIu64 , n); break; case 0x08: printf(" Megabytes written to tape: %" PRIu64 , n); break; case 0x09: printf(" Bytes written to tape: %" PRIu64 , n); break; case 0x100: printf(" Data compression enabled: 0x%" PRIx64, n); break; default: printf(" unknown parameter code = 0x%x, contents in " "hex:\n", pc); dStrHex((const char *)ucp, extra, 1); break; } skip_para: if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* LAST_N_ERR_LPAGE [0x7] introduced: SPC-2 */ static void show_last_n_error_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { printf("No error events logged\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Last n error events page [0x7]\n"); for (k = num; k > 0; k -= pl, ucp += pl) { if (k < 3) { printf("short Last n error events page\n"); return; } pl = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } printf(" Error event %d:\n", pc); if (pl > 4) { if ((pcb & 0x1) && (pcb & 0x2)) { printf(" [binary]:\n"); dStrHex((const char *)ucp + 4, pl - 4, 1); } else if (pcb & 0x1) printf(" %.*s\n", pl - 4, (const char *)(ucp + 4)); else { printf(" [data counter?? (LP bit should be set)]:\n"); dStrHex((const char *)ucp + 4, pl - 4, 1); } } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; } } /* LAST_N_DEFERRED_LPAGE [0xb] introduced: SPC-2 */ static void show_last_n_deferred_error_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { printf("No deferred errors logged\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Last n deferred errors page [0xb]\n"); for (k = num; k > 0; k -= pl, ucp += pl) { if (k < 3) { printf("short Last n deferred errors page\n"); return; } pl = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } printf(" Deferred error %d:\n", pc); dStrHex((const char *)ucp + 4, pl - 4, 1); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; } } static const char * self_test_code[] = { "default", "background short", "background extended", "reserved", "aborted background", "foreground short", "foreground extended", "reserved"}; static const char * self_test_result[] = { "completed without error", "aborted by SEND DIAGNOSTIC", "aborted other than by SEND DIAGNOSTIC", "unknown error, unable to complete", "self test completed with failure in test segment (which one unknown)", "first segment in self test failed", "second segment in self test failed", "another segment in self test failed", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "reserved", "self test in progress"}; /* SELF_TEST_LPAGE [0x10] introduced: SPC-3 */ static void show_self_test_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, n, res, pc, pl, pcb; unsigned int v; unsigned char * ucp; uint64_t ull; char pcb_str[PCB_STR_LEN]; char b[80]; num = len - 4; if (num < 0x190) { pr2serr("short self-test results page [length 0x%x rather than " "0x190 bytes]\n", num); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Self-test results page [0x10]\n"); for (k = 0, ucp = resp + 4; k < 20; ++k, ucp += 20 ) { pcb = ucp[2]; pl = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } n = (ucp[6] << 8) | ucp[7]; if ((0 == n) && (0 == ucp[4])) break; printf(" Parameter code = %d, accumulated power-on hours = %d\n", pc, n); printf(" self-test code: %s [%d]\n", self_test_code[(ucp[4] >> 5) & 0x7], (ucp[4] >> 5) & 0x7); res = ucp[4] & 0xf; printf(" self-test result: %s [%d]\n", self_test_result[res], res); if (ucp[5]) printf(" self-test number = %d\n", (int)ucp[5]); ull = ucp[8]; ull <<= 8; ull |= ucp[9]; ull <<= 8; ull |= ucp[10]; ull <<= 8; ull |= ucp[11]; ull <<= 8; ull |= ucp[12]; ull <<= 8; ull |= ucp[13]; ull <<= 8; ull |= ucp[14]; ull <<= 8; ull |= ucp[15]; if ((0xffffffffffffffffULL != ull) && (res > 0) && ( res < 0xf)) printf(" address of first error = 0x%" PRIx64 "\n", ull); v = ucp[16] & 0xf; if (v) { printf(" sense key = 0x%x [%s] , asc = 0x%x, ascq = 0x%x", v, sg_get_sense_key_str(v, sizeof(b), b), ucp[17], ucp[18]); if (ucp[17] || ucp[18]) printf(" [%s]\n", sg_get_asc_ascq_str(ucp[17], ucp[18], sizeof(b), b)); } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* TEMPERATURE_LPAGE [0xd] introduced: SPC-3 */ static void show_temperature_page(unsigned char * resp, int len, const struct opts_t * op, int show_extra) { int k, num, extra, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed Temperature page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (show_extra) printf("Temperature page [0xd]\n"); } for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) { pr2serr("short Temperature page\n"); return; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: if ((extra > 5) && (k > 5)) { if (ucp[5] < 0xff) printf(" Current temperature = %d C", ucp[5]); else printf(" Current temperature = "); } break; case 1: if ((extra > 5) && (k > 5)) { if (ucp[5] < 0xff) printf(" Reference temperature = %d C", ucp[5]); else printf(" Reference temperature = "); } break; default: if (show_extra) { printf(" unknown parameter code = 0x%x, contents in " "hex:\n", pc); dStrHex((const char *)ucp, extra, 1); } else continue; break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* START_STOP_LPAGE [0xe] introduced: SPC-3 */ static void show_start_stop_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, extra, pc, pcb; unsigned int n; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed Start-stop cycle counter page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Start-stop cycle counter page [0xe]\n"); for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) { pr2serr("short Start-stop cycle counter page\n"); return; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 1: if (10 == extra) printf(" Date of manufacture, year: %.4s, week: %.2s", &ucp[4], &ucp[8]); else if (op->do_verbose) { pr2serr(" Date of manufacture parameter length strange: " "%d\n", extra - 4); dStrHexErr((const char *)ucp, extra, 1); } break; case 2: if (10 == extra) printf(" Accounting date, year: %.4s, week: %.2s", &ucp[4], &ucp[8]); else if (op->do_verbose) { pr2serr(" Accounting date parameter length strange: %d\n", extra - 4); dStrHexErr((const char *)ucp, extra, 1); } break; case 3: if (extra > 7) { n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff == n) printf(" Specified cycle count over device lifetime " "= -1"); else printf(" Specified cycle count over device lifetime " "= %u", n); } break; case 4: if (extra > 7) { n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff == n) printf(" Accumulated start-stop cycles = -1"); else printf(" Accumulated start-stop cycles = %u", n); } break; case 5: if (extra > 7) { n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff == n) printf(" Specified load-unload count over device " "lifetime = -1"); else printf(" Specified load-unload count over device " "lifetime = %u", n); } break; case 6: if (extra > 7) { n = (ucp[4] << 24) | (ucp[5] << 16) | (ucp[6] << 8) | ucp[7]; if (0xffffffff == n) printf(" Accumulated load-unload cycles = -1"); else printf(" Accumulated load-unload cycles = %u", n); } break; default: printf(" unknown parameter code = 0x%x, contents in " "hex:\n", pc); dStrHex((const char *)ucp, extra, 1); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* APP_CLIENT_LPAGE [0xf] introduced: SPC-3 */ static void show_app_client_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, extra, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed Application Client page\n"); return; } if (op->do_verbose || ((op->do_raw == 0) && (op->do_hex == 0))) printf("Application client page [0xf]\n"); if (0 == op->filter_given) { if ((len > 128) && (0 == op->do_hex)) { dStrHex((const char *)resp, 64, 1); printf(" ..... [truncated after 64 of %d bytes (use '-H' to " "see the rest)]\n", len); } else dStrHex((const char *)resp, len, 1); return; } /* only here if filter_given set */ for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) { pr2serr("short Application client page\n"); return; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter != pc) continue; if (op->do_raw) dStrRaw((const char *)ucp, extra); else if (0 == op->do_hex) dStrHex((const char *)ucp, extra, 0); else if (1 == op->do_hex) dStrHex((const char *)ucp, extra, 1); else dStrHex((const char *)ucp, extra, -1); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); break; } } /* IE_LPAGE [0x2f] introduced: SPC-3 */ static void show_ie_page(unsigned char * resp, int len, const struct opts_t * op, int full) { int k, num, extra, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; char b[256]; num = len - 4; ucp = &resp[0] + 4; if (num < 4) { pr2serr("badly formed Informational Exceptions page\n"); return; } if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (full) printf("Informational Exceptions page [0x2f]\n"); } for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) { printf("short Informational Exceptions page\n"); return; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: if (extra > 5) { if (full) { printf(" IE asc = 0x%x, ascq = 0x%x", ucp[4], ucp[5]); if (ucp[4] || ucp[5]) if(sg_get_asc_ascq_str(ucp[4], ucp[5], sizeof(b), b)) printf("\n [%s]", b); } if (extra > 6) { if (ucp[6] < 0xff) printf("\n Current temperature = %d C", ucp[6]); else printf("\n Current temperature = "); if (extra > 7) { if (ucp[7] < 0xff) printf("\n Threshold temperature = %d C [IBM " "extension]", ucp[7]); else printf("\n Threshold temperature = "); } } } break; default: if (full) { printf(" parameter code = 0x%x, contents in hex:\n", pc); dStrHex((const char *)ucp, extra, 1); } break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; } } /* from sas2r15 */ static void show_sas_phy_event_info(int pes, unsigned int val, unsigned int thresh_val) { unsigned int u; switch (pes) { case 0: printf(" No event\n"); break; case 0x1: printf(" Invalid word count: %u\n", val); break; case 0x2: printf(" Running disparity error count: %u\n", val); break; case 0x3: printf(" Loss of dword synchronization count: %u\n", val); break; case 0x4: printf(" Phy reset problem count: %u\n", val); break; case 0x5: printf(" Elasticity buffer overflow count: %u\n", val); break; case 0x6: printf(" Received ERROR count: %u\n", val); break; case 0x20: printf(" Received address frame error count: %u\n", val); break; case 0x21: printf(" Transmitted abandon-class OPEN_REJECT count: %u\n", val); break; case 0x22: printf(" Received abandon-class OPEN_REJECT count: %u\n", val); break; case 0x23: printf(" Transmitted retry-class OPEN_REJECT count: %u\n", val); break; case 0x24: printf(" Received retry-class OPEN_REJECT count: %u\n", val); break; case 0x25: printf(" Received AIP (WATING ON PARTIAL) count: %u\n", val); break; case 0x26: printf(" Received AIP (WAITING ON CONNECTION) count: %u\n", val); break; case 0x27: printf(" Transmitted BREAK count: %u\n", val); break; case 0x28: printf(" Received BREAK count: %u\n", val); break; case 0x29: printf(" Break timeout count: %u\n", val); break; case 0x2a: printf(" Connection count: %u\n", val); break; case 0x2b: printf(" Peak transmitted pathway blocked count: %u\n", val & 0xff); printf(" Peak value detector threshold: %u\n", thresh_val & 0xff); break; case 0x2c: u = val & 0xffff; if (u < 0x8000) printf(" Peak transmitted arbitration wait time (us): " "%u\n", u); else printf(" Peak transmitted arbitration wait time (ms): " "%u\n", 33 + (u - 0x8000)); u = thresh_val & 0xffff; if (u < 0x8000) printf(" Peak value detector threshold (us): %u\n", u); else printf(" Peak value detector threshold (ms): %u\n", 33 + (u - 0x8000)); break; case 0x2d: printf(" Peak arbitration time (us): %u\n", val); printf(" Peak value detector threshold: %u\n", thresh_val); break; case 0x2e: printf(" Peak connection time (us): %u\n", val); printf(" Peak value detector threshold: %u\n", thresh_val); break; case 0x40: printf(" Transmitted SSP frame count: %u\n", val); break; case 0x41: printf(" Received SSP frame count: %u\n", val); break; case 0x42: printf(" Transmitted SSP frame error count: %u\n", val); break; case 0x43: printf(" Received SSP frame error count: %u\n", val); break; case 0x44: printf(" Transmitted CREDIT_BLOCKED count: %u\n", val); break; case 0x45: printf(" Received CREDIT_BLOCKED count: %u\n", val); break; case 0x50: printf(" Transmitted SATA frame count: %u\n", val); break; case 0x51: printf(" Received SATA frame count: %u\n", val); break; case 0x52: printf(" SATA flow control buffer overflow count: %u\n", val); break; case 0x60: printf(" Transmitted SMP frame count: %u\n", val); break; case 0x61: printf(" Received SMP frame count: %u\n", val); break; case 0x63: printf(" Received SMP frame error count: %u\n", val); break; default: printf(" Unknown phy event source: %d, val=%u, thresh_val=%u\n", pes, val, thresh_val); break; } } /* PROTO_SPECIFIC_LPAGE [0x18] for a SAS port */ static void show_sas_port_param(unsigned char * ucp, int param_len, const struct opts_t * op) { int j, m, n, nphys, pcb, t, sz, spld_len; unsigned char * vcp; uint64_t ull; unsigned int ui; char pcb_str[PCB_STR_LEN]; char s[64]; sz = sizeof(s); pcb = ucp[2]; t = (ucp[0] << 8) | ucp[1]; if (op->do_name) printf("rel_target_port=%d\n", t); else printf("relative target port id = %d\n", t); if (op->do_name) printf(" gen_code=%d\n", ucp[6]); else printf(" generation code = %d\n", ucp[6]); nphys = ucp[7]; if (op->do_name) printf(" num_phys=%d\n", nphys); else { printf(" number of phys = %d", nphys); if ((op->do_pcb) && (0 == op->do_name)) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); } for (j = 0, vcp = ucp + 8; j < (param_len - 8); vcp += spld_len, j += spld_len) { if (op->do_name) printf(" phy_id=%d\n", vcp[1]); else printf(" phy identifier = %d\n", vcp[1]); spld_len = vcp[3]; if (spld_len < 44) spld_len = 48; /* in SAS-1 and SAS-1.1 vcp[3]==0 */ else spld_len += 4; if (op->do_name) { t = ((0x70 & vcp[4]) >> 4); printf(" att_dev_type=%d\n", t); printf(" att_iport_mask=0x%x\n", vcp[6]); printf(" att_phy_id=%d\n", vcp[24]); printf(" att_reason=0x%x\n", (vcp[4] & 0xf)); for (n = 0, ull = vcp[16]; n < 8; ++n) { ull <<= 8; ull |= vcp[16 + n]; } printf(" att_sas_addr=0x%" PRIx64 "\n", ull); printf(" att_tport_mask=0x%x\n", vcp[7]); ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; printf(" inv_dwords=%u\n", ui); ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43]; printf(" loss_dword_sync=%u\n", ui); printf(" neg_log_lrate=%d\n", 0xf & vcp[5]); ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; printf(" phy_reset_probs=%u\n", ui); ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; printf(" running_disparity=%u\n", ui); printf(" reason=0x%x\n", (vcp[5] & 0xf0) >> 4); for (n = 0, ull = vcp[8]; n < 8; ++n) { ull <<= 8; ull |= vcp[8 + n]; } printf(" sas_addr=0x%" PRIx64 "\n", ull); } else { t = ((0x70 & vcp[4]) >> 4); /* attached SAS device type. In SAS-1.1 case 2 was an edge * expander; in SAS-2 case 3 is marked as obsolete. */ switch (t) { case 0: snprintf(s, sz, "no device attached"); break; case 1: snprintf(s, sz, "SAS or SATA device"); break; case 2: snprintf(s, sz, "expander device"); break; case 3: snprintf(s, sz, "expander device (fanout)"); break; default: snprintf(s, sz, "reserved [%d]", t); break; } /* the word 'SAS' in following added in spl4r01 */ printf(" attached SAS device type: %s\n", s); t = 0xf & vcp[4]; switch (t) { case 0: snprintf(s, sz, "unknown"); break; case 1: snprintf(s, sz, "power on"); break; case 2: snprintf(s, sz, "hard reset"); break; case 3: snprintf(s, sz, "SMP phy control function"); break; case 4: snprintf(s, sz, "loss of dword synchronization"); break; case 5: snprintf(s, sz, "mux mix up"); break; case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); break; case 7: snprintf(s, sz, "break timeout timer expired"); break; case 8: snprintf(s, sz, "phy test function stopped"); break; case 9: snprintf(s, sz, "expander device reduced functionality"); break; default: snprintf(s, sz, "reserved [0x%x]", t); break; } printf(" attached reason: %s\n", s); t = (vcp[5] & 0xf0) >> 4; switch (t) { case 0: snprintf(s, sz, "unknown"); break; case 1: snprintf(s, sz, "power on"); break; case 2: snprintf(s, sz, "hard reset"); break; case 3: snprintf(s, sz, "SMP phy control function"); break; case 4: snprintf(s, sz, "loss of dword synchronization"); break; case 5: snprintf(s, sz, "mux mix up"); break; case 6: snprintf(s, sz, "I_T nexus loss timeout for STP/SATA"); break; case 7: snprintf(s, sz, "break timeout timer expired"); break; case 8: snprintf(s, sz, "phy test function stopped"); break; case 9: snprintf(s, sz, "expander device reduced functionality"); break; default: snprintf(s, sz, "reserved [0x%x]", t); break; } printf(" reason: %s\n", s); t = (0xf & vcp[5]); switch (t) { case 0: snprintf(s, sz, "phy enabled; unknown reason"); break; case 1: snprintf(s, sz, "phy disabled"); break; case 2: snprintf(s, sz, "phy enabled; speed negotiation failed"); break; case 3: snprintf(s, sz, "phy enabled; SATA spinup hold state"); break; case 4: snprintf(s, sz, "phy enabled; port selector"); break; case 5: snprintf(s, sz, "phy enabled; reset in progress"); break; case 6: snprintf(s, sz, "phy enabled; unsupported phy attached"); break; case 8: snprintf(s, sz, "1.5 Gbps"); break; case 9: snprintf(s, sz, "3 Gbps"); break; case 0xa: snprintf(s, sz, "6 Gbps"); break; case 0xb: snprintf(s, sz, "12 Gbps"); break; default: snprintf(s, sz, "reserved [%d]", t); break; } printf(" negotiated logical link rate: %s\n", s); printf(" attached initiator port: ssp=%d stp=%d smp=%d\n", !! (vcp[6] & 8), !! (vcp[6] & 4), !! (vcp[6] & 2)); printf(" attached target port: ssp=%d stp=%d smp=%d\n", !! (vcp[7] & 8), !! (vcp[7] & 4), !! (vcp[7] & 2)); for (n = 0, ull = vcp[8]; n < 8; ++n) { ull <<= 8; ull |= vcp[8 + n]; } printf(" SAS address = 0x%" PRIx64 "\n", ull); for (n = 0, ull = vcp[16]; n < 8; ++n) { ull <<= 8; ull |= vcp[16 + n]; } printf(" attached SAS address = 0x%" PRIx64 "\n", ull); printf(" attached phy identifier = %d\n", vcp[24]); ui = (vcp[32] << 24) | (vcp[33] << 16) | (vcp[34] << 8) | vcp[35]; printf(" Invalid DWORD count = %u\n", ui); ui = (vcp[36] << 24) | (vcp[37] << 16) | (vcp[38] << 8) | vcp[39]; printf(" Running disparity error count = %u\n", ui); ui = (vcp[40] << 24) | (vcp[41] << 16) | (vcp[42] << 8) | vcp[43]; printf(" Loss of DWORD synchronization = %u\n", ui); ui = (vcp[44] << 24) | (vcp[45] << 16) | (vcp[46] << 8) | vcp[47]; printf(" Phy reset problem = %u\n", ui); } if (spld_len > 51) { int num_ped, pes; unsigned char * xcp; unsigned int pvdt; num_ped = vcp[51]; if (op->do_verbose > 1) printf(" <>\n", num_ped, spld_len, (spld_len - 52) / 12); if (num_ped > 0) { if (op->do_name) { printf(" phy_event_desc_num=%d\n", num_ped); return; /* don't decode at this stage */ } else printf(" Phy event descriptors:\n"); } xcp = vcp + 52; for (m = 0; m < (num_ped * 12); m += 12, xcp += 12) { pes = xcp[3]; ui = (xcp[4] << 24) | (xcp[5] << 16) | (xcp[6] << 8) | xcp[7]; pvdt = (xcp[8] << 24) | (xcp[9] << 16) | (xcp[10] << 8) | xcp[11]; show_sas_phy_event_info(pes, ui, pvdt); } } else if (op->do_verbose) printf(" <>\n"); } } /* PROTO_SPECIFIC_LPAGE [0x18] */ static int show_protocol_specific_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, pl, pc, pid; unsigned char * ucp; num = len - 4; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (op->do_name) printf("log_page=0x%x\n", PROTO_SPECIFIC_LPAGE); } for (k = 0, ucp = resp + 4; k < num; ) { pc = (ucp[0] << 8) + ucp[1]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } pid = 0xf & ucp[4]; if (6 != pid) { pr2serr("Protocol identifier: %d, only support SAS (SPL) which " "is 6\n", pid); return 0; /* only decode SAS log page */ } if ((0 == k) && (0 == op->do_name)) printf("Protocol Specific port page for SAS SSP (sas-2) " "[0x18]\n"); show_sas_port_param(ucp, pl, op); if (op->filter_given) break; skip: k += pl; ucp += pl; } return 1; } /* Returns 1 if processed page, 0 otherwise */ /* STATS_LPAGE [0x19], subpages: 0x0 to 0x1f introduced: SPC-4 */ static int show_stats_perform_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, n, param_len, param_code, spf, subpg_code, extra; int pcb, nam; unsigned char * ucp; const char * ccp; uint64_t ull; char pcb_str[PCB_STR_LEN]; nam = op->do_name; num = len - 4; ucp = resp + 4; spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : 0; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (nam) { printf("log_page=0x%x\n", STATS_LPAGE); if (subpg_code > 0) printf("log_subpage=0x%x\n", subpg_code); } else { if (0 == subpg_code) printf("General Statistics and Performance [0x19]\n"); else printf("Group Statistics and Performance (%d) " "[0x19,0x%x]\n", subpg_code, subpg_code); } } if (subpg_code > 31) return 0; if (0 == subpg_code) { /* General statistics and performance log page */ if (num < 0x5c) return 0; for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) return 0; param_len = ucp[3]; extra = param_len + 4; param_code = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (param_code != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (param_code) { case 1: /* Statistics and performance log parameter */ ccp = nam ? "parameter_code=1" : "Statistics and performance " "log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "read_commands=" : "number of read commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[12]; n < 8; ++n) { ull <<= 8; ull |= ucp[12 + n]; } ccp = nam ? "write_commands=" : "number of write commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[20]; n < 8; ++n) { ull <<= 8; ull |= ucp[20 + n]; } ccp = nam ? "lb_received=" : "number of logical blocks received = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[28]; n < 8; ++n) { ull <<= 8; ull |= ucp[28 + n]; } ccp = nam ? "lb_transmitted=" : "number of logical blocks transmitted = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[36]; n < 8; ++n) { ull <<= 8; ull |= ucp[36 + n]; } ccp = nam ? "read_proc_intervals=" : "read command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[44]; n < 8; ++n) { ull <<= 8; ull |= ucp[44 + n]; } ccp = nam ? "write_proc_intervals=" : "write command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[52]; n < 8; ++n) { ull <<= 8; ull |= ucp[52 + n]; } ccp = nam ? "weight_rw_commands=" : "weighted number of " "read commands plus write commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[60]; n < 8; ++n) { ull <<= 8; ull |= ucp[60 + n]; } ccp = nam ? "weight_rw_processing=" : "weighted read command " "processing plus write command processing = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 2: /* Idle time log parameter */ ccp = nam ? "parameter_code=2" : "Idle time log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "idle_time_intervals=" : "idle time " "intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 3: /* Time interval log parameter for general stats */ ccp = nam ? "parameter_code=3" : "Time interval log " "parameter for general stats"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 4; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "time_interval_neg_exp=" : "time interval " "negative exponent = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[8]; n < 4; ++n) { ull <<= 8; ull |= ucp[8 + n]; } ccp = nam ? "time_interval_int=" : "time interval " "integer = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 4: /* FUA statistics and performance log parameter */ ccp = nam ? "parameter_code=4" : "Force unit access " "statistics and performance log parameter "; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "read_fua_commands=" : "number of read FUA " "commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[12]; n < 8; ++n) { ull <<= 8; ull |= ucp[12 + n]; } ccp = nam ? "write_fua_commands=" : "number of write FUA " "commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[20]; n < 8; ++n) { ull <<= 8; ull |= ucp[20 + n]; } ccp = nam ? "read_fua_nv_commands=" : "number of read FUA_NV commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[28]; n < 8; ++n) { ull <<= 8; ull |= ucp[28 + n]; } ccp = nam ? "write_fua_nv_commands=" : "number of write FUA_NV commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[36]; n < 8; ++n) { ull <<= 8; ull |= ucp[36 + n]; } ccp = nam ? "read_fua_proc_intervals=" : "read FUA command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[44]; n < 8; ++n) { ull <<= 8; ull |= ucp[44 + n]; } ccp = nam ? "write_fua_proc_intervals=" : "write FUA command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[52]; n < 8; ++n) { ull <<= 8; ull |= ucp[52 + n]; } ccp = nam ? "read_fua_nv_proc_intervals=" : "read FUA_NV command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[60]; n < 8; ++n) { ull <<= 8; ull |= ucp[60 + n]; } ccp = nam ? "write_fua_nv_proc_intervals=" : "write FUA_NV command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 6: /* Time interval log parameter for cache stats */ ccp = nam ? "parameter_code=6" : "Time interval log " "parameter for cache stats"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 4; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "time_interval_neg_exp=" : "time interval " "negative exponent = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[8]; n < 4; ++n) { ull <<= 8; ull |= ucp[8 + n]; } ccp = nam ? "time_interval_int=" : "time interval " "integer = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; default: if (nam) { printf("parameter_code=%d\n", param_code); printf(" unknown=1\n"); } else pr2serr("show_performance... unknown parameter code " "%d\n", param_code); if (op->do_verbose) dStrHexErr((const char *)ucp, extra, 1); break; } if ((op->do_pcb) && (0 == op->do_name)) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; } } else { /* Group statistics and performance (n) log page */ if (num < 0x34) return 0; for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) return 0; param_len = ucp[3]; extra = param_len + 4; param_code = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (param_code != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (param_code) { case 1: /* Group n Statistics and performance log parameter */ if (nam) printf("parameter_code=1\n"); else printf("Group %d Statistics and performance log " "parameter\n", subpg_code); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "gn_read_commands=" : "group n number of read " "commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[12]; n < 8; ++n) { ull <<= 8; ull |= ucp[12 + n]; } ccp = nam ? "gn_write_commands=" : "group n number of write " "commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[20]; n < 8; ++n) { ull <<= 8; ull |= ucp[20 + n]; } ccp = nam ? "gn_lb_received=" : "group n number of logical blocks received = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[28]; n < 8; ++n) { ull <<= 8; ull |= ucp[28 + n]; } ccp = nam ? "gn_lb_transmitted=" : "group n number of logical blocks transmitted = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[36]; n < 8; ++n) { ull <<= 8; ull |= ucp[36 + n]; } ccp = nam ? "gn_read_proc_intervals=" : "group n read command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[44]; n < 8; ++n) { ull <<= 8; ull |= ucp[44 + n]; } ccp = nam ? "gn_write_proc_intervals=" : "group n write command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 4: /* Group n FUA statistics and performance log parameter */ ccp = nam ? "parameter_code=4" : "Group n force unit access " "statistics and performance log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "gn_read_fua_commands=" : "group n number of read FUA commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[12]; n < 8; ++n) { ull <<= 8; ull |= ucp[12 + n]; } ccp = nam ? "gn_write_fua_commands=" : "group n number of write FUA commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[20]; n < 8; ++n) { ull <<= 8; ull |= ucp[20 + n]; } ccp = nam ? "gn_read_fua_nv_commands=" : "group n number of read FUA_NV commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[28]; n < 8; ++n) { ull <<= 8; ull |= ucp[28 + n]; } ccp = nam ? "gn_write_fua_nv_commands=" : "group n number of write FUA_NV commands = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[36]; n < 8; ++n) { ull <<= 8; ull |= ucp[36 + n]; } ccp = nam ? "gn_read_fua_proc_intervals=" : "group n read FUA command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[44]; n < 8; ++n) { ull <<= 8; ull |= ucp[44 + n]; } ccp = nam ? "gn_write_fua_proc_intervals=" : "group n write " "FUA command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[52]; n < 8; ++n) { ull <<= 8; ull |= ucp[52 + n]; } ccp = nam ? "gn_read_fua_nv_proc_intervals=" : "group n " "read FUA_NV command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[60]; n < 8; ++n) { ull <<= 8; ull |= ucp[60 + n]; } ccp = nam ? "gn_write_fua_nv_proc_intervals=" : "group n " "write FUA_NV command processing intervals = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; default: if (nam) { printf("parameter_code=%d\n", param_code); printf(" unknown=1\n"); } else pr2serr("show_performance... unknown parameter code " "%d\n", param_code); if (op->do_verbose) dStrHexErr((const char *)ucp, extra, 1); break; } if ((op->do_pcb) && (0 == op->do_name)) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; } } return 1; } /* Returns 1 if processed page, 0 otherwise */ /* STATS_LPAGE [0x19], CACHE_STATS_SUBPG [0x20] introduced: SPC-4 */ static int show_cache_stats_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, n, pc, spf, subpg_code, extra; int pcb, nam; unsigned char * ucp; const char * ccp; uint64_t ull; char pcb_str[PCB_STR_LEN]; nam = op->do_name; num = len - 4; ucp = resp + 4; if (num < 4) { pr2serr("badly formed Cache memory statistics page\n"); return 0; } spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : 0; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (nam) { printf("log_page=0x%x\n", STATS_LPAGE); if (subpg_code > 0) printf("log_subpage=0x%x\n", subpg_code); } else printf("Cache memory statistics page [0x19,0x20]\n"); } for (k = num; k > 0; k -= extra, ucp += extra) { if (k < 3) { pr2serr("short Cache memory statistics page\n"); return 0; } if (8 != ucp[3]) { printf("Cache memory statistics page parameter length not " "8\n"); return 0; } extra = ucp[3] + 4; pc = (ucp[0] << 8) + ucp[1]; pcb = ucp[2]; if (op->filter_given) { if (pc != op->filter) continue; if (op->do_raw) { dStrRaw((const char *)ucp, extra); break; } else if (op->do_hex) { dStrHex((const char *)ucp, extra, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 1: /* Read cache memory hits log parameter */ ccp = nam ? "parameter_code=1" : "Read cache memory hits log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "read_cache_memory_hits=" : "read cache memory hits = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 2: /* Reads to cache memory log parameter */ ccp = nam ? "parameter_code=2" : "Reads to cache memory log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "reads_to_cache_memory=" : "reads to cache memory = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 3: /* Write cache memory hits log parameter */ ccp = nam ? "parameter_code=3" : "Write cache memory hits log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "write_cache_memory_hits=" : "write cache memory hits = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 4: /* Writes from cache memory log parameter */ ccp = nam ? "parameter_code=4" : "Writes from cache memory log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "writes_from_cache_memory=" : "writes from cache memory = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 5: /* Time from last hard reset log parameter */ ccp = nam ? "parameter_code=5" : "Time from last hard reset log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 8; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "time_from_last_hard_reset=" : "time from last hard reset = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; case 6: /* Time interval log parameter for cache stats */ ccp = nam ? "parameter_code=6" : "Time interval log parameter"; printf("%s\n", ccp); for (n = 0, ull = ucp[4]; n < 4; ++n) { ull <<= 8; ull |= ucp[4 + n]; } ccp = nam ? "time_interval_neg_exp=" : "time interval " "negative exponent = "; printf(" %s%" PRIu64 "\n", ccp, ull); for (n = 0, ull = ucp[8]; n < 4; ++n) { ull <<= 8; ull |= ucp[8 + n]; } ccp = nam ? "time_interval_int=" : "time interval " "integer = "; printf(" %s%" PRIu64 "\n", ccp, ull); break; default: if (nam) { printf("parameter_code=%d\n", pc); printf(" unknown=1\n"); } else pr2serr("show_performance... unknown parameter code %d\n", pc); if (op->do_verbose) dStrHexErr((const char *)ucp, extra, 1); break; } if ((op->do_pcb) && (0 == op->do_name)) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; } return 1; } /* FORMAT_STATUS_LPAGE [0x8] introduced: SBC-2 */ static void show_format_status_page(unsigned char * resp, int len, const struct opts_t * op) { int k, j, num, pl, pc, pcb, all_ff, counter; unsigned char * ucp; unsigned char * xp; uint64_t ull; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Format status page [0x8]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } counter = 1; switch (pc) { case 0: printf(" Format data out:\n"); counter = 0; dStrHex((const char *)ucp, pl, 0); break; case 1: printf(" Grown defects during certification"); break; case 2: printf(" Total blocks reassigned during format"); break; case 3: printf(" Total new blocks reassigned"); break; case 4: printf(" Power on minutes since format"); break; default: printf(" Unknown Format status code = 0x%x\n", pc); counter = 0; dStrHex((const char *)ucp, pl, 0); break; } if (counter) { k = pl - 4; xp = ucp + 4; if (k > (int)sizeof(ull)) { xp += (k - sizeof(ull)); k = sizeof(ull); } ull = 0; for (all_ff = 0, j = 0; j < k; ++j) { if (j > 0) ull <<= 8; else all_ff = 1; ull |= xp[j]; if (0xff != xp[j]) all_ff = 0; } if (all_ff) printf(" "); else printf(" = %" PRIu64 "", ull); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); } else { if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* Non-volatile cache page [0x17] introduced: SBC-2 */ static void show_non_volatile_cache_page(unsigned char * resp, int len, const struct opts_t * op) { int j, num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Non-volatile cache page [0x17]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Remaining non-volatile time: "); if (3 == ucp[4]) { j = (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; switch (j) { case 0: printf("0 (i.e. it is now volatile)\n"); break; case 1: printf("\n"); break; case 0xffffff: printf("\n"); break; default: printf("%d minutes [%d:%d]\n", j, (j / 60), (j % 60)); break; } } else printf("\n", ucp[4]); break; case 1: printf(" Maximum non-volatile time: "); if (3 == ucp[4]) { j = (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; switch (j) { case 0: printf("0 (i.e. it is now volatile)\n"); break; case 1: printf("\n"); break; case 0xffffff: printf("\n"); break; default: printf("%d minutes [%d:%d]\n", j, (j / 60), (j % 60)); break; } } else printf("\n", ucp[4]); break; default: printf(" Unknown Format status code = 0x%x\n", pc); dStrHex((const char *)ucp, pl, 0); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* LB_PROV_LPAGE [0xc] introduced: SBC-3 */ static void show_lb_provisioning_page(unsigned char * resp, int len, const struct opts_t * op) { int j, num, pl, pc, pcb; unsigned char * ucp; const char * cp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Logical block provisioning page [0xc]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0x1: cp = " Available LBA mapping threshold"; break; case 0x2: cp = " Used LBA mapping threshold"; break; case 0x100: cp = " De-duplicated LBA"; break; case 0x101: cp = " Compressed LBA"; break; case 0x102: cp = " Total efficiency LBA"; break; default: cp = NULL; break; } if (cp) { printf(" %s resource count:", cp); if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("\n truncated by response length, expected at " "least 8 bytes\n"); else pr2serr("\n parameter length >= 8 expected, got %d\n", pl); break; } j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf(" %d\n", j); if (pl > 8) { switch (ucp[8] & 0x3) { case 0: cp = "not reported"; break; case 1: cp = "dedicated to lu"; break; case 2: cp = "not dedicated to lu"; break; case 3: cp = "reserved"; break; } printf(" Scope: %s\n", cp); } } else if ((pc >= 0xfff0) && (pc <= 0xffff)) { printf(" Vendor specific [0x%x]:", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); } else { printf(" Reserved [parameter_code=0x%x]:\n", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* SOLID_STATE_MEDIA_LPAGE [0x11] introduced: SBC-3 */ static void show_solid_state_media_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Solid state media page [0x11]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0x1: printf(" Percentage used endurance indicator:"); if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr("\n truncated by response length, expected " "at least 8 bytes\n"); else pr2serr("\n parameter length >= 8 expected, got %d\n", pl); break; } printf(" %d%%\n", ucp[7]); break; default: printf(" Reserved [parameter_code=0x%x]:\n", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); break; } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } static const char * dt_dev_activity[] = { "No DT device activity", "Cleaning operation in progress", "Volume is being loaded", "Volume is being unloaded", "Other medium activity", "Reading from medium", "Writing to medium", "Locating medium", "Rewinding medium", /* 8 */ "Erasing volume", "Formatting volume", "Calibrating", "Other DT device activity", "Microcode update in progress", "Reading encrypted from medium", "Writing encrypted to medium", "Diagnostic operation in progress", /* 10 */ }; /* DT device status [0x11] (ssc, adc) */ static void show_dt_device_status_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb, j; unsigned char * ucp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("DT device status page (ssc-3, adc-3) [0x11]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0x0: printf(" Very high frequency data:\n"); if ((pl < 8) || (num < 8)) { if (num < 8) pr2serr(" truncated by response length, expected at " "least 8 bytes\n"); else pr2serr(" parameter length >= 8 expected, got %d\n", pl); break; } printf(" PAMR=%d HUI=%d MACC=%d CMPR=%d ", !!(0x80 & ucp[4]), !!(0x40 & ucp[4]), !!(0x20 & ucp[4]), !!(0x10 & ucp[4])); printf("WRTP=%d CRQST=%d CRQRD=%d DINIT=%d\n", !!(0x8 & ucp[4]), !!(0x4 & ucp[4]), !!(0x2 & ucp[4]), !!(0x1 & ucp[4])); printf(" INXTN=%d RAA=%d MPRSNT=%d ", !!(0x80 & ucp[5]), !!(0x20 & ucp[5]), !!(0x10 & ucp[5])); printf("MSTD=%d MTHRD=%d MOUNTED=%d\n", !!(0x4 & ucp[5]), !!(0x2 & ucp[5]), !!(0x1 & ucp[5])); printf(" DT device activity: "); j = ucp[6]; if (j < (int)(sizeof(dt_dev_activity) / sizeof(dt_dev_activity[0]))) printf("%s\n", dt_dev_activity[j]); else if (j < 0x80) printf("Reserved [0x%x]\n", j); else printf("Vendor specific [0x%x]\n", j); printf(" VS=%d TDDEC=%d EPP=%d ", !!(0x80 & ucp[7]), !!(0x20 & ucp[7]), !!(0x10 & ucp[7])); printf("ESR=%d RRQST=%d INTFC=%d TAFC=%d\n", !!(0x8 & ucp[7]), !!(0x4 & ucp[7]), !!(0x2 & ucp[7]), !!(0x1 & ucp[7])); break; case 0x1: printf(" Very high frequency polling delay: "); if ((pl < 6) || (num < 6)) { if (num < 6) pr2serr("\n truncated by response length, expected at " "least 6 bytes\n"); else pr2serr("\n parameter length >= 6 expected, got %d\n", pl); break; } printf(" %d milliseconds\n", (ucp[4] << 8) + ucp[5]); break; case 0x2: printf(" DT device ADC data encryption control status (hex " "only now):\n"); if ((pl < 12) || (num < 12)) { if (num < 12) pr2serr(" truncated by response length, expected at " "least 12 bytes\n"); else pr2serr(" parameter length >= 12 expected, got %d\n", pl); break; } dStrHex((const char *)ucp + 4, 8, 1); break; case 0x3: printf(" Key management error data (hex only now):\n"); if ((pl < 16) || (num < 16)) { if (num < 16) pr2serr(" truncated by response length, expected at " "least 16 bytes\n"); else pr2serr(" parameter length >= 16 expected, got %d\n", pl); break; } dStrHex((const char *)ucp + 4, 12, 1); break; default: printf(" Reserved [parameter_code=0x%x]:\n", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); break; } // xxxxxxxxxxxxxxx if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* SAT_ATA_RESULTS_LPAGE (SAT-2) [0x16] */ static void show_ata_pt_results_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; unsigned char * dp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("ATA pass-through results page (sat-2) [0x16]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } if ((pc < 0xf) && (pl > 17)) { int extend, sector_count; dp = ucp + 4; printf(" Log_index=0x%x (parameter_code=0x%x)\n", pc + 1, pc); extend = dp[2] & 1; sector_count = dp[5] + (extend ? (dp[4] << 8) : 0); printf(" extend=%d error=0x%x sector_count=0x%x\n", extend, dp[3], sector_count); if (extend) printf(" lba=0x%02x%02x%02x%02x%02x%02x\n", dp[10], dp[8], dp[6], dp[11], dp[9], dp[7]); else printf(" lba=0x%02x%02x%02x\n", dp[11], dp[9], dp[7]); printf(" device=0x%x status=0x%x\n", dp[12], dp[13]); } else { printf(" Reserved [parameter_code=0x%x]:\n", pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } static const char * bms_status[] = { "no background scans active", "background medium scan is active", "background pre-scan is active", "background scan halted due to fatal error", "background scan halted due to a vendor specific pattern of error", "background scan halted due to medium formatted without P-List", "background scan halted - vendor specific cause", "background scan halted due to temperature out of range", "background scan enabled, none active (waiting for BMS interval timer " "to expire)", /* 8 */ "background scan halted - scan results list full", "background scan halted - pre-scan time limit timer expired" /* 10 */, }; static const char * reassign_status[] = { "Reassign status: Reserved [0x0]", "Reassignment pending receipt of Reassign or Write command", "Logical block successfully reassigned by device server", "Reassign status: Reserved [0x3]", "Reassignment by device server failed", "Logical block recovered by device server via rewrite", "Logical block reassigned by application client, has valid data", "Logical block reassigned by application client, contains no valid data", "Logical block unsuccessfully reassigned by application client", /* 8 */ }; /* Background scan results [0x15,0] for disk introduced: SBC-3 */ static void show_background_scan_results_page(unsigned char * resp, int len, const struct opts_t * op) { int j, m, num, pl, pc, pcb; unsigned char * ucp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Background scan results page [0x15]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Status parameters:\n"); if ((pl < 16) || (num < 16)) { if (num < 16) pr2serr(" truncated by response length, expected at " "least 16 bytes\n"); else pr2serr(" parameter length >= 16 expected, got %d\n", pl); break; } printf(" Accumulated power on minutes: "); j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf("%d [h:m %d:%d]\n", j, (j / 60), (j % 60)); printf(" Status: "); j = ucp[9]; if (j < (int)(sizeof(bms_status) / sizeof(bms_status[0]))) printf("%s\n", bms_status[j]); else printf("unknown [0x%x] background scan status value\n", j); j = (ucp[10] << 8) + ucp[11]; printf(" Number of background scans performed: %d\n", j); j = (ucp[12] << 8) + ucp[13]; #ifdef SG_LIB_MINGW printf(" Background medium scan progress: %g%%\n", (double)(j * 100.0 / 65536.0)); #else printf(" Background medium scan progress: %.2f%%\n", (double)(j * 100.0 / 65536.0)); #endif j = (ucp[14] << 8) + ucp[15]; if (0 == j) printf(" Number of background medium scans performed: 0 " "[not reported]\n"); else printf(" Number of background medium scans performed: " "%d\n", j); break; default: if (pc > 0x800) { if ((pc >= 0x8000) && (pc <= 0xafff)) printf(" Medium scan parameter # %d [0x%x], vendor " "specific\n", pc, pc); else printf(" Medium scan parameter # %d [0x%x], " "reserved\n", pc, pc); dStrHex((const char *)ucp, ((pl < num) ? pl : num), 0); break; } else printf(" Medium scan parameter # %d [0x%x]\n", pc, pc); if ((pl < 24) || (num < 24)) { if (num < 24) pr2serr(" truncated by response length, expected at " "least 24 bytes\n"); else pr2serr(" parameter length >= 24 expected, got %d\n", pl); break; } printf(" Power on minutes when error detected: "); j = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf("%d [%d:%d]\n", j, (j / 60), (j % 60)); j = (ucp[8] >> 4) & 0xf; if (j < (int)(sizeof(reassign_status) / sizeof(reassign_status[0]))) printf(" %s\n", reassign_status[j]); else printf(" Reassign status: reserved [0x%x]\n", j); printf(" sense key: %s [sk,asc,ascq: 0x%x,0x%x,0x%x]\n", sg_get_sense_key_str(ucp[8] & 0xf, sizeof(str), str), ucp[8] & 0xf, ucp[9], ucp[10]); if (ucp[9] || ucp[10]) printf(" %s\n", sg_get_asc_ascq_str(ucp[9], ucp[10], sizeof(str), str)); if (op->do_verbose) { printf(" vendor bytes [11 -> 15]: "); for (m = 0; m < 5; ++m) printf("0x%02x ", ucp[11 + m]); printf("\n"); } printf(" LBA (associated with medium error): 0x"); for (m = 0; m < 8; ++m) printf("%02x", ucp[16 + m]); printf("\n"); break; } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* Sequential access device page [0xc] for tape */ static void show_sequential_access_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; uint64_t ull, gbytes; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Sequential access device page (ssc-3)\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } ull = decode_count(ucp + 4, pl - 4); gbytes = ull / 1000000000; switch (pc) { case 0: printf(" Data bytes received with WRITE commands: %" PRIu64 " GB", gbytes); if (op->do_verbose) printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 1: printf(" Data bytes written to media by WRITE commands: %" PRIu64 " GB", gbytes); if (op->do_verbose) printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 2: printf(" Data bytes read from media by READ commands: %" PRIu64 " GB", gbytes); if (op->do_verbose) printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 3: printf(" Data bytes transferred by READ commands: %" PRIu64 " GB", gbytes); if (op->do_verbose) printf(" [%" PRIu64 " bytes]", ull); printf("\n"); break; case 4: printf(" Native capacity from BOP to EOD: %" PRIu64 " MB\n", ull); break; case 5: printf(" Native capacity from BOP to EW of current partition: " "%" PRIu64 " MB\n", ull); break; case 6: printf(" Minimum native capacity from EW to EOP of current " "partition: %" PRIu64 " MB\n", ull); break; case 7: printf(" Native capacity from BOP to current position: %" PRIu64 " MB\n", ull); break; case 8: printf(" Maximum native capacity in device object buffer: %" PRIu64 " MB\n", ull); break; case 0x100: if (ull > 0) printf(" Cleaning action required\n"); else printf(" Cleaning action not required (or completed)\n"); if (op->do_verbose) printf(" cleaning value: %" PRIu64 "\n", ull); break; default: if (pc >= 0x8000) printf(" Vendor specific parameter [0x%x] value: %" PRIu64 "\n", pc, ull); else printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x14 for tape and ADC */ static void show_device_stats_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; uint64_t ull; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Device statistics page (ssc-3 and adc)\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } if (pc < 0x1000) { ull = decode_count(ucp + 4, pl - 4); switch (pc) { case 0: printf(" Lifetime media loads: %" PRIu64 "\n", ull); break; case 1: printf(" Lifetime cleaning operations: %" PRIu64 "\n", ull); break; case 2: printf(" Lifetime power on hours: %" PRIu64 "\n", ull); break; case 3: printf(" Lifetime media motion (head) hours: %" PRIu64 "\n", ull); break; case 4: printf(" Lifetime metres of tape processed: %" PRIu64 "\n", ull); break; case 5: printf(" Lifetime media motion (head) hours when " "incompatible media last loaded: %" PRIu64 "\n", ull); break; case 6: printf(" Lifetime power on hours when last temperature " "condition occurred: %" PRIu64 "\n", ull); break; case 7: printf(" Lifetime power on hours when last power " "consumption condition occurred: %" PRIu64 "\n", ull); break; case 8: printf(" Media motion (head) hours since last successful " "cleaning operation: %" PRIu64 "\n", ull); break; case 9: printf(" Media motion (head) hours since 2nd to last " "successful cleaning: %" PRIu64 "\n", ull); break; case 0xa: printf(" Media motion (head) hours since 3rd to last " "successful cleaning: %" PRIu64 "\n", ull); break; case 0xb: printf(" Lifetime power on hours when last operator " "initiated forced reset\n and/or emergency " "eject occurred: %" PRIu64 "\n", ull); break; default: printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); break; } } else { switch (pc) { case 0x1000: printf(" Media motion (head) hours for each medium type:\n"); printf(" <>:\n"); dStrHex((const char *)ucp, pl, 0); // xxxxxxxxxxx break; default: printf(" Reserved parameter [0x%x], dump in hex:\n", pc); dStrHex((const char *)ucp, pl, 0); break; } } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x14 for media changer */ static void show_media_stats_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; uint64_t ull; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Media statistics page (smc-3)\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } ull = decode_count(ucp + 4, pl - 4); switch (pc) { case 0: printf(" Number of moves: %" PRIu64 "\n", ull); break; case 1: printf(" Number of picks: %" PRIu64 "\n", ull); break; case 2: printf(" Number of pick retries: %" PRIu64 "\n", ull); break; case 3: printf(" Number of places: %" PRIu64 "\n", ull); break; case 4: printf(" Number of place retries: %" PRIu64 "\n", ull); break; case 5: printf(" Number of volume tags read by volume " "tag reader: %" PRIu64 "\n", ull); break; case 6: printf(" Number of invalid volume tags returned by " "volume tag reader: %" PRIu64 "\n", ull); break; case 7: printf(" Number of library door opens: %" PRIu64 "\n", ull); break; case 8: printf(" Number of import/export door opens: %" PRIu64 "\n", ull); break; case 9: printf(" Number of physical inventory scans: %" PRIu64 "\n", ull); break; case 0xa: printf(" Number of medium transport unrecovered errors: " "%" PRIu64 "\n", ull); break; case 0xb: printf(" Number of medium transport recovered errors: " "%" PRIu64 "\n", ull); break; case 0xc: printf(" Number of medium transport X axis translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0xd: printf(" Number of medium transport X axis translation " "recovered errors: %" PRIu64 "\n", ull); break; case 0xe: printf(" Number of medium transport Y axis translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0xf: printf(" Number of medium transport Y axis translation " "recovered errors: %" PRIu64 "\n", ull); break; case 0x10: printf(" Number of medium transport Z axis translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0x11: printf(" Number of medium transport Z axis translation " "recovered errors: %" PRIu64 "\n", ull); break; case 0x12: printf(" Number of medium transport rotational translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0x13: printf(" Number of medium transport rotational translation " "recovered errors: %" PRIu64 "\n", ull); break; case 0x14: printf(" Number of medium transport inversion translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0x15: printf(" Number of medium transport inversion translation " "recovered errors: %" PRIu64 "\n", ull); break; case 0x16: printf(" Number of medium transport auxiliary translation " "unrecovered errors: %" PRIu64 "\n", ull); break; case 0x17: printf(" Number of medium transport auxiliary translation " "recovered errors: %" PRIu64 "\n", ull); break; default: printf(" Reserved parameter [0x%x] value: %" PRIu64 "\n", pc, ull); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x15 for media changer */ static void show_element_stats_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned int v; unsigned char * ucp; char str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Element statistics page (smc-3) [0x15]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } printf(" Element address: %d\n", pc); v = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf(" Number of places: %u\n", v); v = (ucp[8] << 24) + (ucp[9] << 16) + (ucp[10] << 8) + ucp[11]; printf(" Number of place retries: %u\n", v); v = (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) + ucp[15]; printf(" Number of picks: %u\n", v); v = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) + ucp[19]; printf(" Number of pick retries: %u\n", v); v = (ucp[20] << 24) + (ucp[21] << 16) + (ucp[22] << 8) + ucp[23]; printf(" Number of determined volume identifiers: %u\n", v); v = (ucp[24] << 24) + (ucp[25] << 16) + (ucp[26] << 8) + ucp[27]; printf(" Number of unreadable volume identifiers: %u\n", v); if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x16 for tape */ static void show_tape_diag_data_page(unsigned char * resp, int len, const struct opts_t * op) { int k, num, pl, pc, pcb; unsigned int v; unsigned char * ucp; char str[PCB_STR_LEN]; char b[80]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Tape diagnostics data page (ssc-3) [0x16]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } printf(" Parameter code: %d\n", pc); printf(" Density code: 0x%x\n", ucp[6]); printf(" Medium type: 0x%x\n", ucp[7]); v = (ucp[8] << 24) + (ucp[9] << 16) + (ucp[10] << 8) + ucp[11]; printf(" Lifetime media motion hours: %u\n", v); printf(" Repeat: %d\n", !!(ucp[13] & 0x80)); v = ucp[13] & 0xf; printf(" Sense key: 0x%x [%s]\n", v, sg_get_sense_key_str(v, sizeof(b), b)); printf(" Additional sense code: 0x%x\n", ucp[14]); printf(" Additional sense code qualifier: 0x%x\n", ucp[15]); if (ucp[14] || ucp[15]) printf(" [%s]\n", sg_get_asc_ascq_str(ucp[14], ucp[15], sizeof(b), b)); v = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) + ucp[19]; printf(" Vendor specific code qualifier: 0x%x\n", v); v = (ucp[20] << 24) + (ucp[21] << 16) + (ucp[22] << 8) + ucp[23]; printf(" Product revision level: %u\n", v); v = (ucp[24] << 24) + (ucp[25] << 16) + (ucp[26] << 8) + ucp[27]; printf(" Hours since last clean: %u\n", v); printf(" Operation code: 0x%x\n", ucp[28]); printf(" Service action: 0x%x\n", ucp[29] & 0xf); // Check Medium id number for all zeros // ssc4r03.pdf does not define this field, why? xxxxxx for (k = 32; k < 64; ++k) { if(ucp[k]) break; } if (64 == k) printf(" Medium id number is 32 bytes of zero\n"); else { printf(" Medium id number (in hex):\n"); dStrHex((const char *)(ucp + 32), 32, 0); } printf(" Timestamp origin: 0x%x\n", ucp[64] & 0xf); // Check Timestamp for all zeros for (k = 66; k < 72; ++k) { if(ucp[k]) break; } if (72 == k) printf(" Timestamp is all zeros:\n"); else { printf(" Timestamp:\n"); dStrHex((const char *)(ucp + 66), 6, 1); } if (pl > 72) { printf(" Vendor specific:\n"); dStrHex((const char *)(ucp + 72), pl - 72, 0); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x16 for media changer */ static void show_mchanger_diag_data_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned int v; unsigned char * ucp; char str[PCB_STR_LEN]; char b[80]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Media changer diagnostics data page (smc-3) [0x16]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } printf(" Parameter code: %d\n", pc); printf(" Repeat: %d\n", !!(ucp[5] & 0x80)); v = ucp[5] & 0xf; printf(" Sense key: 0x%x [%s]\n", v, sg_get_sense_key_str(v, sizeof(b), b)); printf(" Additional sense code: 0x%x\n", ucp[6]); printf(" Additional sense code qualifier: 0x%x\n", ucp[7]); if (ucp[6] || ucp[7]) printf(" [%s]\n", sg_get_asc_ascq_str(ucp[6], ucp[7], sizeof(b), b)); v = (ucp[8] << 24) + (ucp[9] << 16) + (ucp[10] << 8) + ucp[11]; printf(" Vendor specific code qualifier: 0x%x\n", v); v = (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) + ucp[15]; printf(" Product revision level: %u\n", v); v = (ucp[16] << 24) + (ucp[17] << 16) + (ucp[18] << 8) + ucp[19]; printf(" Number of moves: %u\n", v); v = (ucp[20] << 24) + (ucp[21] << 16) + (ucp[22] << 8) + ucp[23]; printf(" Number of pick: %u\n", v); v = (ucp[24] << 24) + (ucp[25] << 16) + (ucp[26] << 8) + ucp[27]; printf(" Number of pick retries: %u\n", v); v = (ucp[28] << 24) + (ucp[29] << 16) + (ucp[30] << 8) + ucp[31]; printf(" Number of places: %u\n", v); v = (ucp[32] << 24) + (ucp[33] << 16) + (ucp[34] << 8) + ucp[35]; printf(" Number of place retries: %u\n", v); v = (ucp[36] << 24) + (ucp[37] << 16) + (ucp[38] << 8) + ucp[39]; printf(" Number of determined volume identifiers: %u\n", v); v = (ucp[40] << 24) + (ucp[41] << 16) + (ucp[42] << 8) + ucp[43]; printf(" Number of unreadable volume identifiers: %u\n", v); printf(" Operation code: 0x%x\n", ucp[44]); printf(" Service action: 0x%x\n", ucp[45] & 0xf); printf(" Media changer error type: 0x%x\n", ucp[46]); printf(" MTAV: %d\n", !!(ucp[47] & 0x8)); printf(" IAV: %d\n", !!(ucp[47] & 0x4)); printf(" LSAV: %d\n", !!(ucp[47] & 0x2)); printf(" DAV: %d\n", !!(ucp[47] & 0x1)); v = (ucp[48] << 8) + ucp[49]; printf(" Medium transport address: 0x%x\n", v); v = (ucp[50] << 8) + ucp[51]; printf(" Intial address: 0x%x\n", v); v = (ucp[52] << 8) + ucp[53]; printf(" Last successful address: 0x%x\n", v); v = (ucp[54] << 8) + ucp[55]; printf(" Destination address: 0x%x\n", v); if (pl > 91) { printf(" Volume tag information:\n"); dStrHex((const char *)(ucp + 56), 36, 0); } if (pl > 99) { printf(" Timestamp origin: 0x%x\n", ucp[92] & 0xf); printf(" Timestamp:\n"); dStrHex((const char *)(ucp + 94), 6, 1); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } static void volume_stats_partition(const unsigned char * xp, int len, int hex) { int dl; while (len > 3) { dl = xp[0] + 1; if (dl < 3) return; if (hex) printf(" partition number: %d, partition record data " "counter: 0x%" PRIx64 "\n", (xp[2] << 8) + xp[3], decode_count(xp + 4, dl - 4)); else { int k; int all_ffs = 0; int ffs_last_fe = 0; unsigned char uc; for (k = 0; k < (dl - 4); ++k) { uc = xp[4 + k]; if (uc < 0xfe) break; if ((k < (dl - 5)) && (0xfe == uc)) break; if (k == (dl - 5)) { if (0xff == uc) all_ffs = 1; else if (0xfe == uc) ffs_last_fe = 1; } } if (0 == (all_ffs + ffs_last_fe)) printf(" partition number: %d, partition record data " "counter: %" PRIu64 "\n", (xp[2] << 8) + xp[3], decode_count(xp + 4, dl - 4)); else if (all_ffs) printf(" partition number: %d, partition record data " "counter is all 0xFFs\n", (xp[2] << 8) + xp[3]); else printf(" partition number: %d, partition record data " "counter is all 0xFFs apart\n from a trailing " "0xFE\n", (xp[2] << 8) + xp[3]); } xp += dl; len -= dl; } } /* Volume Statistics log page (ssc-4) [0x17, 0x1-0xf] */ static void show_volume_stats_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb, spf, subpg_code; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; spf = !!(resp[0] & 0x40); subpg_code = spf ? resp[1] : 0; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) { if (0 == subpg_code) printf("Volume statistics page (ssc-4) but subpage=0, abnormal: " "treat like subpage=1\n"); else if (subpg_code < 0x10) printf("Volume statistics page (ssc-4), subpage=%d\n", subpg_code); else { printf("Volume statistics page (ssc-4), subpage=%d; Reserved, " "skip\n", subpg_code); return; } } num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Page valid: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 1: printf(" Thread count: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 2: printf(" Total data sets written: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 3: printf(" Total write retries: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 4: printf(" Total unrecovered write errors: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 5: printf(" Total suspended writes: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 6: printf(" Total fatal suspended writes: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 7: printf(" Total data sets read: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 8: printf(" Total read retries: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 9: printf(" Total unrecovered read errors: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xa: printf(" Total suspended reads: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xb: printf(" Total fatal suspended reads: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xc: printf(" Last mount unrecovered write errors: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xd: printf(" Last mount unrecovered read errors: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xe: printf(" Last mount megabytes written: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0xf: printf(" Last mount megabytes read: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x10: printf(" Lifetime megabytes written: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x11: printf(" Lifetime megabytes read: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x12: printf(" Last load write compression ratio: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x13: printf(" Last load read compression ratio: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x14: printf(" Medium mount time: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x15: printf(" Medium ready time: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x16: printf(" Total native capacity: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x17: printf(" Total used native capacity: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x40: printf(" Volume serial number: %.*s\n", pl - 4, ucp + 4); break; case 0x41: printf(" Tape lot identifier: %.*s\n", pl - 4, ucp + 4); break; case 0x42: printf(" Volume barcode: %.*s\n", pl - 4, ucp + 4); break; case 0x43: printf(" Volume manufacturer: %.*s\n", pl - 4, ucp + 4); break; case 0x44: printf(" Volume license code: %.*s\n", pl - 4, ucp + 4); break; case 0x45: printf(" Volume personality: %.*s\n", pl - 4, ucp + 4); break; case 0x80: printf(" Write protect: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x81: printf(" WORM: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x82: printf(" Maximum recommended tape path temperature exceeded: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x100: printf(" Volume write mounts: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x101: printf(" Beginning of medium passes: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x102: printf(" Middle of medium passes: %" PRIu64 "\n", decode_count(ucp + 4, pl - 4)); break; case 0x200: printf(" Logical position of first encrypted logical object:\n"); volume_stats_partition(ucp + 4, pl - 4, 1); break; case 0x201: printf(" Logical position of first unencrypted logical object " "after first\n encrypted logical object:\n"); volume_stats_partition(ucp + 4, pl - 4, 1); break; case 0x202: printf(" Native capacity partition(s):\n"); volume_stats_partition(ucp + 4, pl - 4, 0); break; case 0x203: printf(" Used native capacity partition(s):\n"); volume_stats_partition(ucp + 4, pl - 4, 0); break; case 0x204: printf(" Remaining native capacity partition(s):\n"); volume_stats_partition(ucp + 4, pl - 4, 0); break; case 0x300: printf(" Mount history, payload in hex:\n"); // xxxxxxxx TODO dStrHex((const char *)(ucp + 4), pl - 4, 0); break; default: if (pc >= 0xf000) printf(" Vendor specific parameter code (0x%x), payload " "in hex\n", pc); else printf(" Reserved parameter code (0x%x), payload in hex\n", pc); dStrHex((const char *)(ucp + 4), pl - 4, 0); break; } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf(" <%s>\n", pcb_str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } static const char * tape_alert_strs[] = { "", /* 0x0 */ "Read warning", "Write warning", "Hard error", "Media", "Read failure", "Write failure", "Media life", "Not data grade", /* 0x8 */ "Write protect", "No removal", "Cleaning media", "Unsupported format", "Recoverable mechanical cartridge failure", "Unrecoverable mechanical cartridge failure", "Memory chip in cartridge failure", "Forced eject", /* 0x10 */ "Read only format", "Tape directory corrupted on load", "Nearing media life", "Cleaning required", "Cleaning requested", "Expired cleaning media", "Invalid cleaning tape", "Retension requested", /* 0x18 */ "Dual port interface error", "Cooling fan failing", "Power supply failure", "Power consumption", "Drive maintenance", "Hardware A", "Hardware B", "Interface", /* 0x20 */ "Eject media", "Microcode update fail", "Drive humidity", "Drive temperature", "Drive voltage", "Predictive failure", "Diagnostics required", "Obsolete (28h)", /* 0x28 */ "Obsolete (29h)", "Obsolete (2Ah)", "Obsolete (2Bh)", "Obsolete (2Ch)", "Obsolete (2Dh)", "Obsolete (2Eh)", "Reserved (2Fh)", "Reserved (30h)", /* 0x30 */ "Reserved (31h)", "Lost statistics", "Tape directory invalid at unload", "Tape system area write failure", "Tape system area read failure", "No start of data", "Loading failure", "Unrecoverable unload failure", /* 0x38 */ "Automation interface failure", "Firmware failure", "WORM medium - integrity check failed", "WORM medium - overwrite attempted", }; /* TAPE_ALERT_LPAGE [0x2e] */ static void show_tape_alert_ssc_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb, flag; unsigned char * ucp; char str[PCB_STR_LEN]; /* N.B. the Tape alert log page for smc-3 is different */ if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Tape alert page (ssc-3) [0x2e]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } flag = ucp[4] & 1; if (op->do_verbose && (0 == op->do_brief) && flag) printf(" >>>> "); if ((0 == op->do_brief) || op->do_verbose || flag) { if (pc < (int)(sizeof(tape_alert_strs) / sizeof(tape_alert_strs[0]))) printf(" %s: %d\n", tape_alert_strs[pc], flag); else printf(" Reserved parameter code 0x%x, flag: %d\n", pc, flag); } if (op->do_pcb) { get_pcb_str(pcb, str, sizeof(str)); printf(" <%s>\n", str); } if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x37 */ static void show_seagate_cache_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb; unsigned char * ucp; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Seagate cache page [0x37]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } switch (pc) { case 0: printf(" Blocks sent to initiator"); break; case 1: printf(" Blocks received from initiator"); break; case 2: printf(" Blocks read from cache and sent to initiator"); break; case 3: printf(" Number of read and write commands whose size " "<= segment size"); break; case 4: printf(" Number of read and write commands whose size " "> segment size"); break; default: printf(" Unknown Seagate parameter code = 0x%x", pc); break; } printf(" = %" PRIu64 "", decode_count(ucp + 4, pl - 4)); if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } /* 0x3e */ static void show_seagate_factory_page(unsigned char * resp, int len, const struct opts_t * op) { int num, pl, pc, pcb, valid; unsigned char * ucp; uint64_t ull; char pcb_str[PCB_STR_LEN]; if (op->do_verbose || ((0 == op->do_raw) && (0 == op->do_hex))) printf("Seagate/Hitachi factory page [0x3e]\n"); num = len - 4; ucp = &resp[0] + 4; while (num > 3) { pc = (ucp[0] << 8) | ucp[1]; pcb = ucp[2]; pl = ucp[3] + 4; if (op->filter_given) { if (pc != op->filter) goto skip; if (op->do_raw) { dStrRaw((const char *)ucp, pl); break; } else if (op->do_hex) { dStrHex((const char *)ucp, pl, ((1 == op->do_hex) ? 1 : -1)); break; } } valid = 1; switch (pc) { case 0: printf(" number of hours powered up"); break; case 8: printf(" number of minutes until next internal SMART test"); break; default: valid = 0; printf(" Unknown Seagate/Hitachi parameter code = 0x%x", pc); break; } if (valid) { ull = decode_count(ucp + 4, pl - 4); if (0 == pc) printf(" = %.2f", ((double)ull) / 60.0 ); else printf(" = %" PRIu64 "", ull); } if (op->do_pcb) { get_pcb_str(pcb, pcb_str, sizeof(pcb_str)); printf("\n <%s>\n", pcb_str); } else printf("\n"); if (op->filter_given) break; skip: num -= pl; ucp += pl; } } static void show_ascii_page(unsigned char * resp, int len, struct sg_simple_inquiry_resp * inq_dat, const struct opts_t * op) { int k, num, done, pg_code, subpg_code, spf; if (len < 0) { pr2serr("%s: response has bad length\n", __func__); return; } num = len - 4; done = 1; spf = !!(resp[0] & 0x40); pg_code = resp[0] & 0x3f; subpg_code = spf ? resp[1] : 0; if ((SUPP_PAGES_LPAGE != pg_code ) && (SUPP_SPGS_SUBPG == subpg_code)) { printf("Supported subpages for log page=0x%x [0x%x, 0x%x]\n", pg_code, pg_code, subpg_code); /* introduced: SPC-4 */ for (k = 0; k < num; k += 2) show_page_name((int)resp[4 + k], (int)resp[4 + k + 1], inq_dat); return; } switch (pg_code) { case SUPP_PAGES_LPAGE: /* 0x0 */ if (spf) { printf("Supported log pages and subpages [0x%x, 0x%x]:\n", pg_code, subpg_code); /* introduced: SPC-4 */ for (k = 0; k < num; k += 2) show_page_name((int)resp[4 + k], (int)resp[4 + k + 1], inq_dat); } else { printf("Supported log pages [0x0]:\n"); /* introduced: SPC-2 */ for (k = 0; k < num; ++k) show_page_name((int)resp[4 + k], 0, inq_dat); } break; case BUFF_OVER_UNDER_LPAGE: /* 0x1 */ show_buffer_under_over_run_page(resp, len, op); break; case WRITE_ERR_LPAGE: /* 0x2 */ case READ_ERR_LPAGE: /* 0x3 */ case READ_REV_ERR_LPAGE: /* 0x4 */ case VERIFY_ERR_LPAGE: /* 0x5 */ show_error_counter_page(resp, len, op); break; case NON_MEDIUM_LPAGE: /* 0x6 */ show_non_medium_error_page(resp, len, op); break; case LAST_N_ERR_LPAGE: /* 0x7 */ show_last_n_error_page(resp, len, op); break; case FORMAT_STATUS_LPAGE: /* 0x8 */ { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ show_format_status_page(resp, len, op); break; default: done = 0; break; } } break; case LAST_N_DEFERRED_LPAGE: /* 0xb */ show_last_n_deferred_error_page(resp, len, op); break; case 0xc: { switch (inq_dat->peripheral_type) { case PDT_DISK: /* LB_PROV_LPAGE */ show_lb_provisioning_page(resp, len, op); break; case PDT_TAPE: case PDT_PRINTER: /* tape and (printer) type devices */ show_sequential_access_page(resp, len, op); break; default: done = 0; break; } } break; case TEMPERATURE_LPAGE: /* 0xd */ show_temperature_page(resp, len, op, 1); break; case START_STOP_LPAGE: /* 0xe */ show_start_stop_page(resp, len, op); break; case APP_CLIENT_LPAGE: /* 0xf */ show_app_client_page(resp, len, op); break; case SELF_TEST_LPAGE: /* 0x10 */ show_self_test_page(resp, len, op); break; case SOLID_STATE_MEDIA_LPAGE: /* 0x11 */ switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: show_solid_state_media_page(resp, len, op); break; case PDT_TAPE: case PDT_ADC: show_dt_device_status_page(resp, len, op); break; default: done = 0; break; } break; case 0x14: { switch (inq_dat->peripheral_type) { case PDT_TAPE: case PDT_ADC: /* tape and adc type devices */ show_device_stats_page(resp, len, op); break; case PDT_MCHANGER: /* smc-3 */ show_media_stats_page(resp, len, op); break; default: done = 0; break; } } break; case 0x15: { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ if (0 == subpg_code) show_background_scan_results_page(resp, len, op); else done = 0; /* todo: pending defects [0x15,1] */ break; case PDT_MCHANGER: /* smc-3 */ show_element_stats_page(resp, len, op); break; default: done = 0; break; } } break; case SAT_ATA_RESULTS_LPAGE: /* 0x16 */ { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ show_ata_pt_results_page(resp, len, op); break; case PDT_TAPE: /* ssc-4 */ show_tape_diag_data_page(resp, len, op); break; case PDT_MCHANGER: /* smc-3 */ show_mchanger_diag_data_page(resp, len, op); break; default: done = 0; break; } } break; case 0x17: { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ show_non_volatile_cache_page(resp, len, op); break; case PDT_TAPE: /* ssc-4, subpages 1 to 0xf */ show_volume_stats_page(resp, len, op); break; default: done = 0; break; } } break; case PROTO_SPECIFIC_LPAGE: /* 0x18 */ done = show_protocol_specific_page(resp, len, op); break; case STATS_LPAGE: /* 0x19, defined for subpages 0 to 32 inclusive */ if (subpg_code <= HIGH_GRP_STATS_SUBPG) done = show_stats_perform_page(resp, len, op); else if (subpg_code == CACHE_STATS_SUBPG) done = show_cache_stats_page(resp, len, op); else done = 0; break; case PCT_LPAGE: /* 0x1a */ show_power_condition_transitions_page(resp, len, op); break; case 0x1b: show_data_compression_log_page(resp, len, op); break; case TAPE_ALERT_LPAGE: /* 0x2e */ { switch (inq_dat->peripheral_type) { case PDT_TAPE: /* ssc only */ show_tape_alert_ssc_page(resp, len, op); break; default: done = 0; break; } } break; case 0x30: /* vendor specific: IBM */ show_tape_usage_log_page(resp, len, op); break; case 0x31: /* vendor specific: IBM */ show_tape_capacity_log_page(resp, len, op); break; case 0x32: /* vendor specific, now tweaked and standardized at 0x1b */ show_data_compression_log_page(resp, len, op); break; case IE_LPAGE: show_ie_page(resp, len, op, 1); break; case 0x37: { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ show_seagate_cache_page(resp, len, op); break; default: done = 0; break; } } break; case 0x3e: { switch (inq_dat->peripheral_type) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_RBC: /* disk (direct access) type devices */ show_seagate_factory_page(resp, len, op); break; default: done = 0; break; } } break; default: done = 0; break; } if (! done) { if (spf) printf("No ascii information for page = 0x%x, subpage = 0x%x, " "here is hex:\n", pg_code, subpg_code); else printf("No ascii information for page = 0x%x, here is hex:\n", pg_code); if (len > 128) { dStrHex((const char *)resp, 64, 1); printf(" ..... [truncated after 64 of %d bytes (use '-H' to " "see the rest)]\n", len); } else dStrHex((const char *)resp, len, 1); } } static int fetchTemperature(int sg_fd, unsigned char * resp, int max_len, struct opts_t * op) { int len; int res = 0; op->pg_code = TEMPERATURE_LPAGE; op->subpg_code = NOT_SPG_SUBPG; res = do_logs(sg_fd, resp, max_len, op); if (0 == res) { len = (resp[2] << 8) + resp[3] + 4; if (op->do_raw) dStrRaw((const char *)resp, len); else if (op->do_hex) dStrHex((const char *)resp, len, (1 == op->do_hex)); else show_temperature_page(resp, len, op, 0); }else if (SG_LIB_CAT_NOT_READY == res) pr2serr("Device not ready\n"); else { op->pg_code = IE_LPAGE; res = do_logs(sg_fd, resp, max_len, op); if (0 == res) { len = (resp[2] << 8) + resp[3] + 4; if (op->do_raw) dStrRaw((const char *)resp, len); else if (op->do_hex) dStrHex((const char *)resp, len, (1 == op->do_hex)); else show_ie_page(resp, len, op, 0); } else pr2serr("Unable to find temperature in either Temperature or " "IE log page\n"); } sg_cmds_close_device(sg_fd); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } int main(int argc, char * argv[]) { int sg_fd, k, pg_len, res, resp_len; int in_len = -1; int ret = 0; struct sg_simple_inquiry_resp inq_out; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); memset(rsp_buff, 0, sizeof(rsp_buff)); /* N.B. some disks only give data for current cumulative */ op->page_control = 1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } if (op->do_version) { pr2serr("Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_select) { if (op->do_temperature) { pr2serr("--select cannot be used with --temperature\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_transport) { pr2serr("--select cannot be used with --transport\n"); return SG_LIB_SYNTAX_ERROR; } } else if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if (op->do_all) { if (op->do_select) { pr2serr("--all conflicts with --select\n"); return SG_LIB_SYNTAX_ERROR; } if (op->filter) { pr2serr("--all conflicts with --filter\n"); return SG_LIB_SYNTAX_ERROR; } } if (op->in_fn) { if (! op->do_select) { pr2serr("--in=FN can only be used with --select\n"); return SG_LIB_SYNTAX_ERROR; } if (f2hex_arr(op->in_fn, op->do_raw, 0, rsp_buff, &in_len, sizeof(rsp_buff))) return SG_LIB_FILE_ERROR; } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT win32_spt_init_state = scsi_pt_win32_spt_state(); if (op->do_verbose > 4) pr2serr("Initial win32 SPT interface state: %s\n", win32_spt_init_state ? "direct" : "indirect"); #endif #endif sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, op->do_verbose); if ((sg_fd < 0) && (0 == op->o_readonly)) sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->do_verbose); if (sg_fd < 0) { pr2serr("error opening file: %s: %s \n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->do_list || op->do_all) { op->pg_code = SUPP_PAGES_LPAGE; if ((op->do_list > 1) || (op->do_all > 1)) op->subpg_code = SUPP_SPGS_SUBPG; } if (op->do_transport) { if ((op->pg_code > 0) || (op->subpg_code > 0) || op->do_temperature) { pr2serr("'-T' should not be mixed with options implying other " "pages\n"); return SG_LIB_FILE_ERROR; } op->pg_code = PROTO_SPECIFIC_LPAGE; } pg_len = 0; if (op->no_inq < 2) { if (sg_simple_inquiry(sg_fd, &inq_out, 1, op->do_verbose)) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->device_name); sg_cmds_close_device(sg_fd); return SG_LIB_CAT_OTHER; } if ((0 == op->do_raw) && (0 == op->do_hex) && (0 == op->do_name) && (0 == op->no_inq)) printf(" %.8s %.16s %.4s\n", inq_out.vendor, inq_out.product, inq_out.revision); } else memset(&inq_out, 0, sizeof(inq_out)); if (1 == op->do_temperature) return fetchTemperature(sg_fd, rsp_buff, SHORT_RESP_LEN, op); if (op->do_select) { k = sg_ll_log_select(sg_fd, !!(op->do_pcreset), op->do_sp, op->page_control, op->pg_code, op->subpg_code, rsp_buff, ((in_len > 0) ? in_len : 0), 1, op->do_verbose); if (k) { if (SG_LIB_CAT_NOT_READY == k) pr2serr("log_select: device not ready\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("log_select: field in cdb illegal\n"); else if (SG_LIB_CAT_INVALID_OP == k) pr2serr("log_select: not supported\n"); else if (SG_LIB_CAT_UNIT_ATTENTION == k) pr2serr("log_select: unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == k) pr2serr("log_select: aborted command\n"); else pr2serr("log_select: failed (%d), try '-v' for more " "information\n", k); } return (k >= 0) ? k : SG_LIB_CAT_OTHER; } resp_len = (op->maxlen > 0) ? op->maxlen : MX_ALLOC_LEN; res = do_logs(sg_fd, rsp_buff, resp_len, op); if (0 == res) { pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; if ((pg_len + 4) > resp_len) { pr2serr("Only fetched %d bytes of response (available: %d " "bytes)\n truncate output\n", resp_len, pg_len + 4); pg_len = resp_len - 4; } } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("log_sense: not supported\n"); else if (SG_LIB_CAT_NOT_READY == res) pr2serr("log_sense: device not ready\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("log_sense: field in cdb illegal\n"); else if (SG_LIB_CAT_UNIT_ATTENTION == res) pr2serr("log_sense: unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("log_sense: aborted command\n"); if (0 == op->do_all) { if (op->filter_given) { if (op->do_hex > 2) dStrHex((const char *)rsp_buff, pg_len + 4, (op->do_hex < 4)); else show_ascii_page(rsp_buff, pg_len + 4, &inq_out, op); } else if (op->do_raw) dStrRaw((const char *)rsp_buff, pg_len + 4); else if (op->do_hex > 1) dStrHex((const char *)rsp_buff, pg_len + 4, (2 == op->do_hex)); else if (pg_len > 1) { if (op->do_hex) { if (rsp_buff[0] & 0x40) printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, " "page_len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1], !!(rsp_buff[0] & 0x80), pg_len); else printf("Log page code=0x%x, DS=%d, SPF=0, page_len=0x%x\n", rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len); dStrHex((const char *)rsp_buff, pg_len + 4, 1); } else show_ascii_page(rsp_buff, pg_len + 4, &inq_out, op); } } ret = res; if (op->do_all && (pg_len > 1)) { int my_len = pg_len; int spf; unsigned char parr[1024]; spf = !!(rsp_buff[0] & 0x40); if (my_len > (int)sizeof(parr)) { pr2serr("Unexpectedly large page_len=%d, trim to %d\n", my_len, (int)sizeof(parr)); my_len = sizeof(parr); } memcpy(parr, rsp_buff + 4, my_len); for (k = 0; k < my_len; ++k) { if (0 == op->do_raw) printf("\n"); op->pg_code = parr[k] & 0x3f; if (spf) op->subpg_code = parr[++k]; else op->subpg_code = NOT_SPG_SUBPG; res = do_logs(sg_fd, rsp_buff, resp_len, op); if (0 == res) { pg_len = (rsp_buff[2] << 8) + rsp_buff[3]; if ((pg_len + 4) > resp_len) { pr2serr("Only fetched %d bytes of response, truncate " "output\n", resp_len); pg_len = resp_len - 4; } if (op->do_raw) dStrRaw((const char *)rsp_buff, pg_len + 4); else if (op->do_hex > 1) dStrHex((const char *)rsp_buff, pg_len + 4, (2 == op->do_hex)); else if (op->do_hex) { if (rsp_buff[0] & 0x40) printf("Log page code=0x%x,0x%x, DS=%d, SPF=1, page_" "len=0x%x\n", rsp_buff[0] & 0x3f, rsp_buff[1], !!(rsp_buff[0] & 0x80), pg_len); else printf("Log page code=0x%x, DS=%d, SPF=0, page_len=" "0x%x\n", rsp_buff[0] & 0x3f, !!(rsp_buff[0] & 0x80), pg_len); dStrHex((const char *)rsp_buff, pg_len + 4, 1); } else show_ascii_page(rsp_buff, pg_len + 4, &inq_out, op); } else if (SG_LIB_CAT_INVALID_OP == res) pr2serr("log_sense: page=0x%x,0x%x not supported\n", op->pg_code, op->subpg_code); else if (SG_LIB_CAT_NOT_READY == res) pr2serr("log_sense: device not ready\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("log_sense: field in cdb illegal " "[page=0x%x,0x%x]\n", op->pg_code, op->subpg_code); else if (SG_LIB_CAT_UNIT_ATTENTION == res) pr2serr("log_sense: unit attention\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("log_sense: aborted command\n"); else pr2serr("log_sense: failed, try '-v' for more information\n"); } } sg_cmds_close_device(sg_fd); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_rdac.c0000664000175000017500000003022712335513125014711 0ustar douggdougg/* * sg_rdac * * Retrieve / set RDAC options. * * Copyright (C) 2006-2007 Hannes Reinecke * * Based on sg_modes.c and sg_emc_trespass.c; credits from there apply. * * 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. */ #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "1.06 20130507"; unsigned char mode6_hdr[] = { 75, /* Length */ 0, /* medium */ 0, /* params */ 8, /* Block descriptor length */ }; unsigned char block_descriptor[] = { 0, /* Density code */ 0, 0, 0, /* Number of blocks */ 0, /* Reserved */ 0, 0x02, 0, /* 512 byte blocks */ }; struct rdac_legacy_page { unsigned char page_code; unsigned char page_length; char current_serial[16]; char alternate_serial[16]; unsigned char current_mode_msb; unsigned char current_mode_lsb; unsigned char alternate_mode_msb; unsigned char alternate_mode_lsb; unsigned char quiescence; unsigned char options; unsigned char lun_table[32]; unsigned char lun_table_exp[32]; unsigned short reserved; }; static int do_verbose = 0; static void dump_mode_page( unsigned char *page, int len ) { int i, k; for (k = 0; k < len; k += 16) { printf("%x:",k / 16); for (i = 0; i < 16; i++) { printf(" %02x", page[k + i]); if (k + i >= len) { printf("\n"); break; } } printf("\n"); } } #define MX_ALLOC_LEN (1024 * 4) #define RDAC_CONTROLLER_PAGE 0x2c #define RDAC_CONTROLLER_PAGE_LEN 0x68 #define LEGACY_PAGE 0x00 #define EXPANDED_LUN_SPACE_PAGE 0x01 #define RDAC_FAIL_ALL_PATHS 0x1 #define RDAC_FAIL_SELECTED_PATHS 0x2 #define RDAC_FORCE_QUIESCENCE 0x2 #define RDAC_QUIESCENCE_TIME 10 static int fail_all_paths(int fd) { unsigned char fail_paths_pg[118]; struct rdac_legacy_page *rdac_page; int res; char b[80]; memset(fail_paths_pg, 0, 118); memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_page->quiescence = RDAC_QUIESCENCE_TIME; rdac_page->options = RDAC_FORCE_QUIESCENCE; rdac_page->current_mode_lsb = RDAC_FAIL_ALL_PATHS; res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); switch (res) { case 0: if (do_verbose) fprintf(stderr, "fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "fail paths failed: %s\n", b); break; } return res; } static int fail_this_path(int fd, int lun) { unsigned char fail_paths_pg[118]; struct rdac_legacy_page *rdac_page; int res; char b[80]; memset(fail_paths_pg, 0, 118); memcpy(fail_paths_pg, mode6_hdr, 4); memcpy(fail_paths_pg + 4, block_descriptor, 8); rdac_page = (struct rdac_legacy_page *)(fail_paths_pg + 4 + 8); rdac_page->page_code = RDAC_CONTROLLER_PAGE | 0x40; rdac_page->page_length = RDAC_CONTROLLER_PAGE_LEN; rdac_page->current_mode_lsb = RDAC_FAIL_SELECTED_PATHS; rdac_page->quiescence = RDAC_QUIESCENCE_TIME; rdac_page->options = RDAC_FORCE_QUIESCENCE; memset(rdac_page->lun_table, 0x0, 32); rdac_page->lun_table[lun] = 0x81; res = sg_ll_mode_select6(fd, 1 /* pf */, 0 /* sp */, fail_paths_pg, 118, 1, (do_verbose ? 2 : 0)); switch (res) { case 0: if (do_verbose) fprintf(stderr, "fail paths successful\n"); break; default: sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "fail paths page (lun=%d) failed: %s\n", lun, b); break; } return res; } static void print_rdac_mode( unsigned char *ptr ) { struct rdac_legacy_page *rdac_ptr; int i, k, bd_len; bd_len = ptr[3]; rdac_ptr = (struct rdac_legacy_page *)(ptr + 4 + bd_len); printf("RDAC Legacy page\n"); printf(" Controller serial: %s\n", rdac_ptr->current_serial); printf(" Alternate controller serial: %s\n", rdac_ptr->alternate_serial); printf(" RDAC mode (redundant processor): "); switch (rdac_ptr->current_mode_msb) { case 0x00: printf("alternate controller not present; "); break; case 0x01: printf("alternate controller present; "); break; default: printf("(Unknown controller status 0x%x); ", rdac_ptr->current_mode_msb); break; } switch (rdac_ptr->current_mode_lsb) { case 0x0: printf("inactive\n"); break; case 0x1: printf("active\n"); break; case 0x2: printf("Dual active mode\n"); break; default: printf("(Unknown mode 0x%x)\n", rdac_ptr->current_mode_lsb); } printf(" RDAC mode (alternate processor): "); switch (rdac_ptr->alternate_mode_msb) { case 0x00: printf("alternate controller not present; "); break; case 0x01: printf("alternate controller present; "); break; case 0x02: printf("active/active mode; "); break; default: printf("(Unknown status 0x%x); ", rdac_ptr->alternate_mode_msb); break; } switch (rdac_ptr->alternate_mode_lsb) { case 0x0: printf("inactive\n"); break; case 0x1: printf("active\n"); break; case 0x2: printf("Dual active mode\n"); break; case 0x04: printf("held in reset\n"); break; default: printf("(Unknown mode 0x%x)\n", rdac_ptr->alternate_mode_lsb); } printf(" Quiescence timeout: %d\n", rdac_ptr->quiescence); printf(" RDAC option 0x%x\n", rdac_ptr->options); printf (" LUN Table:\n"); for (k = 0; k < 32; k += 8) { printf(" %x:",k / 8); for (i = 0; i < 8; i++) { switch (rdac_ptr->lun_table[k + i]) { case 0x0: printf(" x"); break; case 0x1: printf(" p"); break; case 0x2: printf(" a"); break; case 0x3: printf(" u"); break; default: printf(" ?"); break; } } printf("\n"); } } static void usage() { printf("Usage: sg_rdac [-a] [-f=LUN] [-v] [-V] DEVICE\n" " where:\n" " -a transfer all devices to the controller\n" " serving DEVICE.\n" " -f=LUN transfer the device at LUN to the\n" " controller serving DEVICE\n" " -v verbose\n" " -V print version then exit\n\n" " Display/Modify RDAC Redundant Controller Page 0x2c.\n" " If [-a] or [-f] is not specified the current settings" " are displayed.\n"); } int main(int argc, char * argv[]) { unsigned char rsp_buff[MX_ALLOC_LEN]; char **argptr; char * file_name = 0; int res, fd, k, lun = -1; int fail_all = 0; int fail_path = 0; int ret = 0; if (argc < 2) { usage (); return SG_LIB_SYNTAX_ERROR; } for (k = 1; k < argc; ++k) { argptr = argv + k; if (!strcmp (*argptr, "-v")) ++do_verbose; else if (!strncmp(*argptr, "-f=",3)) { ++fail_path; lun = strtoul(*argptr + 3, NULL, 0); } else if (!strcmp(*argptr, "-a")) { ++fail_all; } else if (!strcmp(*argptr, "-V")) { fprintf(stderr, "sg_rdac version: %s\n", version_str); return 0; } else if (*argv[k] == '-') { fprintf(stderr, "Unrecognized switch: %s\n", argv[k]); file_name = 0; break; } else if (0 == file_name) file_name = argv[k]; else { fprintf(stderr, "too many arguments\n"); file_name = 0; break; } } if (0 == file_name) { usage(); return SG_LIB_SYNTAX_ERROR; } fd = sg_cmds_open_device(file_name, 0 /* rw */, do_verbose); if (fd < 0) { fprintf(stderr, "open error: %s: %s\n", file_name, safe_strerror(-fd)); usage(); return SG_LIB_FILE_ERROR; } if (fail_all) { res = fail_all_paths(fd); } else if (fail_path) { res = fail_this_path(fd, lun); } else { res = sg_ll_mode_sense6(fd, /*DBD*/ 0, /* page control */0, 0x2c, 0, rsp_buff, 252, 1, do_verbose); if (!res) { if (do_verbose) dump_mode_page(rsp_buff, rsp_buff[0]); print_rdac_mode(rsp_buff); } else { if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, ">>>>>> try again without " "the '-6' switch for a 10 byte MODE " "SENSE command\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "mode sense: invalid field " "in cdb (perhaps subpages or page " "control (PC) not supported)\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, do_verbose); fprintf(stderr, "mode sense failed: %s\n", b); } } } ret = res; res = sg_cmds_close_device(fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_format.c0000664000175000017500000012605112414667052015300 0ustar douggdougg/* * sg_format : format a SCSI disk * potentially with a different number of blocks and block size * * formerly called blk512-linux.c (v0.4) * * Copyright (C) 2003 Grant Grundler grundler at parisc-linux dot org * Copyright (C) 2003 James Bottomley jejb at parisc-linux dot org * Copyright (C) 2005-2014 Douglas Gilbert dgilbert at interlog dot com * * 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. * * See http://www.t10.org for relevant standards and drafts. The most recent * draft is SBC-4 revision 2. */ #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "1.30 20141006"; #define RW_ERROR_RECOVERY_PAGE 1 /* can give alternate with --mode=MP */ #define SHORT_TIMEOUT 20 /* 20 seconds unless --wait given */ #define FORMAT_TIMEOUT (20 * 3600) /* 20 hours ! */ /* Seagate ST32000444SS 2TB disk takes 9.5 hours, now there are 4TB disks */ #define POLL_DURATION_SECS 60 #define DEF_POLL_TYPE 0 #if defined(MSC_VER) || defined(__MINGW32__) #define HAVE_MS_SLEEP #endif #ifdef HAVE_MS_SLEEP #include #define sleep_for(seconds) Sleep( (seconds) * 1000) #else #define sleep_for(seconds) sleep(seconds) #endif #define MAX_BUFF_SZ 252 static unsigned char dbuff[MAX_BUFF_SZ]; static struct option long_options[] = { {"count", required_argument, 0, 'c'}, {"cmplst", required_argument, 0, 'C'}, {"dcrt", no_argument, 0, 'D'}, {"early", no_argument, 0, 'e'}, {"fmtpinfo", required_argument, 0, 'f'}, {"format", no_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"ip_def", no_argument, 0, 'I'}, {"long", no_argument, 0, 'l'}, {"mode", required_argument, 0, 'M'}, {"pinfo", no_argument, 0, 'p'}, {"pfu", required_argument, 0, 'P'}, {"pie", required_argument, 0, 'q'}, {"poll", required_argument, 0, 'x'}, {"resize", no_argument, 0, 'r'}, {"rto_req", no_argument, 0, 'R'}, {"security", no_argument, 0, 'S'}, {"six", no_argument, 0, '6'}, {"size", required_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wait", no_argument, 0, 'w'}, {0, 0, 0, 0}, }; static void usage() { printf("usage: sg_format [--cmplst=0|1] [--count=COUNT] [--dcrt] " "[--early]\n" " [--fmtpinfo=FPI] [--format] [--help] " "[--ip_def] [--long]\n" " [--mode=MP] [--pfu=PFU] [--pie=PIE] " "[--pinfo] [--poll=PT]\n" " [--resize] [--rto_req] [--security] " "[--six] [--size=SIZE]\n" " [--verbose] [--version] [--wait] DEVICE\n" " where:\n" " --cmplst=0|1\n" " -C 0|1 sets CMPLST bit in format cdb " "(default: 1)\n" " --count=COUNT|-c COUNT number of blocks to report " "after format or\n" " resize. Format default is " "same as current\n" " --dcrt|-D disable certification (doesn't " "verify media)\n" " --early|-e exit once format started (user can " "monitor progress)\n" " --fmtpinfo=FPI|-f FPI FMTPINFO field value " "(default: 0)\n" " --format|-F format unit (default: report current " "count and size)\n" " use thrice for FORMAT UNIT command " "only\n" " --help|-h prints out this usage message\n" " --ip_def|-I initialization pattern: default\n" " --long|-l allow for 64 bit lbas (default: assume " "32 bit lbas)\n" " --mode=MP|-M MP mode page (def: 1 -> RW error " "recovery mpage)\n" " --pie=PIE|-q PIE Protection Information Exponent " "(default: 0)\n" " --pinfo|-p set upper bit of FMTPINFO field\n" " (deprecated, use '--fmtpinfo=FPI' " "instead)\n" " --poll=PT|-x PT PT is poll type, 0 for test unit " "ready\n" " 1 for request sense (def: 0 (in " "future will be 1))\n"); printf(" --resize|-r resize (rather than format) to COUNT " "value\n" " --rto_req|-R set lower bit of FMTPINFO field\n" " (deprecated use '--fmtpinfo=FPI' " "instead)\n" " --security|-S set security initialization (SI) bit\n" " --six|-6 use 6 byte MODE SENSE/SELECT to probe " "disk\n" " (def: use 10 byte MODE SENSE/SELECT)\n" " --size=SIZE|-s SIZE bytes per logical block, " "defaults to DEVICE's\n" " current logical block size. Only " "needed to\n" " change current logical block " "size\n" " --verbose|-v increase verbosity\n" " --version|-V print version details and exit\n" " --wait|-w format command waits until format " "operation completes\n" " (default: set IMMED=1 and poll with " "Test Unit Ready)\n\n" "\tExample: sg_format --format /dev/sdc\n\n" "This utility formats or resizes a SCSI disk.\n"); printf("WARNING: This utility will destroy all the data on " "DEVICE when\n\t '--format' is given. Check that you " "have the correct DEVICE.\n"); } /* Return 0 on success, else see sg_ll_format_unit() */ static int scsi_format(int fd, int fmtpinfo, int cmplst, int pf_usage, int immed, int dcrt, int pie, int ip_def, int sec_init, int early, int pt, int verbose) { int res, need_hdr, progress, pr, rem, verb, fmt_pl_sz, longlist, off; int resp_len, ip_desc; const int SH_FORMAT_HEADER_SZ = 4; const int LO_FORMAT_HEADER_SZ = 8; const char INIT_PATTERN_DESC_SZ = 4; unsigned char fmt_pl[LO_FORMAT_HEADER_SZ + INIT_PATTERN_DESC_SZ]; unsigned char reqSense[MAX_BUFF_SZ]; char b[80]; memset(fmt_pl, 0, sizeof(fmt_pl)); longlist = (pie > 0); ip_desc = (ip_def || sec_init); off = longlist ? LO_FORMAT_HEADER_SZ : SH_FORMAT_HEADER_SZ; fmt_pl[0] = pf_usage & 0x7; /* PROTECTION_FIELD_USAGE (bits 2-0) */ fmt_pl[1] = (immed ? 0x2 : 0); /* FOV=0, [DPRY,DCRT,STPF,IP=0] */ if (dcrt) fmt_pl[1] |= 0xa0; /* FOV=1, DCRT=1 */ if (ip_desc) { fmt_pl[1] |= 0x88; /* FOV=1, IP=1 */ if (sec_init) fmt_pl[off + 0] = 0x20; /* SI=1 in IP desc */ } if (longlist) fmt_pl[3] = (pie & 0xf); /* PROTECTION_INTERVAL_EXPONENT */ /* with the long parameter list header, P_I_INFORMATION is always 0 */ need_hdr = (immed || cmplst || dcrt || ip_desc || (pf_usage > 0) || (pie > 0)); fmt_pl_sz = 0; if (need_hdr) fmt_pl_sz = off + (ip_desc ? INIT_PATTERN_DESC_SZ : 0); res = sg_ll_format_unit(fd, fmtpinfo, longlist, need_hdr /* FMTDATA*/, cmplst, 0 /* DEFECT_LIST_FORMAT */, (immed ? SHORT_TIMEOUT : FORMAT_TIMEOUT), fmt_pl, fmt_pl_sz, 1, verbose); if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Format command: %s\n", b); return res; } if (! immed) return 0; printf("\nFormat has started\n"); if (early) { if (immed) printf("Format continuing,\n request sense or " "test unit ready can be used to monitor " "progress\n"); return 0; } verb = (verbose > 1) ? (verbose - 1) : 0; if (0 == pt) { for(;;) { sleep_for(POLL_DURATION_SECS); progress = -1; res = sg_ll_test_unit_ready_progress(fd, 0, &progress, 1, verb); if (progress >= 0) { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("Format in progress, %d.%02d%% done\n", pr, rem); } else break; } } if (pt || (SG_LIB_CAT_NOT_READY == res)) { for(;;) { sleep_for(POLL_DURATION_SECS); memset(reqSense, 0x0, sizeof(reqSense)); res = sg_ll_request_sense(fd, 0, reqSense, sizeof(reqSense), 0, verb); if (res) { fprintf(stderr, "polling with Request Sense " "command failed [res=%d]\n", res); break; } resp_len = reqSense[7] + 8; if (verb) { fprintf(stderr, "Parameter data in hex:\n"); dStrHexErr((const char *)reqSense, resp_len, 1); } progress = -1; sg_get_sense_progress_fld(reqSense, resp_len, &progress); if (progress >= 0) { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("Format in progress, %d.%02d%% done\n", pr, rem); } else break; } } #if 0 for (k = 0; k < num_rs; ++k) { if (k > 0) sleep_for(30); memset(requestSenseBuff, 0x0, sizeof(requestSenseBuff)); res = sg_ll_request_sense(sg_fd, desc, requestSenseBuff, maxlen, 1, verbose); if (res) { ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Request Sense command: %s\n", b); break; } /* "Additional sense length" same in descriptor and fixed */ resp_len = requestSenseBuff[7] + 8; if (verbose > 1) { fprintf(stderr, "Parameter data in hex\n"); dStrHexErr((const char *)requestSenseBuff, resp_len, 1); } progress = -1; sg_get_sense_progress_fld(requestSenseBuff, resp_len, &progress); if (progress < 0) { ret = res; if (verbose > 1) fprintf(stderr, "No progress indication found, " "iteration %d\n", k + 1); /* N.B. exits first time there isn't a progress indication */ break; } else printf("Progress indication: %d.%02d%% done\n", (progress * 100) / 65536, ((progress * 100) % 65536) / 656); } #endif printf("FORMAT Complete\n"); return 0; } #define VPD_DEVICE_ID 0x83 #define VPD_ASSOC_LU 0 #define VPD_ASSOC_TPORT 1 #define TPROTO_ISCSI 5 static char * get_lu_name(const unsigned char * ucp, int u_len, char * b, int b_len) { int len, off, sns_dlen, dlen, k; unsigned char u_sns[512]; char * cp; len = u_len - 4; ucp += 4; off = -1; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { sns_dlen = ucp[off + 3]; memcpy(u_sns, ucp + off + 4, sns_dlen); /* now want to check if this is iSCSI */ off = -1; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_TPORT, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { if ((0x80 & ucp[1]) && (TPROTO_ISCSI == (ucp[0] >> 4))) { snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } } } else sns_dlen = 0; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 3 /* NAA */, 1 /* binary */)) { dlen = ucp[off + 3]; if (! ((8 == dlen) || (16 ==dlen))) return b; cp = b; for (k = 0; ((k < dlen) && (b_len > 1)); ++k) { snprintf(cp, b_len, "%02x", ucp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 2 /* EUI */, 1 /* binary */)) { dlen = ucp[off + 3]; if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen))) return b; cp = b; for (k = 0; ((k < dlen) && (b_len > 1)); ++k) { snprintf(cp, b_len, "%02x", ucp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (sns_dlen > 0) snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } #define SAFE_STD_INQ_RESP_LEN 36 #define VPD_SUPPORTED_VPDS 0x0 #define VPD_UNIT_SERIAL_NUM 0x80 #define VPD_DEVICE_ID 0x83 static int print_dev_id(int fd, unsigned char * sinq_resp, int max_rlen, int verbose) { int res, k, n, verb, pdt, has_sn, has_di; unsigned char b[256]; char a[256]; char pdt_name[64]; verb = (verbose > 1) ? verbose - 1 : 0; memset(sinq_resp, 0, max_rlen); res = sg_ll_inquiry(fd, 0, 0 /* evpd */, 0 /* pg_op */, b, SAFE_STD_INQ_RESP_LEN, 1, verb); if (res) return res; n = b[4] + 5; if (n > SAFE_STD_INQ_RESP_LEN) n = SAFE_STD_INQ_RESP_LEN; memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen); if (n == SAFE_STD_INQ_RESP_LEN) { pdt = b[0] & 0x1f; printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", (const char *)(b + 8), (const char *)(b + 16), (const char *)(b + 32), sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt); if (verbose) printf(" PROTECT=%d\n", !!(b[5] & 1)); if (b[5] & 1) printf(" << supports protection information>>" "\n"); } else { fprintf(stderr, "Short INQUIRY response: %d bytes, expect at " "least " "36\n", n); return SG_LIB_CAT_OTHER; } res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_SUPPORTED_VPDS, b, SAFE_STD_INQ_RESP_LEN, 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS gave res=%d\n", res); return 0; } if (VPD_SUPPORTED_VPDS != b[1]) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (SAFE_STD_INQ_RESP_LEN - 4)) n = (SAFE_STD_INQ_RESP_LEN - 4); for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) { if (VPD_UNIT_SERIAL_NUM == b[4 + k]) { if (has_di) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS " "dis-ordered\n"); return 0; } ++has_sn; } else if (VPD_DEVICE_ID == b[4 + k]) { ++has_di; break; } } if (has_sn) { res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_UNIT_SERIAL_NUM, b, sizeof(b), 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_UNIT_SERIAL_NUM gave " "res=%d\n", res); return 0; } if (VPD_UNIT_SERIAL_NUM != b[1]) { if (verbose) fprintf(stderr, "VPD_UNIT_SERIAL_NUM " "corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (int)(sizeof(b) - 4)) n = (sizeof(b) - 4); printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4)); } if (has_di) { res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_DEVICE_ID, b, sizeof(b), 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_DEVICE_ID gave res=%d\n", res); return 0; } if (VPD_DEVICE_ID != b[1]) { if (verbose) fprintf(stderr, "VPD_DEVICE_ID corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (int)(sizeof(b) - 4)) n = (sizeof(b) - 4); n = strlen(get_lu_name(b, n + 4, a, sizeof(a))); if (n > 0) printf(" LU name: %.*s\n", n, a); } return 0; } #define RCAP_REPLY_LEN 32 /* Returns block size or -2 if do_16==0 and the number of blocks is too * big, or returns -1 for other error. */ static int print_read_cap(int fd, int do_16, int verbose) { int res, k; unsigned char resp_buff[RCAP_REPLY_LEN]; unsigned int last_blk_addr, block_size; uint64_t llast_blk_addr; char b[80]; if (do_16) { res = sg_ll_readcap_16(fd, 0 /* pmi */, 0 /* llba */, resp_buff, 32, 1, verbose); if (0 == res) { for (k = 0, llast_blk_addr = 0; k < 8; ++k) { llast_blk_addr <<= 8; llast_blk_addr |= resp_buff[k]; } block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) | (resp_buff[10] << 8) | resp_buff[11]); printf("Read Capacity (16) results:\n"); printf(" Protection: prot_en=%d, p_type=%d, " "p_i_exponent=%d\n", !!(resp_buff[12] & 0x1), ((resp_buff[12] >> 1) & 0x7), ((resp_buff[13] >> 4) & 0xf)); printf(" Logical block provisioning: lbpme=%d, " "lbprz=%d\n", !!(resp_buff[14] & 0x80), !!(resp_buff[14] & 0x40)); printf(" Logical blocks per physical block " "exponent=%d\n", resp_buff[13] & 0xf); printf(" Lowest aligned logical block address=%d\n", ((resp_buff[14] & 0x3f) << 8) + resp_buff[15]); printf(" Number of logical blocks=%" PRIu64 "\n", llast_blk_addr + 1); printf(" Logical block size=%u bytes\n", block_size); return (int)block_size; } } else { res = sg_ll_readcap_10(fd, 0 /* pmi */, 0 /* lba */, resp_buff, 8, 1, verbose); if (0 == res) { last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) | (resp_buff[2] << 8) | resp_buff[3]); block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) | (resp_buff[6] << 8) | resp_buff[7]); if (0xffffffff == last_blk_addr) { if (verbose) printf("Read Capacity (10) reponse " "indicates that Read Capacity (16) " "is required\n"); return -2; } printf("Read Capacity (10) results:\n"); printf(" Number of logical blocks=%u\n", last_blk_addr + 1); printf(" Logical block size=%u bytes\n", block_size); return (int)block_size; } } sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "READ CAPACITY (%d): %s\n", (do_16 ? 16 : 10), b); return -1; } int main(int argc, char **argv) { int mode_page = RW_ERROR_RECOVERY_PAGE; int fd, res, calc_len, bd_len, dev_specific_param; int offset, j, bd_blk_len, prob, len, pdt; uint64_t ull; int64_t blk_count = 0; /* -c value */ int blk_size = 0; /* -s value */ int format = 0; /* -F */ int ip_def = 0; /* -I */ int resize = 0; /* -r */ int verbose = 0; /* -v */ int fwait = 0; /* -w */ int mode6 = 0; int fmtpinfo = 0; int pinfo = 0; /* deprecated, prefer fmtpinfo */ int pie = 0; int pfu = 0; int pt = DEF_POLL_TYPE; int rto_req = 0; /* deprecated, prefer fmtpinfo */ int cmplst = 1; int do_rcap16 = 0; int long_lba = 0; int dcrt = 0; int do_si = 0; int early = 0; const char * device_name = NULL; char b[80]; unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN]; int ret = 0; while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, "c:C:Def:FhIlM:pP:q:rRs:SvVwx:6", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': if (0 == strcmp("-1", optarg)) blk_count = -1; else { blk_count = sg_get_llnum(optarg); if (-1 == blk_count) { fprintf(stderr, "bad argument to " "'--count'\n"); return SG_LIB_SYNTAX_ERROR; } } break; case 'C': cmplst = sg_get_num(optarg); if ((cmplst < 0) || ( cmplst > 1)) { fprintf(stderr, "bad argument to '--cmplst', " "want 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'D': dcrt = 1; break; case 'e': early = 1; break; case 'f': fmtpinfo = sg_get_num(optarg); if ((fmtpinfo < 0) || ( fmtpinfo > 3)) { fprintf(stderr, "bad argument to " "'--fmtpinfo', accepts 0 to 3 " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'F': ++format; break; case 'h': usage(); return 0; case 'I': ip_def = 1; break; case 'l': long_lba = 1; do_rcap16 = 1; break; case 'M': mode_page = sg_get_num(optarg); if ((mode_page < 0) || ( mode_page > 62)) { fprintf(stderr, "bad argument to '--mode', " "accepts 0 to 62 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': pinfo = 1; break; case 'P': pfu = sg_get_num(optarg); if ((pfu < 0) || ( pfu > 7)) { fprintf(stderr, "bad argument to '--pfu', " "accepts 0 to 7 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'q': pie = sg_get_num(optarg); if ((pie < 0) || ( pie > 15)) { fprintf(stderr, "bad argument to '--pie', " "accepts 0 to 15 inclusive\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': resize = 1; break; case 'R': rto_req = 1; break; case 's': blk_size = sg_get_num(optarg); if (blk_size <= 0) { fprintf(stderr, "bad argument to '--size', " "want arg > 0\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'S': do_si = 1; break; case 'v': verbose++; break; case 'V': fprintf(stderr, "sg_format version: %s\n", version_str); return 0; case 'w': fwait = 1; break; case 'x': pt = !!sg_get_num(optarg); break; case '6': mode6 = 1; break; default: usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } if (NULL == device_name) { fprintf(stderr, "no DEVICE name given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (ip_def && do_si) { fprintf(stderr, "'--ip_def' and '--security' contradict, " "choose one\n"); return SG_LIB_SYNTAX_ERROR; } if (resize) { if (format) { fprintf(stderr, "both '--format' and '--resize'" "not permitted\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else if (0 == blk_count) { fprintf(stderr, "'--resize' needs a '--count' (other" " than 0)\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else if (0 != blk_size) { fprintf(stderr, "'--resize' not compatible with " "'--size'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } if ((pinfo > 0) || (rto_req > 0) || (fmtpinfo > 0)) { if ((pinfo || rto_req) && fmtpinfo) { fprintf(stderr, "confusing with both '--pinfo' or " "'--rto_req' together with\n'--fmtpinfo', " "best use '--fmtpinfo' only\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (pinfo) fmtpinfo |= 2; if (rto_req) fmtpinfo |= 1; } if ((fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose)) < 0) { fprintf(stderr, "error opening device file: %s: %s\n", device_name, safe_strerror(-fd)); return SG_LIB_FILE_ERROR; } if (format > 2) goto format_only; ret = print_dev_id(fd, inq_resp, sizeof(inq_resp), verbose); if (ret) goto out; pdt = 0x1f & inq_resp[0]; if ((0 != pdt) && (7 != pdt) && (0xe != pdt)) { fprintf(stderr, "This format is only defined for disks " "(using SBC-2 or RBC) and MO media\n"); ret = SG_LIB_CAT_MALFORMED; goto out; } again_with_long_lba: memset(dbuff, 0, MAX_BUFF_SZ); if (mode6) res = sg_ll_mode_sense6(fd, 0 /* DBD */, 0 /* current */, mode_page, 0 /* subpage */, dbuff, MAX_BUFF_SZ, 1, verbose); else res = sg_ll_mode_sense10(fd, long_lba, 0 /* DBD */, 0 /* current */, mode_page, 0 /* subpage */, dbuff, MAX_BUFF_SZ, 1, verbose); ret = res; if (res) { if (SG_LIB_CAT_ILLEGAL_REQ == res) { if (long_lba && (! mode6)) fprintf(stderr, "bad field in MODE SENSE " "(%d) [longlba flag not supported?]" "\n", (mode6 ? 6 : 10)); else fprintf(stderr, "bad field in MODE SENSE " "(%d) [mode_page %d not supported?]" "\n", (mode6 ? 6 : 10), mode_page); } else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "MODE SENSE (%d) command: %s\n", (mode6 ? 6 : 10), b); } if (0 == verbose) fprintf(stderr, " try '-v' for more " "information\n"); goto out; } if (mode6) { calc_len = dbuff[0] + 1; dev_specific_param = dbuff[2]; bd_len = dbuff[3]; long_lba = 0; offset = 4; /* prepare for mode select */ dbuff[0] = 0; dbuff[1] = 0; dbuff[2] = 0; } else { calc_len = (dbuff[0] << 8) + dbuff[1] + 2; dev_specific_param = dbuff[3]; bd_len = (dbuff[6] << 8) + dbuff[7]; long_lba = (dbuff[4] & 1); offset = 8; /* prepare for mode select */ dbuff[0] = 0; dbuff[1] = 0; dbuff[2] = 0; dbuff[3] = 0; } if ((offset + bd_len) < calc_len) dbuff[offset + bd_len] &= 0x7f; /* clear PS bit in mpage */ prob = 0; bd_blk_len = 0; printf("Mode Sense (block descriptor) data, prior to changes:\n"); if (dev_specific_param & 0x40) printf(" <<< Write Protect (WP) bit set >>>\n"); if (bd_len > 0) { ull = 0; for (j = 0; j < (long_lba ? 8 : 4); ++j) { if (j > 0) ull <<= 8; ull |= dbuff[offset + j]; } if ((0 == long_lba) && (0xffffffff == ull)) { if (verbose) fprintf(stderr, "Mode sense number of " "blocks maxed out, set longlba\n"); long_lba = 1; mode6 = 0; do_rcap16 = 1; goto again_with_long_lba; } if (long_lba) bd_blk_len = (dbuff[offset + 12] << 24) + (dbuff[offset + 13] << 16) + (dbuff[offset + 14] << 8) + dbuff[offset + 15]; else bd_blk_len = (dbuff[offset + 5] << 16) + (dbuff[offset + 6] << 8) + dbuff[offset + 7]; if (long_lba) { printf(" <<< longlba flag set (64 bit lba) >>>\n"); if (bd_len != 16) prob = 1; } else if (bd_len != 8) prob = 1; printf(" Number of blocks=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); printf(" Block size=%d [0x%x]\n", bd_blk_len, bd_blk_len); } else { printf(" No block descriptors present\n"); prob = 1; } if (resize || (format && ((blk_count != 0) || ((blk_size > 0) && (blk_size != bd_blk_len))))) { /* want to run MODE SELECT */ /* Working Draft SCSI Primary Commands - 3 (SPC-3) pg 255 ** ** If the SCSI device doesn't support changing its capacity by changing ** the NUMBER OF BLOCKS field using the MODE SELECT command, the value ** in the NUMBER OF BLOCKS field is ignored. If the device supports changing ** its capacity by changing the NUMBER OF BLOCKS field, then the ** NUMBER OF BLOCKS field is interpreted as follows: ** a) If the number of blocks is set to zero, the device shall retain ** its current capacity if the block size has not changed. If the ** number of blocks is set to zero and the block size has changed, ** the device shall be set to its maximum capacity when the new ** block size takes effect; ** ** b) If the number of blocks is greater than zero and less than or ** equal to its maximum capacity, the device shall be set to that ** number of blocks. If the block size has not changed, the device ** shall not become format corrupted. This capacity setting shall be ** retained through power cycles, hard resets, logical unit resets, ** and I_T nexus losses; ** ** c) If the number of blocks field is set to a value greater than the ** maximum capacity of the device and less than FFFF FFFFh, then the ** command is terminated with a CHECK CONDITION status. The sense key ** is set to ILLEGAL REQUEST. The device shall retain its previous ** block descriptor settings; or ** ** d) If the number of blocks is set to FFFF FFFFh, the device shall be ** set to its maximum capacity. If the block size has not changed, ** the device shall not become format corrupted. This capacity setting ** shall be retained through power cycles, hard resets, logical unit ** resets, and I_T nexus losses. */ if (prob) { fprintf(stderr, "Need to perform MODE SELECT (to " "change number or blocks or block length)\n"); fprintf(stderr, "but (single) block descriptor not " "found in earlier MODE SENSE\n"); ret = SG_LIB_CAT_MALFORMED; goto out; } if (blk_count != 0) { len = (long_lba ? 8 : 4); for (j = 0; j < len; ++j) dbuff[offset + j] = (blk_count >> ((len - j - 1) * 8)) & 0xff; } else if ((blk_size > 0) && (blk_size != bd_blk_len)) { len = (long_lba ? 8 : 4); for (j = 0; j < len; ++j) dbuff[offset + j] = 0; } if ((blk_size > 0) && (blk_size != bd_blk_len)) { if (long_lba) { dbuff[offset + 12] = (blk_size >> 24) & 0xff; dbuff[offset + 13] = (blk_size >> 16) & 0xff; dbuff[offset + 14] = (blk_size >> 8) & 0xff; dbuff[offset + 15] = blk_size & 0xff; } else { dbuff[offset + 5] = (blk_size >> 16) & 0xff; dbuff[offset + 6] = (blk_size >> 8) & 0xff; dbuff[offset + 7] = blk_size & 0xff; } } if (mode6) res = sg_ll_mode_select6(fd, 1 /* PF */, 1 /* SP */, dbuff, calc_len, 1, verbose); else res = sg_ll_mode_select10(fd, 1 /* PF */, 1 /* SP */, dbuff, calc_len, 1, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "MODE SELECT command: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for " "more information\n"); goto out; } } if (resize) { printf("Resize operation seems to have been successful\n"); goto out; } else if (! format) { res = print_read_cap(fd, do_rcap16, verbose); if (-2 == res) { do_rcap16 = 1; res = print_read_cap(fd, do_rcap16, verbose); } if (res < 0) ret = -1; if ((res > 0) && (bd_blk_len > 0) && (res != (int)bd_blk_len)) { printf(" Warning: mode sense and read capacity " "report different block sizes [%d,%d]\n", bd_blk_len, res); printf(" Probably needs format\n"); } printf("No changes made. To format use '--format'. To " "resize use '--resize'\n"); goto out; } if (format) { format_only: #if 1 printf("\nA FORMAT will commence in 15 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); printf("\nA FORMAT will commence in 10 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); printf("\nA FORMAT will commence in 5 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); res = scsi_format(fd, fmtpinfo, cmplst, pfu, ! fwait, dcrt, pie, ip_def, do_si, early, pt, verbose); ret = res; if (res) { fprintf(stderr, "FORMAT failed\n"); if (0 == verbose) fprintf(stderr, " try '-v' for more " "information\n"); } #else fprintf(stderr, "FORMAT ignored, testing\n"); #endif } out: res = sg_cmds_close_device(fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_rmsn.c0000664000175000017500000001271712335513125014763 0ustar douggdougg/* * Copyright (c) 2005-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program was originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI command READ MEDIA SERIAL NUMBER * to the given SCSI device. */ static const char * version_str = "1.10 20140516"; #define SERIAL_NUM_SANITY_LEN (16 * 1024) static struct option long_options[] = { {"help", 0, 0, 'h'}, {"raw", 0, 0, 'r'}, {"readonly", 0, 0, 'R'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_rmsn [--help] [--raw] [--readonly] [--verbose] [--version]\n" " DEVICE\n" " where:\n" " --help|-h print out usage message\n" " --raw|-r output serial number to stdout " "(potentially binary)\n" " --readonly|-R open DEVICE read-only (def: open it " "read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI READ MEDIA SERIAL NUMBER command\n" ); } int main(int argc, char * argv[]) { int sg_fd, res, c, sn_len, n; unsigned char rmsn_buff[4]; unsigned char * ucp = NULL; int raw = 0; int readonly = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hrRvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'r': ++raw; break; case 'R': ++readonly; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(rmsn_buff, 0x0, sizeof(rmsn_buff)); res = sg_ll_read_media_serial_num(sg_fd, rmsn_buff, sizeof(rmsn_buff), 1, verbose); ret = res; if (0 == res) { sn_len = (rmsn_buff[0] << 24) + (rmsn_buff[1] << 16) + (rmsn_buff[2] << 8) + rmsn_buff[3]; if (! raw) printf("Reported serial number length = %d\n", sn_len); if (0 == sn_len) { fprintf(stderr, " This implies the media has no serial " "number\n"); goto err_out; } if (sn_len > SERIAL_NUM_SANITY_LEN) { fprintf(stderr, " That length (%d) seems too long for a " "serial number\n", sn_len); goto err_out; } sn_len += 4; ucp = (unsigned char *)malloc(sn_len); if (NULL == ucp) { fprintf(stderr, " Out of memory (ram)\n"); goto err_out; } res = sg_ll_read_media_serial_num(sg_fd, ucp, sn_len, 1, verbose); if (0 == res) { sn_len = (ucp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3]; if (raw) { if (sn_len > 0) { n = fwrite(ucp + 4, 1, sn_len, stdout); if (n) { ; } /* unused, dummy to suppress warning */ } } else { printf("Serial number:\n"); if (sn_len > 0) dStrHex((const char *)ucp + 4, sn_len, 0); } } } if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Read Media Serial Number: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for more information\n"); } err_out: if (ucp) free(ucp); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_map.c0000664000175000017500000003625312142450532014560 0ustar douggdougg/* Utility program for the Linux OS SCSI generic ("sg") device driver. * 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. This shows the mapping from "sg" devices to other scsi devices (i.e. sd, scd or st) if any. Note: This program requires sg version 2 or better. Version 0.19 20041203 Version 1.02 20050511 - allow for sparse disk name with up to 3 letter SCSI disk device node names (e.g. /dev/sdaaa) [Nate Dailey < Nate dot Dailey at stratus dot com >] */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" static const char * version_str = "1.09 20130507"; static const char * devfs_id = "/dev/.devfsd"; #define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ #define INQUIRY_RESP_INITIAL_LEN 36 #define MAX_SG_DEVS 4096 #define PRESENT_ARRAY_SIZE MAX_SG_DEVS static const char * sysfs_sg_dir = "/sys/class/scsi_generic"; static char gen_index_arr[PRESENT_ARRAY_SIZE]; static int has_sysfs_sg = 0; typedef struct my_map_info { int active; int lin_dev_type; int oth_dev_num; struct sg_scsi_id sg_dat; char vendor[8]; char product[16]; char revision[4]; } my_map_info_t; #define MAX_SD_DEVS (26 + 26*26 + 26*26*26) /* sdX, sdXX, sdXXX */ /* (26 + 676 + 17576) = 18278 */ #define MAX_SR_DEVS 128 #define MAX_ST_DEVS 128 #define MAX_OSST_DEVS 128 #define MAX_ERRORS 5 static my_map_info_t map_arr[MAX_SG_DEVS]; #define LIN_DEV_TYPE_UNKNOWN 0 #define LIN_DEV_TYPE_SD 1 #define LIN_DEV_TYPE_SR 2 #define LIN_DEV_TYPE_ST 3 #define LIN_DEV_TYPE_SCD 4 #define LIN_DEV_TYPE_OSST 5 typedef struct my_scsi_idlun { /* why can't userland see this structure ??? */ int dev_id; int host_unique_id; } My_scsi_idlun; #define EBUFF_SZ 256 static char ebuff[EBUFF_SZ]; static void scan_dev_type(const char * leadin, int max_dev, int do_numeric, int lin_dev_type, int last_sg_ind); static void usage() { printf("Usage: sg_map [-a] [-h] [-i] [-n] [-sd] [-scd or -sr] [-st] " "[-V] [-x]\n"); printf(" where:\n"); printf(" -a do alphabetic scan (ie sga, sgb, sgc)\n"); printf(" -h or -? show this usage message then exit\n"); printf(" -i also show device INQUIRY strings\n"); printf(" -n do numeric scan (i.e. sg0, sg1, sg2) " "(default)\n"); printf(" -sd show mapping to disks\n"); printf(" -scd show mapping to cdroms (look for /dev/scd\n"); printf(" -sr show mapping to cdroms (look for /dev/sr\n"); printf(" -st show mapping to tapes (st and osst devices)\n"); printf(" -V print version string then exit\n"); printf(" -x also show bus,chan,id,lun and type\n\n"); printf("If no '-s*' arguments given then show all mappings. This " "utility\nis DEPRECATED, do not use in Linux 2.6 series or " "later.\n"); } static int scandir_select(const struct dirent * s) { int k; if (1 == sscanf(s->d_name, "sg%d", &k)) { if ((k >= 0) && (k < PRESENT_ARRAY_SIZE)) { gen_index_arr[k] = 1; return 1; } } return 0; } static int sysfs_sg_scan(const char * dir_name) { struct dirent ** namelist; int num, k; num = scandir(dir_name, &namelist, scandir_select, NULL); if (num < 0) return -errno; for (k = 0; k < num; ++k) free(namelist[k]); free(namelist); return num; } static void make_dev_name(char * fname, const char * leadin, int k, int do_numeric) { char buff[64]; int ones,tens,hundreds; /* for lack of a better name */ int buff_idx; strcpy(fname, leadin ? leadin : "/dev/sg"); if (do_numeric) { sprintf(buff, "%d", k); strcat(fname, buff); } else if (k >= (26 + 26*26 + 26*26*26)) { strcat(fname, "xxxx"); } else { ones = k % 26; if ((k - 26) >= 0) tens = ((k-26)/26) % 26; else tens = -1; if ((k - (26 + 26*26)) >= 0) hundreds = ((k - (26 + 26*26))/(26*26)) % 26; else hundreds = -1; buff_idx = 0; if (hundreds >= 0) buff[buff_idx++] = 'a' + (char)hundreds; if (tens >= 0) buff[buff_idx++] = 'a' + (char)tens; buff[buff_idx++] = 'a' + (char)ones; buff[buff_idx] = '\0'; strcat(fname, buff); } } int main(int argc, char * argv[]) { int sg_fd, res, k; int do_numeric = NUMERIC_SCAN_DEF; int do_all_s = 1; int do_sd = 0; int do_st = 0; int do_osst = 0; int do_sr = 0; int do_scd = 0; int do_extra = 0; int do_inquiry = 0; char fname[64]; int num_errors = 0; int num_silent = 0; int eacces_err = 0; int last_sg_ind = -1; struct stat a_stat; for (k = 1; k < argc; ++k) { if (0 == strcmp("-n", argv[k])) do_numeric = 1; else if (0 == strcmp("-a", argv[k])) do_numeric = 0; else if (0 == strcmp("-x", argv[k])) do_extra = 1; else if (0 == strcmp("-i", argv[k])) do_inquiry = 1; else if (0 == strcmp("-sd", argv[k])) { do_sd = 1; do_all_s = 0; } else if (0 == strcmp("-st", argv[k])) { do_st = 1; do_osst = 1; do_all_s = 0; } else if (0 == strcmp("-sr", argv[k])) { do_sr = 1; do_all_s = 0; } else if (0 == strcmp("-scd", argv[k])) { do_scd = 1; do_all_s = 0; } else if (0 == strcmp("-V", argv[k])) { fprintf(stderr, "Version string: %s\n", version_str); exit(0); } else if ((0 == strcmp("-?", argv[k])) || (0 == strncmp("-h", argv[k], 2))) { printf( "Show mapping from sg devices to other scsi device names\n\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else if (*argv[k] == '-') { printf("Unknown switch: %s\n", argv[k]); usage(); return SG_LIB_SYNTAX_ERROR; } else if (*argv[k] != '-') { printf("Unknown argument\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } if ((stat(sysfs_sg_dir, &a_stat) >= 0) && (S_ISDIR(a_stat.st_mode))) has_sysfs_sg = sysfs_sg_scan(sysfs_sg_dir); if (stat(devfs_id, &a_stat) == 0) printf("# Note: the devfs pseudo file system is present\n"); for (k = 0, res = 0; (k < MAX_SG_DEVS) && (num_errors < MAX_ERRORS); ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { if (res < 0) { snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname); perror("sg_map: close error"); return SG_LIB_FILE_ERROR; } if (has_sysfs_sg) { if (0 == gen_index_arr[k]) { sg_fd = -1; continue; } make_dev_name(fname, "/dev/sg", k, 1); } else make_dev_name(fname, "/dev/sg", k, do_numeric); sg_fd = open(fname, O_RDONLY | O_NONBLOCK); if (sg_fd < 0) { if (EBUSY == errno) { map_arr[k].active = -2; continue; } else if ((ENODEV == errno) || (ENOENT == errno) || (ENXIO == errno)) { ++num_errors; ++num_silent; map_arr[k].active = -1; continue; } else { if (EACCES == errno) eacces_err = 1; snprintf(ebuff, EBUFF_SZ, "Error opening %s ", fname); perror(ebuff); ++num_errors; continue; } } res = ioctl(sg_fd, SG_GET_SCSI_ID, &map_arr[k].sg_dat); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "device %s failed on sg ioctl, skip", fname); perror(ebuff); ++num_errors; continue; } if (do_inquiry) { char buff[INQUIRY_RESP_INITIAL_LEN]; if (0 == sg_ll_inquiry(sg_fd, 0, 0, 0, buff, sizeof(buff), 1, 0)) { memcpy(map_arr[k].vendor, &buff[8], 8); memcpy(map_arr[k].product, &buff[16], 16); memcpy(map_arr[k].revision, &buff[32], 4); } } map_arr[k].active = 1; map_arr[k].oth_dev_num = -1; last_sg_ind = k; } if ((num_errors >= MAX_ERRORS) && (num_silent < num_errors)) { printf("Stopping because there are too many error\n"); if (eacces_err) printf(" root access may be required\n"); return SG_LIB_FILE_ERROR; } if (last_sg_ind < 0) { printf("Stopping because no sg devices found\n"); } if (do_all_s || do_sd) scan_dev_type("/dev/sd", MAX_SD_DEVS, 0, LIN_DEV_TYPE_SD, last_sg_ind); if (do_all_s || do_sr) scan_dev_type("/dev/sr", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SR, last_sg_ind); if (do_all_s || do_scd) scan_dev_type("/dev/scd", MAX_SR_DEVS, 1, LIN_DEV_TYPE_SCD, last_sg_ind); if (do_all_s || do_st) scan_dev_type("/dev/nst", MAX_ST_DEVS, 1, LIN_DEV_TYPE_ST, last_sg_ind); if (do_all_s || do_osst) scan_dev_type("/dev/osst", MAX_OSST_DEVS, 1, LIN_DEV_TYPE_OSST, last_sg_ind); for (k = 0; k <= last_sg_ind; ++k) { if (has_sysfs_sg) { if (0 == gen_index_arr[k]) { continue; } make_dev_name(fname, "/dev/sg", k, 1); } else make_dev_name(fname, "/dev/sg", k, do_numeric); printf("%s", fname); switch (map_arr[k].active) { case -2: printf(do_extra ? " -2 -2 -2 -2 -2" : " busy"); break; case -1: printf(do_extra ? " -1 -1 -1 -1 -1" : " not present"); break; case 0: printf(do_extra ? " -3 -3 -3 -3 -3" : " some error"); break; case 1: if (do_extra) printf(" %d %d %d %d %d", map_arr[k].sg_dat.host_no, map_arr[k].sg_dat.channel, map_arr[k].sg_dat.scsi_id, map_arr[k].sg_dat.lun, map_arr[k].sg_dat.scsi_type); switch (map_arr[k].lin_dev_type) { case LIN_DEV_TYPE_SD: make_dev_name(fname, "/dev/sd" , map_arr[k].oth_dev_num, 0); printf(" %s", fname); break; case LIN_DEV_TYPE_ST: make_dev_name(fname, "/dev/nst" , map_arr[k].oth_dev_num, 1); printf(" %s", fname); break; case LIN_DEV_TYPE_OSST: make_dev_name(fname, "/dev/osst" , map_arr[k].oth_dev_num, 1); printf(" %s", fname); break; case LIN_DEV_TYPE_SR: make_dev_name(fname, "/dev/sr" , map_arr[k].oth_dev_num, 1); printf(" %s", fname); break; case LIN_DEV_TYPE_SCD: make_dev_name(fname, "/dev/scd" , map_arr[k].oth_dev_num, 1); printf(" %s", fname); break; default: break; } if (do_inquiry) printf(" %.8s %.16s %.4s", map_arr[k].vendor, map_arr[k].product, map_arr[k].revision); break; default: printf(" bad logic\n"); break; } printf("\n"); } return 0; } static int find_dev_in_sg_arr(My_scsi_idlun * my_idlun, int host_no, int last_sg_ind) { int k; struct sg_scsi_id * sidp; for (k = 0; k <= last_sg_ind; ++k) { sidp = &(map_arr[k].sg_dat); if ((host_no == sidp->host_no) && ((my_idlun->dev_id & 0xff) == sidp->scsi_id) && (((my_idlun->dev_id >> 8) & 0xff) == sidp->lun) && (((my_idlun->dev_id >> 16) & 0xff) == sidp->channel)) return k; } return -1; } static void scan_dev_type(const char * leadin, int max_dev, int do_numeric, int lin_dev_type, int last_sg_ind) { int k, res, ind, sg_fd = 0; int num_errors = 0; int num_silent = 0; int host_no = -1; My_scsi_idlun my_idlun; char fname[64]; for (k = 0, res = 0; (k < max_dev) && (num_errors < MAX_ERRORS); ++k, res = (sg_fd >= 0) ? close(sg_fd) : 0) { /* ignore close() errors */ #if 0 if (res < 0) { snprintf(ebuff, EBUFF_SZ, "Error closing %s ", fname); perror("sg_map: close error"); #ifndef IGN_CLOSE_ERR return; #else ++num_errors; sg_fd = 0; #endif } #endif make_dev_name(fname, leadin, k, do_numeric); #ifdef DEBUG printf ("Trying %s: ", fname); #endif sg_fd = open(fname, O_RDONLY | O_NONBLOCK); if (sg_fd < 0) { #ifdef DEBUG printf ("ERROR %i\n", errno); #endif if (EBUSY == errno) { printf("Device %s is busy\n", fname); ++num_errors; } else if ((ENODEV == errno) || (ENXIO == errno)) { ++num_errors; ++num_silent; } else if (ENOENT != errno) { /* ignore ENOENT for sparse names */ snprintf(ebuff, EBUFF_SZ, "Error opening %s ", fname); perror(ebuff); ++num_errors; } continue; } res = ioctl(sg_fd, SCSI_IOCTL_GET_IDLUN, &my_idlun); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "device %s failed on scsi ioctl(idlun), skip", fname); perror(ebuff); ++num_errors; #ifdef DEBUG printf ("Couldn't get IDLUN!\n"); #endif continue; } res = ioctl(sg_fd, SCSI_IOCTL_GET_BUS_NUMBER, &host_no); if (res < 0) { snprintf(ebuff, EBUFF_SZ, "device %s failed on scsi ioctl(bus_number), skip", fname); perror(ebuff); ++num_errors; #ifdef DEBUG printf ("Couldn't get BUS!\n"); #endif continue; } #ifdef DEBUG printf ("%i(%x) %i %i %i %i\n", host_no, my_idlun.host_unique_id, (my_idlun.dev_id>>24)&0xff, (my_idlun.dev_id>>16)&0xff, (my_idlun.dev_id>>8)&0xff, my_idlun.dev_id&0xff); #endif ind = find_dev_in_sg_arr(&my_idlun, host_no, last_sg_ind); if (ind >= 0) { map_arr[ind].oth_dev_num = k; map_arr[ind].lin_dev_type = lin_dev_type; } else printf("Strange, could not find device %s mapped to sg device??\n", fname); } } sg3_utils-1.40/src/sg_modes.c0000664000175000017500000013212412357543201015110 0ustar douggdougg/* * Copyright (C) 2000-2014 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. * * This program outputs information provided by a SCSI MODE SENSE command. * Does 10 byte MODE SENSE commands by default, Trent Piepho added a "-6" * switch for force 6 byte mode sense commands. * This utility cannot modify mode pages. See the sdparm utility for that. */ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "1.44 20140708"; #define DEF_ALLOC_LEN (1024 * 4) #define DEF_6_ALLOC_LEN 252 #define PG_CODE_ALL 0x3f #define PG_CODE_MASK 0x3f #define PG_CODE_MAX 0x3f #define SPG_CODE_ALL 0xff #define PROTO_SPECIFIC_1 0x18 #define PROTO_SPECIFIC_2 0x19 #define EBUFF_SZ 256 static struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"control", required_argument, 0, 'c'}, {"dbd", no_argument, 0, 'd'}, {"dbout", no_argument, 0, 'D'}, {"examine", no_argument, 0, 'e'}, {"flexible", no_argument, 0, 'f'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"list", no_argument, 0, 'l'}, {"llbaa", no_argument, 0, 'L'}, {"maxlen", required_argument, 0, 'm'}, {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, {"page", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"six", no_argument, 0, '6'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_all; int do_dbd; int do_dbout; int do_examine; int do_flexible; int do_help; int do_hex; int do_list; int do_llbaa; int maxlen; int do_raw; int do_six; int do_verbose; int do_version; int page_control; int pg_code; int subpg_code; int subpg_code_set; const char * device_name; int opt_new; }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { printf("Usage: sg_modes [--all] [--control=PC] [--dbd] [--dbout] " "[--examine]\n" " [--flexible] [--help] [--hex] [--list] " "[--llbaa]\n" " [--maxlen=LEN] [--page=PG[,SPG]] [--raw] [-R] " "[--six]\n" " [--verbose] [--version] [DEVICE]\n" " where:\n" " --all|-a get all mode pages supported by device\n" " use twice to get all mode pages and subpages\n" " --control=PC|-c PC page control (default: 0)\n" " 0: current, 1: changeable,\n" " 2: (manufacturer's) defaults, 3: saved\n" " --dbd|-d disable block descriptors (DBD field in cdb)\n" " --dbout|-D disable block descriptor output\n" " --examine|-e examine pages # 0 through to 0x3e, note if " "found\n" " --flexible|-f be flexible, cope with MODE SENSE 6/10 " "response mixup\n"); printf(" --help|-h print usage message then exit\n" " --hex|-H output full response in hex\n" " use twice to output page number and header " "in hex\n" " --list|-l list common page codes for device peripheral " "type,\n" " if no device given then assume disk type\n" " --llbaa|-L set Long LBA Accepted (LLBAA field in mode " "sense (10) cdb)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 4096 or 252 (for MODE " "SENSE 6) bytes)\n" " --page=PG|-p PG page code to fetch (def: 63)\n" " --page=PG,SPG|-p PG,SPG\n" " page code and subpage code to fetch " "(defs: 63,0)\n" " --raw|-r output response in binary to stdout\n" " -R mode page response to stdout, a byte per " "line in ASCII\n" " hex (same result as '--raw --raw')\n" " --six|-6 use MODE SENSE(6), by default uses MODE " "SENSE(10)\n" " --verbose|-v increase verbosity\n" " --version|-V output version string then exit\n\n" "Performs a SCSI MODE SENSE (10 or 6) command. To access and " "possibly change\nmode page fields see the sdparm utility.\n"); } static void usage_old() { printf("Usage: sg_modes [-a] [-A] [-c=PC] [-d] [-D] [-e] [-f] [-h] " "[-H] [-l] [-L]\n" " [-m=LEN] [-p=PG[,SPG]] [-r] [-subp=SPG] [-v] " "[-V] [-6]\n" " [DEVICE]\n" " where:\n" " -a get all mode pages supported by device\n" " -A get all mode pages and subpages supported by device\n" " -c=PC page control (def: 0 [current]," " 1 [changeable],\n" " 2 [default], 3 [saved])\n" " -d disable block descriptors (DBD field in cdb)\n" " -D disable block descriptor output\n" " -e examine pages # 0 through to 0x3e, note if found\n" " -f be flexible, cope with MODE SENSE 6/10 response " "mixup\n"); printf(" -h output page number and header in hex\n" " -H output page number and header in hex (same as '-h')\n" " -l list common page codes for device peripheral type,\n" " if no device given then assume disk type\n" " -L set Long LBA Accepted (LLBAA field in mode sense " "10 cdb)\n" " -m=LEN max response length (allocation length in cdb)\n" " (def: 0 -> 4096 or 252 (for MODE SENSE 6) bytes)\n" " -p=PG page code in hex (def: 3f)\n" " -p=PG,SPG both in hex, (defs: 3f,0)\n" " -r mode page output to stdout, a byte per line in " "ASCII hex\n" " -subp=SPG sub page code in hex (def: 0)\n" " -v verbose\n" " -V output version string\n" " -6 Use MODE SENSE(6), by default uses MODE SENSE(10)\n" " -? output this usage message\n\n" "Performs a SCSI MODE SENSE (10 or 6) command\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } /* Processes command line options according to new option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c, n, nn; char * cp; while (1) { int option_index = 0; c = getopt_long(argc, argv, "6aAc:dDefhHlLm:NOp:rRsvV", long_options, &option_index); if (c == -1) break; switch (c) { case '6': ++op->do_six; break; case 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'c': n = sg_get_num(optarg); if ((n < 0) || (n > 3)) { pr2serr("bad argument to '--control='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->page_control = n; break; case 'd': ++op->do_dbd; break; case 'D': ++op->do_dbout; break; case 'e': ++op->do_examine; break; case 'f': ++op->do_flexible; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'l': ++op->do_list; break; case 'L': ++op->do_llbaa; break; case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 65535)) { pr2serr("bad argument to '--maxlen='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->maxlen = n; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': cp = strchr(optarg, ','); n = sg_get_num_nomult(optarg); if ((n < 0) || (n > 63)) { pr2serr("Bad argument to '--page='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (cp) { nn = sg_get_num_nomult(cp + 1); if ((nn < 0) || (nn > 255)) { pr2serr("Bad second value in argument to '--page='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->subpg_code = nn; op->subpg_code_set = 1; } else nn = 0; op->pg_code = n; break; case 'r': ++op->do_raw; break; case 'R': op->do_raw += 2; break; case 's': ++op->do_six; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: pr2serr("unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Processes command line options according to old option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int process_cl_old(struct opts_t * op, int argc, char * argv[]) { int k, jmp_out, plen, num, n; unsigned int u, uu; 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 '6': ++op->do_six; break; case 'a': ++op->do_all; break; case 'A': op->do_all += 2; break; case 'd': ++op->do_dbd; break; case 'D': ++op->do_dbout; break; case 'e': ++op->do_examine; break; case 'f': ++op->do_flexible; break; case 'h': case 'H': op->do_hex += 2; break; case 'l': ++op->do_list; break; case 'L': ++op->do_llbaa; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case 'r': op->do_raw += 2; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case '?': ++op->do_help; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("c=", cp, 2)) { num = sscanf(cp + 2, "%x", &u); if ((1 != num) || (u > 3)) { pr2serr("Bad page control after 'c=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->page_control = u; } else if (0 == strncmp("m=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 0) || (n > 65535)) { pr2serr("Bad argument after 'm=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->maxlen = n; } else if (0 == strncmp("p=", cp, 2)) { if (NULL == strchr(cp + 2, ',')) { num = sscanf(cp + 2, "%x", &u); if ((1 != num) || (u > 63)) { pr2serr("Bad page code value after 'p=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->pg_code = u; } else if (2 == sscanf(cp + 2, "%x,%x", &u, &uu)) { if (uu > 255) { pr2serr("Bad subpage code value after 'p=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->pg_code = u; op->subpg_code = uu; op->subpg_code_set = 1; } else { pr2serr("Bad page code, subpage code sequence after 'p=' " "option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strncmp("subp=", cp, 5)) { num = sscanf(cp + 5, "%x", &u); if ((1 != num) || (u > 255)) { pr2serr("Bad sub page code after 'subp=' option\n"); usage_old(); return SG_LIB_SYNTAX_ERROR; } op->subpg_code = u; op->subpg_code_set = 1; if (-1 == op->pg_code) op->pg_code = 0; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == op->device_name) op->device_name = cp; else { pr2serr("too many arguments, got: %s, not expecting: %s\n", op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Process command line options. First check using new option format unless * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the * old option format to be checked first. Both new and old format can be * countermanded by a '-O' and '-N' options respectively. As soon as either * of these options is detected (when processing the other format), processing * stops and is restarted using the other format. Clear? */ static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } struct page_code_desc { int page_code; int subpage_code; const char * desc; }; static struct page_code_desc pc_desc_common[] = { {0x0, 0x0, "Unit Attention condition [vendor specific format]"}, {0x2, 0x0, "Disconnect-Reconnect"}, {0x9, 0x0, "Peripheral device (obsolete)"}, {0xa, 0x0, "Control"}, {0xa, 0x1, "Control extension"}, {0x15, 0x0, "Extended"}, {0x16, 0x0, "Extended device-type specific"}, {0x18, 0x0, "Protocol specific lu"}, {0x19, 0x0, "Protocol specific port"}, {0x1a, 0x0, "Power condition"}, {0x1a, 0x1, "Power consumption"}, {0x1c, 0x0, "Informational exceptions control"}, {PG_CODE_ALL, 0x0, "[yields all supported pages]"}, {PG_CODE_ALL, SPG_CODE_ALL, "[yields all supported pages and subpages]"}, }; static struct page_code_desc pc_desc_disk[] = { {0x1, 0x0, "Read-Write error recovery"}, {0x3, 0x0, "Format (obsolete)"}, {0x4, 0x0, "Rigid disk geometry (obsolete)"}, {0x5, 0x0, "Flexible geometry (obsolete)"}, {0x7, 0x0, "Verify error recovery"}, {0x8, 0x0, "Caching"}, {0xa, 0x02, "Application tag"}, {0xa, 0xf1, "Parallel ATA control (SAT)"}, {0xa, 0xf2, "Reserved (SATA control) (SAT)"}, {0xb, 0x0, "Medium types supported (obsolete)"}, {0xc, 0x0, "Notch and partition (obsolete)"}, {0xd, 0x0, "Power condition (obsolete, moved to 0x1a)"}, {0x10, 0x0, "XOR control"}, /* obsolete in sbc3r32 */ {0x1a, 0xf1, "ATA Power condition"}, {0x1c, 0x1, "Background control"}, {0x1c, 0x2, "Logical block provisioning"}, }; static struct page_code_desc pc_desc_tape[] = { {0x1, 0x0, "Read-Write error recovery"}, {0xa, 0xf0, "Control data protection"}, {0xf, 0x0, "Data Compression"}, {0x10, 0x0, "Device configuration"}, {0x10, 0x1, "Device configuration extension"}, {0x11, 0x0, "Medium Partition [1]"}, {0x12, 0x0, "Medium Partition [2]"}, {0x13, 0x0, "Medium Partition [3]"}, {0x14, 0x0, "Medium Partition [4]"}, {0x1c, 0x0, "Informational exceptions control (tape version)"}, {0x1d, 0x0, "Medium configuration"}, }; static struct page_code_desc pc_desc_cddvd[] = { {0x1, 0x0, "Read-Write error recovery"}, {0x3, 0x0, "MRW"}, {0x5, 0x0, "Write parameters"}, {0x7, 0x0, "Verify error recovery"}, {0x8, 0x0, "Caching"}, {0xd, 0x0, "CD device parameters (obsolete)"}, {0xe, 0x0, "CD audio"}, {0x1a, 0x0, "Power condition (mmc)"}, {0x1c, 0x0, "Fault/failure reporting control (mmc)"}, {0x1d, 0x0, "Timeout and protect"}, {0x2a, 0x0, "MM capabilities and mechanical status (obsolete)"}, }; static struct page_code_desc pc_desc_smc[] = { {0x1d, 0x0, "Element address assignment"}, {0x1e, 0x0, "Transport geometry parameters"}, {0x1f, 0x0, "Device capabilities"}, {0x1f, 0x41, "Extended device capabilities"}, }; static struct page_code_desc pc_desc_scc[] = { {0x1b, 0x0, "LUN mapping"}, }; static struct page_code_desc pc_desc_ses[] = { {0x14, 0x0, "Enclosure services management"}, }; static struct page_code_desc pc_desc_rbc[] = { {0x6, 0x0, "RBC device parameters"}, }; static struct page_code_desc pc_desc_adc[] = { /* {0xe, 0x0, "ADC device configuration"}, */ {0xe, 0x1, "Target device"}, {0xe, 0x2, "DT device primary port"}, {0xe, 0x3, "Logical unit"}, {0xe, 0x4, "Target device serial number"}, }; static struct page_code_desc * mode_page_cs_table(int scsi_ptype, int * size) { switch (scsi_ptype) { case -1: /* common list */ *size = sizeof(pc_desc_common) / sizeof(pc_desc_common[0]); return &pc_desc_common[0]; case PDT_DISK: /* disk (direct access) type devices */ case PDT_WO: case PDT_OPTICAL: *size = sizeof(pc_desc_disk) / sizeof(pc_desc_disk[0]); return &pc_desc_disk[0]; case PDT_TAPE: /* tape devices */ case PDT_PRINTER: *size = sizeof(pc_desc_tape) / sizeof(pc_desc_tape[0]); return &pc_desc_tape[0]; case PDT_MMC: /* cd/dvd/bd devices */ *size = sizeof(pc_desc_cddvd) / sizeof(pc_desc_cddvd[0]); return &pc_desc_cddvd[0]; case PDT_MCHANGER: /* medium changer devices */ *size = sizeof(pc_desc_smc) / sizeof(pc_desc_smc[0]); return &pc_desc_smc[0]; case PDT_SAC: /* storage array devices */ *size = sizeof(pc_desc_scc) / sizeof(pc_desc_scc[0]); return &pc_desc_scc[0]; case PDT_SES: /* enclosure services devices */ *size = sizeof(pc_desc_ses) / sizeof(pc_desc_ses[0]); return &pc_desc_ses[0]; case PDT_RBC: /* simplified direct access device */ *size = sizeof(pc_desc_rbc) / sizeof(pc_desc_rbc[0]); return &pc_desc_rbc[0]; case PDT_ADC: /* automation device/interface */ *size = sizeof(pc_desc_adc) / sizeof(pc_desc_adc[0]); return &pc_desc_adc[0]; } *size = 0; return NULL; } static struct page_code_desc pc_desc_t_fcp[] = { {0x18, 0x0, "LU control"}, {0x19, 0x0, "Port control"}, }; static struct page_code_desc pc_desc_t_spi4[] = { {0x18, 0x0, "LU control"}, {0x19, 0x0, "Port control short format"}, {0x19, 0x1, "Margin control"}, {0x19, 0x2, "Saved training configuration value"}, {0x19, 0x3, "Negotiated settings"}, {0x19, 0x4, "Report transfer capabilities"}, }; static struct page_code_desc pc_desc_t_sas[] = { {0x18, 0x0, "Protocol specific logical unit (SAS)"}, {0x19, 0x0, "Protocol specific port (SAS)"}, {0x19, 0x1, "Phy control and discover (SAS)"}, {0x19, 0x2, "Shared port control (SAS)"}, {0x19, 0x3, "Enhanced phy control (SAS)"}, }; static struct page_code_desc pc_desc_t_adc[] = { {0xe, 0x1, "Target device"}, {0xe, 0x2, "DT device primary port"}, {0xe, 0x3, "Logical unit"}, {0x18, 0x0, "Protocol specific lu"}, {0x19, 0x0, "Protocol specific port"}, }; static struct page_code_desc * mode_page_transp_table(int t_proto, int * size) { switch (t_proto) { case TPROTO_FCP: *size = sizeof(pc_desc_t_fcp) / sizeof(pc_desc_t_fcp[0]); return &pc_desc_t_fcp[0]; case TPROTO_SPI: *size = sizeof(pc_desc_t_spi4) / sizeof(pc_desc_t_spi4[0]); return &pc_desc_t_spi4[0]; case TPROTO_SAS: *size = sizeof(pc_desc_t_sas) / sizeof(pc_desc_t_sas[0]); return &pc_desc_t_sas[0]; case TPROTO_ADT: *size = sizeof(pc_desc_t_adc) / sizeof(pc_desc_t_adc[0]); return &pc_desc_t_adc[0]; } *size = 0; return NULL; } static const char * find_page_code_desc(int page_num, int subpage_num, int scsi_ptype, int inq_byte6, int t_proto) { int k; int num; const struct page_code_desc * pcdp; if (t_proto >= 0) { pcdp = mode_page_transp_table(t_proto, &num); if (pcdp) { for (k = 0; k < num; ++k, ++pcdp) { if ((page_num == pcdp->page_code) && (subpage_num == pcdp->subpage_code)) return pcdp->desc; else if (page_num < pcdp->page_code) break; } } } pcdp = mode_page_cs_table(scsi_ptype, &num); if (pcdp) { for (k = 0; k < num; ++k, ++pcdp) { if ((page_num == pcdp->page_code) && (subpage_num == pcdp->subpage_code)) return pcdp->desc; else if (page_num < pcdp->page_code) break; } } if ((0xd != scsi_ptype) && (inq_byte6 & 0x40)) { /* check for attached enclosure services processor */ pcdp = mode_page_cs_table(0xd, &num); if (pcdp) { for (k = 0; k < num; ++k, ++pcdp) { if ((page_num == pcdp->page_code) && (subpage_num == pcdp->subpage_code)) return pcdp->desc; else if (page_num < pcdp->page_code) break; } } } if ((0x8 != scsi_ptype) && (inq_byte6 & 0x8)) { /* check for attached medium changer device */ pcdp = mode_page_cs_table(0x8, &num); if (pcdp) { for (k = 0; k < num; ++k, ++pcdp) { if ((page_num == pcdp->page_code) && (subpage_num == pcdp->subpage_code)) return pcdp->desc; else if (page_num < pcdp->page_code) break; } } } pcdp = mode_page_cs_table(-1, &num); for (k = 0; k < num; ++k, ++pcdp) { if ((page_num == pcdp->page_code) && (subpage_num == pcdp->subpage_code)) return pcdp->desc; else if (page_num < pcdp->page_code) break; } return NULL; } static void list_page_codes(int scsi_ptype, int inq_byte6, int t_proto) { int num, num_ptype, pg, spg, c, d, valid_transport; const struct page_code_desc * dp; const struct page_code_desc * pe_dp; char b[64]; valid_transport = ((t_proto >= 0) && (t_proto <= 0xf)) ? 1 : 0; printf("Page[,subpage] Name\n"); printf("=====================\n"); dp = mode_page_cs_table(-1, &num); pe_dp = mode_page_cs_table(scsi_ptype, &num_ptype); while (1) { pg = dp ? dp->page_code : PG_CODE_ALL + 1; spg = dp ? dp->subpage_code : SPG_CODE_ALL; c = (pg << 8) + spg; pg = pe_dp ? pe_dp->page_code : PG_CODE_ALL + 1; spg = pe_dp ? pe_dp->subpage_code : SPG_CODE_ALL; d = (pg << 8) + spg; if (valid_transport && ((PROTO_SPECIFIC_1 == c) || (PROTO_SPECIFIC_2 == c))) dp = (--num <= 0) ? NULL : (dp + 1); /* skip protocol specific */ else if (c == d) { if (pe_dp->subpage_code) printf(" 0x%02x,0x%02x * %s\n", pe_dp->page_code, pe_dp->subpage_code, pe_dp->desc); else printf(" 0x%02x * %s\n", pe_dp->page_code, pe_dp->desc); dp = (--num <= 0) ? NULL : (dp + 1); pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1); } else if (c < d) { if (dp->subpage_code) printf(" 0x%02x,0x%02x %s\n", dp->page_code, dp->subpage_code, dp->desc); else printf(" 0x%02x %s\n", dp->page_code, dp->desc); dp = (--num <= 0) ? NULL : (dp + 1); } else { if (pe_dp->subpage_code) printf(" 0x%02x,0x%02x %s\n", pe_dp->page_code, pe_dp->subpage_code, pe_dp->desc); else printf(" 0x%02x %s\n", pe_dp->page_code, pe_dp->desc); pe_dp = (--num_ptype <= 0) ? NULL : (pe_dp + 1); } if ((NULL == dp) && (NULL == pe_dp)) break; } if ((0xd != scsi_ptype) && (inq_byte6 & 0x40)) { /* check for attached enclosure services processor */ printf("\n Attached enclosure services processor\n"); dp = mode_page_cs_table(0xd, &num); while (dp) { if (dp->subpage_code) printf(" 0x%02x,0x%02x %s\n", dp->page_code, dp->subpage_code, dp->desc); else printf(" 0x%02x %s\n", dp->page_code, dp->desc); dp = (--num <= 0) ? NULL : (dp + 1); } } if ((0x8 != scsi_ptype) && (inq_byte6 & 0x8)) { /* check for attached medium changer device */ printf("\n Attached medium changer device\n"); dp = mode_page_cs_table(0x8, &num); while (dp) { if (dp->subpage_code) printf(" 0x%02x,0x%02x %s\n", dp->page_code, dp->subpage_code, dp->desc); else printf(" 0x%02x %s\n", dp->page_code, dp->desc); dp = (--num <= 0) ? NULL : (dp + 1); } } if (valid_transport) { printf("\n Transport protocol: %s\n", sg_get_trans_proto_str(t_proto, sizeof(b), b)); dp = mode_page_transp_table(t_proto, &num); while (dp) { if (dp->subpage_code) printf(" 0x%02x,0x%02x %s\n", dp->page_code, dp->subpage_code, dp->desc); else printf(" 0x%02x %s\n", dp->page_code, dp->desc); dp = (--num <= 0) ? NULL : (dp + 1); } } } static int examine_pages(int sg_fd, int inq_pdt, int inq_byte6, const struct opts_t * op) { int k, res, header, mresp_len, len; unsigned char rbuf[256]; const char * cp; mresp_len = (op->do_raw || op->do_hex) ? sizeof(rbuf) : 4; for (header = 0, k = 0; k < PG_CODE_MAX; ++k) { if (op->do_six) { res = sg_ll_mode_sense6(sg_fd, 0, 0, k, 0, rbuf, mresp_len, 1, op->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) { pr2serr(">>>>>> try again without the '-6' switch for a 10 " "byte MODE SENSE command\n"); return res; } else if (SG_LIB_CAT_NOT_READY == res) { pr2serr("MODE SENSE (6) failed, device not ready\n"); return res; } } else { res = sg_ll_mode_sense10(sg_fd, 0, 0, 0, k, 0, rbuf, mresp_len, 1, op->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) { pr2serr(">>>>>> try again with a '-6' switch for a 6 byte " "MODE SENSE command\n"); return res; } else if (SG_LIB_CAT_NOT_READY == res) { pr2serr("MODE SENSE (10) failed, device not ready\n"); return res; } } if (0 == res) { len = op->do_six ? (rbuf[0] + 1) : ((rbuf[0] << 8) + rbuf[1] + 2); if (len > mresp_len) len = mresp_len; if (op->do_raw) { dStrRaw((const char *)rbuf, len); continue; } if (0 == header) { printf("Discovered mode pages:\n"); header = 1; } cp = find_page_code_desc(k, 0, inq_pdt, inq_byte6, -1); if (cp) printf(" %s\n", cp); else printf(" [0x%x]\n", k); if (op->do_hex) dStrHex((const char *)rbuf, len, 1); } else if (op->do_verbose) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose - 1); pr2serr("MODE SENSE (%s) failed: %s\n", (op->do_six ? "6" : "10"), b); } } return res; } static const char * pg_control_str_arr[] = { "current", "changeable", "default", "saved", }; int main(int argc, char * argv[]) { int sg_fd, k, num, len, res, md_len, bd_len, longlba, page_num, spf; char ebuff[EBUFF_SZ]; const char * descp; unsigned char * rsp_buff = NULL; unsigned char def_rsp_buff[DEF_ALLOC_LEN]; unsigned char * malloc_rsp_buff = NULL; int rsp_buff_size = DEF_ALLOC_LEN; int ret = 0; int density_code_off, t_proto, inq_pdt, inq_byte6, resp_mode6; int num_ua_pages; unsigned char * ucp; unsigned char uc; struct sg_simple_inquiry_resp inq_out; char pdt_name[64]; char b[80]; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->pg_code = -1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } if (op->do_version) { pr2serr("Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { if (op->do_list) { if ((op->pg_code < 0) || (op->pg_code > PG_CODE_MAX)) { printf(" Assume peripheral device type: disk\n"); list_page_codes(0, 0, -1); } else { printf(" peripheral device type: %s\n", sg_get_pdt_str(op->pg_code, sizeof(pdt_name), pdt_name)); if (op->subpg_code_set) list_page_codes(op->pg_code, 0, op->subpg_code); else list_page_codes(op->pg_code, 0, -1); } return 0; } pr2serr("No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_examine && (op->pg_code >= 0)) { pr2serr("can't give '-e' and a page number\n"); return SG_LIB_SYNTAX_ERROR; } if ((op->do_six) && (op->do_llbaa)) { pr2serr("LLBAA not defined for MODE SENSE 6, try without '-L'\n"); return SG_LIB_SYNTAX_ERROR; } if (op->maxlen > 0) { if (op->do_six && (op->maxlen > 255)) { pr2serr("For Mode Sense (6) maxlen cannot exceed 255\n"); return SG_LIB_SYNTAX_ERROR; } if (op->maxlen > DEF_ALLOC_LEN) { malloc_rsp_buff = (unsigned char *)malloc(op->maxlen); if (NULL == malloc_rsp_buff) { pr2serr("Unable to malloc maxlen=%d bytes\n", op->maxlen); return SG_LIB_SYNTAX_ERROR; } rsp_buff = malloc_rsp_buff; } else rsp_buff = def_rsp_buff; rsp_buff_size = op->maxlen; } else { /* maxlen == 0 */ rsp_buff_size = op->do_six ? DEF_6_ALLOC_LEN : DEF_ALLOC_LEN; rsp_buff = def_rsp_buff; } /* If no pages or list selected than treat as 'a' */ if (! ((op->pg_code >= 0) || op->do_all || op->do_list || op->do_examine)) op->do_all = 1; if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->do_verbose)) < 0) { pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); if (malloc_rsp_buff) free(malloc_rsp_buff); return SG_LIB_FILE_ERROR; } if (sg_simple_inquiry(sg_fd, &inq_out, 1, op->do_verbose)) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->device_name); ret = SG_LIB_CAT_OTHER; goto finish; } inq_pdt = inq_out.peripheral_type; inq_byte6 = inq_out.byte_6; if (0 == op->do_raw) printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", inq_out.vendor, inq_out.product, inq_out.revision, sg_get_pdt_str(inq_pdt, sizeof(pdt_name), pdt_name), inq_pdt); if (op->do_list) { if (op->subpg_code_set) list_page_codes(inq_pdt, inq_byte6, op->subpg_code); else list_page_codes(inq_pdt, inq_byte6, -1); goto finish; } if (op->do_examine) { ret = examine_pages(sg_fd, inq_pdt, inq_byte6, op); goto finish; } if (PG_CODE_ALL == op->pg_code) { if (0 == op->do_all) ++op->do_all; } else if (op->do_all) op->pg_code = PG_CODE_ALL; if (op->do_all > 1) op->subpg_code = SPG_CODE_ALL; if (op->do_raw > 1) { if (op->do_all) { if (op->opt_new) pr2serr("'-R' requires a specific (sub)page, not all\n"); else pr2serr("'-r' requires a specific (sub)page, not all\n"); usage_for(op); ret = SG_LIB_SYNTAX_ERROR; goto finish; } } memset(rsp_buff, 0, rsp_buff_size); if (op->do_six) { res = sg_ll_mode_sense6(sg_fd, op->do_dbd, op->page_control, op->pg_code, op->subpg_code, rsp_buff, rsp_buff_size, 1, op->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) pr2serr(">>>>>> try again without the '-6' switch for a 10 byte " "MODE SENSE command\n"); } else { res = sg_ll_mode_sense10(sg_fd, op->do_llbaa, op->do_dbd, op->page_control, op->pg_code, op->subpg_code, rsp_buff, rsp_buff_size, 1, op->do_verbose); if (SG_LIB_CAT_INVALID_OP == res) pr2serr(">>>>>> try again with a '-6' switch for a 6 byte MODE " "SENSE command\n"); } if (SG_LIB_CAT_ILLEGAL_REQ == res) { if (op->subpg_code > 0) pr2serr("invalid field in cdb (perhaps subpages not " "supported)\n"); else if (op->page_control > 0) pr2serr("invalid field in cdb (perhaps page control (PC) not " "supported)\n"); else pr2serr("invalid field in cdb (perhaps page 0x%x not " "supported)\n", op->pg_code); } else if (res) { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); pr2serr("%s\n", b); } ret = res; if (0 == res) { int medium_type, specific, headerlen; ret = 0; resp_mode6 = op->do_six; if (op->do_flexible) { num = rsp_buff[0]; if (op->do_six && (num < 3)) resp_mode6 = 0; if ((0 == op->do_six) && (num > 5)) { if ((num > 11) && (0 == (num % 2)) && (0 == rsp_buff[4]) && (0 == rsp_buff[5]) && (0 == rsp_buff[6])) { rsp_buff[1] = num; rsp_buff[0] = 0; pr2serr(">>> msense(10) but resp[0]=%d and not msense(6) " "response so fix length\n", num); } else resp_mode6 = 1; } } if ((! op->do_raw) && (1 != op->do_hex)) { if (resp_mode6 == op->do_six) printf("Mode parameter header from MODE SENSE(%s):\n", (op->do_six ? "6" : "10")); else printf(" >>> Mode parameter header from MODE SENSE(%s),\n" " decoded as %s byte response:\n", (op->do_six ? "6" : "10"), (resp_mode6 ? "6" : "10")); } if (resp_mode6) { headerlen = 4; md_len = rsp_buff[0] + 1; bd_len = rsp_buff[3]; medium_type = rsp_buff[1]; specific = rsp_buff[2]; longlba = 0; } else { headerlen = 8; md_len = (rsp_buff[0] << 8) + rsp_buff[1] + 2; bd_len = (rsp_buff[6] << 8) + rsp_buff[7]; medium_type = rsp_buff[2]; specific = rsp_buff[3]; longlba = rsp_buff[4] & 1; } if ((bd_len + headerlen) > md_len) { pr2serr("Invalid block descriptor length=%d, ignore\n", bd_len); bd_len = 0; } if (op->do_raw) { if (1 == op->do_raw) dStrRaw((const char *)rsp_buff, md_len); else { ucp = rsp_buff + bd_len + headerlen; md_len -= bd_len + headerlen; spf = ((ucp[0] & 0x40) ? 1 : 0); len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2)); len = (len < md_len) ? len : md_len; for (k = 0; k < len; ++k) printf("%02x\n", ucp[k]); } goto finish; } if (1 == op->do_hex) { dStrHex((const char *)rsp_buff, md_len, 1); goto finish; } else if (op->do_hex > 1) dStrHex((const char *)rsp_buff, headerlen, 1); if (0 == inq_pdt) printf(" Mode data length=%d, medium type=0x%.2x, WP=%d," " DpoFua=%d, longlba=%d\n", md_len, medium_type, !!(specific & 0x80), !!(specific & 0x10), longlba); else printf(" Mode data length=%d, medium type=0x%.2x, specific" " param=0x%.2x, longlba=%d\n", md_len, medium_type, specific, longlba); if (md_len > rsp_buff_size) { printf("Only fetched %d bytes of response, truncate output\n", rsp_buff_size); md_len = rsp_buff_size; if (bd_len + headerlen > rsp_buff_size) bd_len = rsp_buff_size - headerlen; } if (! op->do_dbout) { printf(" Block descriptor length=%d\n", bd_len); if (bd_len > 0) { len = 8; density_code_off = 0; num = bd_len; if (longlba) { printf("> longlba direct access device block " "descriptors:\n"); len = 16; density_code_off = 8; } else if (0 == inq_pdt) { printf("> Direct access device block descriptors:\n"); density_code_off = 4; } else printf("> General mode parameter block descriptors:\n"); ucp = rsp_buff + headerlen; while (num > 0) { printf(" Density code=0x%x\n", *(ucp + density_code_off)); dStrHex((const char *)ucp, len, 1); ucp += len; num -= len; } printf("\n"); } } ucp = rsp_buff + bd_len + headerlen; /* start of mode page(s) */ md_len -= bd_len + headerlen; /* length of mode page(s) */ num_ua_pages = 0; for (k = 0; md_len > 0; ++k) { /* got mode page(s) */ if ((k > 0) && (! op->do_all) && (SPG_CODE_ALL != op->subpg_code)) { pr2serr("Unexpectedly received extra mode page responses, " "ignore\n"); break; } uc = *ucp; spf = ((uc & 0x40) ? 1 : 0); len = (spf ? ((ucp[2] << 8) + ucp[3] + 4) : (ucp[1] + 2)); page_num = ucp[0] & PG_CODE_MASK; if (0x0 == page_num) { ++num_ua_pages; if((num_ua_pages > 3) && (md_len > 0xa00)) { pr2serr(">>> Seen 3 unit attention pages (only one " "should be at end)\n and mpage length=%d, " "looks malformed, try '-f' option\n", md_len); break; } } if (op->do_hex) { if (spf) printf(">> page_code=0x%x, subpage_code=0x%x, page_cont" "rol=%d\n", page_num, ucp[1], op->page_control); else printf(">> page_code=0x%x, page_control=%d\n", page_num, op->page_control); } else { descp = NULL; if ((0x18 == page_num) || (0x19 == page_num)) { t_proto = (spf ? ucp[5] : ucp[2]) & 0xf; descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0), inq_pdt, inq_byte6, t_proto); } else descp = find_page_code_desc(page_num, (spf ? ucp[1] : 0), inq_pdt, inq_byte6, -1); if (NULL == descp) { if (spf) snprintf(ebuff, EBUFF_SZ, "0x%x, subpage_code: 0x%x", page_num, ucp[1]); else snprintf(ebuff, EBUFF_SZ, "0x%x", page_num); } if (descp) printf(">> %s, page_control: %s\n", descp, pg_control_str_arr[op->page_control]); else printf(">> page_code: %s, page_control: %s\n", ebuff, pg_control_str_arr[op->page_control]); } num = (len > md_len) ? md_len : len; if ((k > 0) && (num > 256)) { num = 256; pr2serr(">>> page length (%d) > 256 bytes, unlikely trim\n" " Try '-f' option\n", len); } dStrHex((const char *)ucp, num , 1); ucp += len; md_len -= len; } } finish: sg_cmds_close_device(sg_fd); if (malloc_rsp_buff) free(malloc_rsp_buff); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_turs.c0000664000175000017500000002571612335161436015010 0ustar douggdougg/* 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-2014 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. * */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifndef SG_LIB_MINGW #include #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "3.30 20140514"; #if defined(MSC_VER) || defined(__MINGW32__) #define HAVE_MS_SLEEP #endif #ifdef HAVE_MS_SLEEP #include #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 * op) { if (op->opt_new) usage(); else usage_old(); } static int process_cl_new(struct opts_t * op, 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 '?': ++op->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; } op->do_number = n; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': ++op->do_progress; break; case 't': ++op->do_time; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->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 * op, 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': op->opt_new = 1; return 0; case 'O': break; case 'p': ++op->do_progress; break; case 't': ++op->do_time; break; case 'v': ++op->do_verbose; break; case 'V': ++op->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)) { op->do_number = sg_get_num(cp + 2); if (op->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 == op->device_name) op->device_name = cp; else { fprintf(stderr, "too many arguments, got: %s, not expecting: " "%s\n", op->device_name, cp); usage_old(); return SG_LIB_SYNTAX_ERROR; } } return 0; } static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } int main(int argc, char * argv[]) { int sg_fd, k, res, progress, pr, rem; int num_errs = 0; int reported = 0; int ret = 0; #ifndef SG_LIB_MINGW struct timeval start_tm, end_tm; #endif struct opts_t opts; struct opts_t * op; char b[80]; op = &opts; memset(op, 0, sizeof(opts)); op->do_number = 1; res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { fprintf(stderr, "No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->do_verbose)) < 0) { fprintf(stderr, "sg_turs: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->do_progress) { for (k = 0; k < op->do_number; ++k) { if (k > 0) sleep_for(30); progress = -1; res = sg_ll_test_unit_ready_progress(sg_fd, k, &progress, ((1 == op->do_number) ? 1 : 0), op->do_verbose); if (progress < 0) { ret = res; break; } else { pr = (progress * 100) / 65536; rem = ((progress * 100) % 65536) / 656; printf("Progress indication: %d.%02d%% done\n", pr, rem); } } if (op->do_number > 1) printf("Completed %d Test Unit Ready commands\n", ((k < op->do_number) ? k + 1 : k)); } else { #ifndef SG_LIB_MINGW if (op->do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } #endif for (k = 0; k < op->do_number; ++k) { /* Might get Unit Attention on first invocation */ res = sg_ll_test_unit_ready(sg_fd, k, (0 == k), op->do_verbose); if (res) { ++num_errs; ret = res; if (1 == op->do_number) { if (SG_LIB_CAT_NOT_READY == res) printf("device not ready\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); printf("%s\n", b); } reported = 1; break; } } } #ifndef SG_LIB_MINGW if ((op->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)op->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 (((op->do_number > 1) || (num_errs > 0)) && (! reported)) printf("Completed %d Test Unit Ready commands with %d errors\n", op->do_number, num_errs); } sg_cmds_close_device(sg_fd); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_reset.c0000664000175000017500000002121012422552302015107 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 1999-2014 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. * * This program send either device, bus or host resets to device, * or bus or host associated with the given sg device. */ #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_io_linux.h" #define ME "sg_reset: " static const char * version_str = "0.59 20141024"; #ifndef SG_SCSI_RESET #define SG_SCSI_RESET 0x2284 #endif #ifndef SG_SCSI_RESET_NOTHING #define SG_SCSI_RESET_NOTHING 0 #define SG_SCSI_RESET_DEVICE 1 #define SG_SCSI_RESET_BUS 2 #define SG_SCSI_RESET_HOST 3 #endif #ifndef SG_SCSI_RESET_TARGET #define SG_SCSI_RESET_TARGET 4 #endif #ifndef SG_SCSI_RESET_NO_ESCALATE #define SG_SCSI_RESET_NO_ESCALATE 0x100 #endif static struct option long_options[] = { {"bus", no_argument, 0, 'b'}, {"device", no_argument, 0, 'd'}, {"help", no_argument, 0, 'z'}, {"host", no_argument, 0, 'H'}, {"no-esc", no_argument, 0, 'N'}, {"no-escalate", no_argument, 0, 'N'}, {"target", no_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage(int compat_mode) { fprintf(stderr, "Usage: " "sg_reset [--bus] [--device] [--help] [--host] [--no-esc] " "[--target]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --bus|-b SCSI bus reset (SPI concept), might be all " "targets\n" " --device|-d device (logical unit) reset\n"); if (compat_mode) { fprintf(stderr, " --help|-z print usage information then exit\n" " --host|-h|-H host (bus adapter: HBA) reset\n"); } else { fprintf(stderr, " --help|-h print usage information then exit\n" " --host|-H host (bus adapter: HBA) reset\n"); } fprintf(stderr, " --no-esc|-N overrides default action and only does " "reset requested\n" " --target|-t target reset. The target holds the DEVICE " "and perhaps\n" " other LUs\n" " --verbose|-v increase the level of verbosity\n" " --version|-V print version number then exit\n\n" "Use SG_SCSI_RESET ioctl to send a reset to the " "host/bus/target/device\nalong the DEVICE path. The DEVICE " "itself is known as a logical unit (LU)\nin SCSI terminology.\n" "Be warned: if the '-N' option is not given then if '-d' " "fails then a\ntarget reset ('-t') is instigated. And it " "'-t' fails then a bus reset\n('-b') is instigated. And if " "'-b' fails then a host reset ('h') is\ninstigated. It is " "recommended to use '-N' to stop the reset escalation.\n" ); } int main(int argc, char * argv[]) { int c, sg_fd, res, k, hold_errno; int do_device_reset = 0; int do_bus_reset = 0; int do_host_reset = 0; int no_escalate = 0; int do_target_reset = 0; int verbose = 0; char * device_name = NULL; char * cp = NULL; cp = getenv("SG3_UTILS_OLD_OPTS"); if (NULL == cp) cp = getenv("SG_RESET_OLD_OPTS"); while (1) { int option_index = 0; c = getopt_long(argc, argv, "bdhHNtvVz", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': ++do_bus_reset; break; case 'd': ++do_device_reset; break; case 'h': if (cp) { ++do_host_reset; break; } else { usage(!!cp); return 0; } case 'H': ++do_host_reset; break; case 'N': ++no_escalate; break; case 't': ++do_target_reset; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'z': usage(!!cp); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(!!cp); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: %s\n", argv[optind]); usage(!!cp); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { fprintf(stderr, "Missing DEVICE name. Use '--help' to see usage.\n"); return SG_LIB_SYNTAX_ERROR; } if (cp && (0 == verbose)) ++verbose; // older behaviour was more verbose if ((!!do_device_reset + !!do_target_reset + !!do_bus_reset + !!do_host_reset) > 1) { fprintf(stderr, "Can only request one type of reset per " "invocation\n"); return 1; } sg_fd = open(device_name, O_RDWR | O_NONBLOCK); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: ", device_name); perror(""); return 1; } k = SG_SCSI_RESET_NOTHING; if (do_device_reset) { if (verbose) printf(ME "starting device reset\n"); k = SG_SCSI_RESET_DEVICE; } else if (do_target_reset) { if (verbose) printf(ME "starting target reset\n"); k = SG_SCSI_RESET_TARGET; } else if (do_bus_reset) { if (verbose) printf(ME "starting bus reset\n"); k = SG_SCSI_RESET_BUS; } else if (do_host_reset) { if (verbose) printf(ME "starting host reset\n"); k = SG_SCSI_RESET_HOST; } if (no_escalate) k += SG_SCSI_RESET_NO_ESCALATE; if (verbose > 2) fprintf(stderr, " third argument to ioctl(SG_SCSI_RESET) is " "0x%x\n", k); res = ioctl(sg_fd, SG_SCSI_RESET, &k); if (res < 0) { hold_errno = errno; switch (errno) { case EBUSY: fprintf(stderr, ME "BUSY, may be resetting now\n"); break; case ENODEV: fprintf(stderr, ME "'no device' error, may be temporary while " "device is resetting\n"); break; case EAGAIN: fprintf(stderr, ME "try again later, may be resetting now\n"); break; case EIO: fprintf(stderr, ME "reset (for value=0x%x) may not be " "available\n", k); break; case EPERM: case EACCES: fprintf(stderr, ME "reset requires CAP_SYS_ADMIN (root) " "permission\n"); break; case EINVAL: fprintf(stderr, ME "SG_SCSI_RESET not supported (for " "value=0x%x)\n", k); default: perror(ME "SG_SCSI_RESET failed"); break; } if (verbose > 1) fprintf(stderr, ME "ioctl(SG_SCSI_RESET) returned %d, errno=%d\n", res, hold_errno); close(sg_fd); return 1; } if (no_escalate) k -= SG_SCSI_RESET_NO_ESCALATE; if (verbose) { if (SG_SCSI_RESET_NOTHING == k) printf(ME "did nothing, device is normal mode\n"); else if (SG_SCSI_RESET_DEVICE == k) printf(ME "completed device %sreset\n", (no_escalate ? "" : "(or target or bus or host) ")); else if (SG_SCSI_RESET_TARGET == k) printf(ME "completed target %sreset\n", (no_escalate ? "" : "(or bus or host) ")); else if (SG_SCSI_RESET_BUS == k) printf(ME "completed bus %sreset\n", (no_escalate ? "" : "(or host) ")); else if (SG_SCSI_RESET_HOST == k) printf(ME "completed host reset\n"); } if (close(sg_fd) < 0) { perror(ME "close error"); return 1; } return 0; } sg3_utils-1.40/src/sg_copy_results.c0000664000175000017500000003660012353021654016535 0ustar douggdougg/* * Copyright (c) 2011-2014 Hannes Reinecke, SUSE Labs * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program for the Linux OS SCSI subsystem. * Copyright (C) 2004-2010 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. This program issues the SCSI command RECEIVE COPY RESULTS to a given SCSI device. It sends the command with the service action passed as the sa argument, and the optional list identifier passed as the list_id argument. */ static const char * version_str = "1.10 20140625"; #define MAX_XFER_LEN 10000 /* #define SG_DEBUG */ #define ME "sg_copy_results: " #define EBUFF_SZ 256 struct descriptor_type { int code; char desc[124]; }; struct descriptor_type target_descriptor_codes[] = { { 0xe0, "Fibre Channel N_Port_Name"}, { 0xe1, "Fibre Channel N_port_ID"}, { 0xe2, "Fibre Channesl N_port_ID with N_Port_Name checking"}, { 0xe3, "Parallel Interface T_L" }, { 0xe4, "Identification descriptor" }, { 0xe5, "IPv4" }, { 0xe6, "Alias" }, { 0xe7, "RDMA" }, { 0xe8, "IEEE 1395 EUI-64" }, { 0xe9, "SAS Serial SCSI Protocol" }, { 0xea, "IPv6" }, { 0xeb, "IP Copy Service" }, { -1, "" } }; struct descriptor_type segment_descriptor_codes [] = { { 0x00, "Copy from block device to stream device" }, { 0x01, "Copy from stream device to block device" }, { 0x02, "Copy from block device to block device" }, { 0x03, "Copy from stream device to stream device" }, { 0x04, "Copy inline data to stream device" }, { 0x05, "Copy embedded data to stream device" }, { 0x06, "Read from stream device and discard" }, { 0x07, "Verify block or stream device operation" }, { 0x08, "Copy block device with offset to stream device" }, { 0x09, "Copy stream device to block device with offset" }, { 0x0A, "Copy block device with offset to block device with offset" }, { 0x0B, "Copy from block device to stream device " "and hold a copy of processed data for the application client" }, { 0x0C, "Copy from stream device to block device " "and hold a copy of processed data for the application client" }, { 0x0D, "Copy from block device to block device " "and hold a copy of processed data for the application client" }, { 0x0E, "Copy from stream device to stream device " "and hold a copy of processed data for the application client" }, { 0x0F, "Read from stream device " "and hold a copy of processed data for the application client" }, { 0x10, "Write filemarks to sequential-access device" }, { 0x11, "Space records or filemarks on sequential-access device" }, { 0x12, "Locate on sequential-access device" }, { 0x13, "Image copy from sequential-access device to sequential-access " "device" }, { 0x14, "Register persistent reservation key" }, { 0x15, "Third party persistent reservations source I_T nexus" }, { -1, "" } }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void scsi_failed_segment_details(unsigned char *rcBuff, unsigned int rcBuffLen) { unsigned int len; char senseBuff[1024]; int senseLen; if (rcBuffLen < 4) { pr2serr(" <>\n"); return; } len = (rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]; if (len + 4 > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } if (len < 52) { pr2serr(" <>\n"); return; } len = (rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]; if (len + 4 > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } printf("Receive copy results (copy status):\n"); printf(" Held data discarded: %s\n", rcBuff[4] & 0x80 ? "Yes":"No"); printf(" Copy manager status: "); switch (rcBuff[4] & 0x7f) { case 0: printf("Operation in progress\n"); break; case 1: printf("Operation completed without errors\n"); break; case 2: printf("Operation completed with errors\n"); break; default: printf("Unknown/Reserved\n"); break; } printf(" Segments processed: %u\n", (rcBuff[5] << 8) | rcBuff[6]); printf(" Transfer count units: %u\n", rcBuff[7]); printf(" Transfer count: %u\n", rcBuff[8] << 24 | rcBuff[9] << 16 | rcBuff[10] << 8 | rcBuff[11]); } static void scsi_operating_parameters(unsigned char *rcBuff, unsigned int rcBuffLen) { unsigned int len, n; len = (rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]; if (len + 4 > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } printf("Receive copy results (report operating parameters):\n"); printf(" Supports no list identifier (SNLID): %s\n", rcBuff[4] & 1 ? "yes" : "no"); n = (rcBuff[8] << 8) | rcBuff[9]; printf(" Maximum target descriptor count: %u\n", n); n = (rcBuff[10] << 8) | rcBuff[11]; printf(" Maximum segment descriptor count: %u\n", n); n = (rcBuff[12] << 24) | (rcBuff[13] << 16) | (rcBuff[14] << 8) | rcBuff[15]; printf(" Maximum descriptor list length: %u bytes\n", n); n = (rcBuff[16] << 24) | (rcBuff[17] << 16) | (rcBuff[18] << 8) | rcBuff[19]; printf(" Maximum segment length: %u bytes\n", n); n = (rcBuff[20] << 24) | (rcBuff[21] << 16) | (rcBuff[22] << 8) | rcBuff[23]; if (n == 0) { printf(" Inline data not supported\n"); } else { printf(" Maximum inline data length: %u bytes\n", n); } n = (rcBuff[24] << 24) | (rcBuff[25] << 16) | (rcBuff[26] << 8) | rcBuff[27]; printf(" Held data limit: %u bytes\n", n); n = (rcBuff[28] << 24) | (rcBuff[29] << 16) | (rcBuff[30] << 8) | rcBuff[31]; printf(" Maximum stream device transfer size: %u bytes\n", n); n = (rcBuff[34] << 8) | rcBuff[35]; printf(" Total concurrent copies: %u\n", n); printf(" Maximum concurrent copies: %u\n", rcBuff[36]); printf(" Data segment granularity: %lu bytes\n", (unsigned long)(1 << rcBuff[37])); printf(" Inline data granularity: %lu bytes\n", (unsigned long)(1 << rcBuff[38])); printf(" Held data granularity: %lu bytes\n", (unsigned long)(1 << rcBuff[39])); printf(" Implemented descriptor list:\n"); for (n = 0; n < rcBuff[43]; n++) { int code = rcBuff[44 + n]; if (code < 0x16) { struct descriptor_type *seg_desc = segment_descriptor_codes; while (strlen(seg_desc->desc)) { if (seg_desc->code == code) break; seg_desc++; } printf(" Segment descriptor 0x%02x: %s\n", code, strlen(seg_desc->desc) ? seg_desc->desc : "Reserved"); } else if (code < 0xc0) { printf(" Segment descriptor 0x%02x: Reserved\n", code); } else if (code < 0xe0) { printf(" Vendor specific descriptor 0x%02x\n", code); } else { struct descriptor_type *tgt_desc = target_descriptor_codes; while (strlen(tgt_desc->desc)) { if (tgt_desc->code == code) break; tgt_desc++; } printf(" Target descriptor 0x%02x: %s\n", code, strlen(tgt_desc->desc) ? tgt_desc->desc : "Reserved"); } } printf("\n"); } static struct option long_options[] = { {"failed", 0, 0, 'f'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"list_id", 1, 0, 'l'}, {"params", 0, 0, 'p'}, {"readonly", 0, 0, 'R'}, {"receive", 0, 0, 'r'}, {"status", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"xfer_len", 1, 0, 'x'}, {0, 0, 0, 0}, }; static void usage() { pr2serr("Usage: " "sg_copy_results [--failed|--params|--receive|--status] [--help]\n" " [--hex] [--list_id=ID] [--readonly] " "[--verbose]\n" " [--version] [--xfer_len=BTL] DEVICE\n" " where:\n" " --failed|-f use FAILED SEGMENT DETAILS service " "action\n" " --help|-h print out usage message\n" " --hex|-H print out response buffer in hex\n" " --list_id=ID|-l ID list identifier (default: 0)\n" " --params|-p use OPERATING PARAMETERS service " "action\n" " --readonly|-R open DEVICE read-only (def: read-write)\n" " --receive|-r use RECEIVE DATA service action\n" " --status|-s use COPY STATUS service action\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --xfer_len=BTL|-x BTL byte transfer length (< 10000) " "(default:\n" " 520 bytes)\n\n" "Performs a SCSI RECEIVE COPY RESULTS command. Returns the " "response as\nspecified by the service action parameters.\n" ); } static const char * rec_copy_name_arr[] = { "Receive copy status(LID1)", "Receive copy data(LID1)", "Receive copy [0x2]", "Receive copy operating parameters", "Receive copy failure details(LID1)", }; int main(int argc, char * argv[]) { int sg_fd, res, c, k; unsigned char * cpResultBuff = NULL; int xfer_len = 520; int sa = 3; uint32_t list_id = 0; int do_hex = 0; int o_readonly = 0; int verbose = 0; const char * cp; const char * device_name = NULL; char file_name[256]; int ret = 1; memset(file_name, 0, sizeof file_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "fhHl:prRsvVx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'f': sa = 4; break; case 'H': do_hex = 1; break; case 'h': case '?': usage(); return 0; case 'l': k = sg_get_num(optarg); if (-1 == k) { pr2serr("bad argument to '--list_id'\n"); return SG_LIB_SYNTAX_ERROR; } list_id = (uint32_t)k; break; case 'p': sa = 3; break; case 'r': sa = 1; break; case 'R': ++o_readonly; break; case 's': sa = 0; break; case 'v': ++verbose; break; case 'V': pr2serr(ME "version: %s\n", version_str); return 0; case 'x': xfer_len = sg_get_num(optarg); if (-1 == xfer_len) { pr2serr("bad argument to '--xfer_len'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (xfer_len >= MAX_XFER_LEN) { pr2serr("xfer_len (%d) is out of range ( < %d)\n", xfer_len, MAX_XFER_LEN); usage(); return SG_LIB_SYNTAX_ERROR; } if (NULL == (cpResultBuff = (unsigned char *)malloc(xfer_len))) { pr2serr(ME "out of memory\n"); return SG_LIB_FILE_ERROR; } memset(cpResultBuff, 0x00, xfer_len); sg_fd = sg_cmds_open_device(device_name, o_readonly, verbose); if (sg_fd < 0) { pr2serr(ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if ((sa < 0) || (sa >= (int)(sizeof(rec_copy_name_arr) / sizeof(char *)))) cp = "Out of range service action"; else cp = rec_copy_name_arr[sa]; if (verbose) pr2serr(ME "issue %s to device %s\n\t\txfer_len= %d (0x%x), list_id=%" PRIu32 "\n", cp, device_name, xfer_len, xfer_len, list_id); res = sg_ll_receive_copy_results(sg_fd, sa, list_id, cpResultBuff, xfer_len, 1, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr(" SCSI %s failed: %s\n", cp, b); goto finish; } if (1 == do_hex) { dStrHex((const char *)cpResultBuff, xfer_len, 1); res = 0; goto finish; } switch (sa) { case 4: /* Failed segment details */ scsi_failed_segment_details(cpResultBuff, xfer_len); res = 0; break; case 3: /* Operating parameters */ scsi_operating_parameters(cpResultBuff, xfer_len); res = 0; break; case 0: /* Copy status */ scsi_copy_status(cpResultBuff, xfer_len); res = 0; break; default: dStrHex((const char *)cpResultBuff, xfer_len, 1); res = 0; break; } finish: free(cpResultBuff); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr(ME "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_raw.c0000664000175000017500000004256012420601524014570 0ustar douggdougg/* * A utility program originally written for the Linux OS SCSI subsystem. * * Copyright (C) 2000-2014 Ingo van Lil * * 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. * * This program can be used to send raw SCSI commands (with an optional * data phase) through a Generic SCSI interface. */ #define _XOPEN_SOURCE 600 /* clear up posix_memalign() warning */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #define SG_RAW_VERSION "0.4.11 (2014-10-18)" #ifdef SG_LIB_WIN32 #ifndef HAVE_SYSCONF #include static size_t win_pagesize(void) { SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); return sys_info.dwPageSize; } #endif #endif #define DEFAULT_TIMEOUT 20 #define MIN_SCSI_CDBSZ 6 #define MAX_SCSI_CDBSZ 256 #define MAX_SCSI_DXLEN (64 * 1024) static struct option long_options[] = { { "binary", no_argument, NULL, 'b' }, { "help", no_argument, NULL, 'h' }, { "infile", required_argument, NULL, 'i' }, { "skip", required_argument, NULL, 'k' }, { "nosense", no_argument, NULL, 'n' }, { "outfile", required_argument, NULL, 'o' }, { "request", required_argument, NULL, 'r' }, { "readonly", no_argument, NULL, 'R' }, { "send", required_argument, NULL, 's' }, { "timeout", required_argument, NULL, 't' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { 0, 0, 0, 0 } }; struct opts_t { char *device_name; unsigned char cdb[MAX_SCSI_CDBSZ]; int cdb_length; int do_datain; int datain_len; const char *datain_file; int datain_binary; int do_dataout; int dataout_len; const char *dataout_file; off_t dataout_offset; int timeout; int no_sense; int readonly; int do_help; int do_verbose; int do_version; }; static void version() { fprintf(stderr, "sg_raw " SG_RAW_VERSION "\n" "Copyright (C) 2007-2012 Ingo van Lil \n" "This is free software. You may redistribute copies of it " "under the terms of\n" "the GNU General Public License " ".\n" "There is NO WARRANTY, to the extent permitted by law.\n"); } static void usage() { fprintf(stderr, "Usage: sg_raw [OPTION]* DEVICE CDB0 CDB1 ...\n" "\n" "Options:\n" " -b, --binary Dump data in binary form, even when " "writing to stdout\n" " -h, --help Show this message and exit\n" " -i, --infile=IFILE Read data to send from IFILE (default: " "stdin)\n" " -k, --skip=LEN Skip the first LEN bytes when reading " "data to send\n" " -n, --nosense Don't display sense information\n" " -o, --outfile=OFILE Write binary data to OFILE (def: " "hexdump to stdout)\n" " -r, --request=RLEN Request up to RLEN bytes of data " "(data-in)\n" " -R, --readonly Open DEVICE read-only (default: " "read-write)\n" " -s, --send=SLEN Send SLEN bytes of data (data-out)\n" " -t, --timeout=SEC Timeout in seconds (default: 20)\n" " -v, --verbose Increase verbosity\n" " -V, --version Show version information and exit\n" "\n" "Between 6 and 256 command bytes (two hex digits each) can be " "specified\nand will be sent to DEVICE. Bidirectional commands " "accepted.\n\n" "Simple example: Perform INQUIRY on /dev/sg0:\n" " sg_raw -r 1k /dev/sg0 12 00 00 00 60 00\n"); } static int process_cl(struct opts_t * op, int argc, char *argv[]) { while (1) { int c, n; c = getopt_long(argc, argv, "bhi:k:no:r:Rs:t:vV", long_options, NULL); if (c == -1) break; switch (c) { case 'b': op->datain_binary = 1; break; case 'h': case '?': op->do_help = 1; return 0; case 'i': if (op->dataout_file) { fprintf(stderr, "Too many '--infile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_file = optarg; break; case 'k': n = sg_get_num(optarg); if (n < 0) { fprintf(stderr, "Invalid argument to '--skip'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_offset = n; break; case 'n': op->no_sense = 1; break; case 'o': if (op->datain_file) { fprintf(stderr, "Too many '--outfile=' options\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_file = optarg; break; case 'r': op->do_datain = 1; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { fprintf(stderr, "Invalid argument to '--request'\n"); return SG_LIB_SYNTAX_ERROR; } op->datain_len = n; break; case 'R': ++op->readonly; break; case 's': op->do_dataout = 1; n = sg_get_num(optarg); if (n < 0 || n > MAX_SCSI_DXLEN) { fprintf(stderr, "Invalid argument to '--send'\n"); return SG_LIB_SYNTAX_ERROR; } op->dataout_len = n; break; case 't': n = sg_get_num(optarg); if (n < 0) { fprintf(stderr, "Invalid argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } op->timeout = n; break; case 'v': ++op->do_verbose; break; case 'V': op->do_version = 1; return 0; default: return SG_LIB_SYNTAX_ERROR; } } if (optind >= argc) { fprintf(stderr, "No device specified\n"); return SG_LIB_SYNTAX_ERROR; } op->device_name = argv[optind]; ++optind; while (optind < argc) { char *opt = argv[optind++]; char *endptr; int cmd = strtol(opt, &endptr, 16); if (*opt == '\0' || *endptr != '\0' || cmd < 0x00 || cmd > 0xff) { fprintf(stderr, "Invalid command byte '%s'\n", opt); return SG_LIB_SYNTAX_ERROR; } if (op->cdb_length > MAX_SCSI_CDBSZ) { fprintf(stderr, "CDB too long (max. %d bytes)\n", MAX_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } op->cdb[op->cdb_length] = cmd; ++op->cdb_length; } if (op->cdb_length < MIN_SCSI_CDBSZ) { fprintf(stderr, "CDB too short (min. %d bytes)\n", MIN_SCSI_CDBSZ); return SG_LIB_SYNTAX_ERROR; } if (op->do_verbose > 2) { int sa; char b[80]; if (op->cdb_length > 16) { sa = (op->cdb[8] << 8) + op->cdb[9]; if (0x7f != op->cdb[0]) printf(">>> Unlikely to be SCSI CDB since all over 16 " "bytes long should\n>>> start with 0x7f\n"); } else sa = op->cdb[1] & 0x1f; sg_get_opcode_sa_name(op->cdb[0], sa, 0, sizeof(b), b); printf("Attempt to decode cdb name: %s\n", b); } return 0; } /* Allocate aligned memory (heap) starting on page boundary */ static unsigned char * my_memalign(int length, unsigned char ** wrkBuffp) { size_t psz; #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #elif defined(SG_LIB_WIN32) psz = win_pagesize(); #else psz = 4096; /* give up, pick likely figure */ #endif #ifdef HAVE_POSIX_MEMALIGN { int err; void * wp = NULL; err = posix_memalign(&wp, psz, length); if (err || (NULL == wp)) { fprintf(stderr, "posix_memalign: error [%d], out of memory?\n", err); return NULL; } memset(wp, 0, length); if (wrkBuffp) *wrkBuffp = (unsigned char *)wp; return (unsigned char *)wp; } #else { unsigned char * wrkBuff; wrkBuff = (unsigned char*)calloc(length + psz, 1); if (NULL == wrkBuff) { if (wrkBuffp) *wrkBuffp = NULL; return NULL; } else if (wrkBuffp) *wrkBuffp = wrkBuff; return (unsigned char *)(((unsigned long)wrkBuff + psz - 1) & (~(psz - 1))); } #endif } static int skip(int fd, off_t offset) { off_t remain; char buffer[512]; if (lseek(fd, offset, SEEK_SET) >= 0) { return 0; } // lseek failed; fall back to reading and discarding data remain = offset; while (remain > 0) { ssize_t amount, done; amount = (remain < (off_t)sizeof(buffer)) ? remain : (off_t)sizeof(buffer); done = read(fd, buffer, amount); if (done < 0) { perror("Error reading input data"); return SG_LIB_FILE_ERROR; } else if (done == 0) { fprintf(stderr, "EOF on input file/stream\n"); return SG_LIB_FILE_ERROR; } else { remain -= done; } } return 0; } static unsigned char * fetch_dataout(struct opts_t * op) { unsigned char *buf = NULL; unsigned char *wrkBuf = NULL; int fd, len; int ok = 0; if (op->dataout_file) { fd = open(op->dataout_file, O_RDONLY); if (fd < 0) { perror(op->dataout_file); goto bail; } } else { fd = STDIN_FILENO; } if (sg_set_binary_mode(fd) < 0) { perror("sg_set_binary_mode"); goto bail; } if (op->dataout_offset > 0) { if (skip(fd, op->dataout_offset) != 0) { goto bail; } } buf = my_memalign(op->dataout_len, &wrkBuf); if (buf == NULL) { perror("malloc"); goto bail; } len = read(fd, buf, op->dataout_len); if (len < 0) { perror("Failed to read input data"); goto bail; } else if (len < op->dataout_len) { fprintf(stderr, "EOF on input file/stream\n"); goto bail; } ok = 1; bail: if (fd >= 0 && fd != STDIN_FILENO) close(fd); if (!ok) { if (wrkBuf) free(wrkBuf); return NULL; } return buf; } static int write_dataout(const char *filename, unsigned char *buf, int len) { int ret = SG_LIB_FILE_ERROR; int fd; if ((filename == NULL) || ((1 == strlen(filename)) && ('-' == filename[0]))) fd = STDOUT_FILENO; else { fd = creat(filename, 0666); if (fd < 0) { perror(filename); goto bail; } } if (sg_set_binary_mode(fd) < 0) { perror("sg_set_binary_mode"); goto bail; } if (write(fd, buf, len) != len) { perror(filename ? filename : "stdout"); goto bail; } ret = 0; bail: if (fd >= 0 && fd != STDOUT_FILENO) close(fd); return ret; } int main(int argc, char *argv[]) { int ret = 0; int res_cat, status, slen, k, ret2; int sg_fd = -1; struct sg_pt_base *ptvp = NULL; unsigned char sense_buffer[32]; unsigned char * dxfer_buffer_in = NULL; unsigned char * dxfer_buffer_out = NULL; unsigned char *wrkBuf = NULL; struct opts_t opts; struct opts_t * op; char b[128]; op = &opts; memset(op, 0, sizeof(opts)); op->timeout = DEFAULT_TIMEOUT; ret = process_cl(op, argc, argv); if (ret != 0) { usage(); goto done; } else if (op->do_help) { usage(); goto done; } else if (op->do_version) { version(); goto done; } sg_fd = scsi_pt_open_device(op->device_name, op->readonly, op->do_verbose); if (sg_fd < 0) { fprintf(stderr, "%s: %s\n", op->device_name, safe_strerror(-sg_fd)); ret = SG_LIB_FILE_ERROR; goto done; } ptvp = construct_scsi_pt_obj(); if (ptvp == NULL) { fprintf(stderr, "out of memory\n"); ret = SG_LIB_CAT_OTHER; goto done; } if (op->do_verbose) { fprintf(stderr, " cdb to send: "); for (k = 0; k < op->cdb_length; ++k) fprintf(stderr, "%02x ", op->cdb[k]); fprintf(stderr, "\n"); if (op->do_verbose > 2) { sg_get_command_name(op->cdb, 0, sizeof(b) - 1, b); b[sizeof(b) - 1] = '\0'; fprintf(stderr, " Command name: %s\n", b); } } set_scsi_pt_cdb(ptvp, op->cdb, op->cdb_length); set_scsi_pt_sense(ptvp, sense_buffer, sizeof(sense_buffer)); if (op->do_dataout) { dxfer_buffer_out = fetch_dataout(op); if (dxfer_buffer_out == NULL) { ret = SG_LIB_CAT_OTHER; goto done; } set_scsi_pt_data_out(ptvp, dxfer_buffer_out, op->dataout_len); } if (op->do_datain) { dxfer_buffer_in = my_memalign(op->datain_len, &wrkBuf); if (dxfer_buffer_in == NULL) { perror("malloc"); ret = SG_LIB_CAT_OTHER; goto done; } set_scsi_pt_data_in(ptvp, dxfer_buffer_in, op->datain_len); } ret = do_scsi_pt(ptvp, sg_fd, op->timeout, op->do_verbose); if (ret > 0) { if (SCSI_PT_DO_BAD_PARAMS == ret) { fprintf(stderr, "do_scsi_pt: bad pass through setup\n"); ret = SG_LIB_CAT_OTHER; } else if (SCSI_PT_DO_TIMEOUT == ret) { fprintf(stderr, "do_scsi_pt: timeout\n"); ret = SG_LIB_CAT_TIMEOUT; } else ret = SG_LIB_CAT_OTHER; goto done; } else if (ret < 0) { fprintf(stderr, "do_scsi_pt: %s\n", safe_strerror(-ret)); ret = SG_LIB_CAT_OTHER; goto done; } slen = 0; res_cat = get_scsi_pt_result_category(ptvp); switch (res_cat) { case SCSI_PT_RESULT_GOOD: ret = 0; break; case SCSI_PT_RESULT_SENSE: slen = get_scsi_pt_sense_len(ptvp); ret = sg_err_category_sense(sense_buffer, slen); break; case SCSI_PT_RESULT_TRANSPORT_ERR: get_scsi_pt_transport_err_str(ptvp, sizeof(b), b); fprintf(sg_warnings_strm, ">>> transport error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; case SCSI_PT_RESULT_OS_ERR: get_scsi_pt_os_err_str(ptvp, sizeof(b), b); fprintf(sg_warnings_strm, ">>> os error: %s\n", b); ret = SG_LIB_CAT_OTHER; break; default: fprintf(sg_warnings_strm, ">>> unknown pass through result " "category (%d)\n", res_cat); ret = SG_LIB_CAT_OTHER; break; } status = get_scsi_pt_status_response(ptvp); fprintf(stderr, "SCSI Status: "); sg_print_scsi_status(status); fprintf(stderr, "\n\n"); if ((SAM_STAT_CHECK_CONDITION == status) && (! op->no_sense)) { if (SCSI_PT_RESULT_SENSE != res_cat) slen = get_scsi_pt_sense_len(ptvp); if (0 == slen) fprintf(stderr, ">>> Strange: status is CHECK CONDITION but no " "Sense Information\n"); else { fprintf(stderr, "Sense Information:\n"); sg_print_sense(NULL, sense_buffer, slen, (op->do_verbose > 0)); fprintf(stderr, "\n"); } } if (SAM_STAT_RESERVATION_CONFLICT == status) ret = SG_LIB_CAT_RES_CONFLICT; if (op->do_datain) { int data_len = op->datain_len - get_scsi_pt_resid(ptvp); if (ret && !(SG_LIB_CAT_RECOVERED == ret || SG_LIB_CAT_NO_SENSE == ret)) fprintf(stderr, "Error %d occurred, no data received\n", ret); else if (data_len == 0) { fprintf(stderr, "No data received\n"); } else { if (op->datain_file == NULL && !op->datain_binary) { fprintf(stderr, "Received %d bytes of data:\n", data_len); dStrHexErr((const char *)dxfer_buffer_in, data_len, 0); } else { const char * cp = "stdout"; if (op->datain_file && ! ((1 == strlen(op->datain_file)) && ('-' == op->datain_file[0]))) cp = op->datain_file; fprintf(stderr, "Writing %d bytes of data to %s\n", data_len, cp); ret2 = write_dataout(op->datain_file, dxfer_buffer_in, data_len); if (0 != ret2) { if (0 == ret) ret = ret2; goto done; } } } } done: if (op->do_verbose) { sg_get_category_sense_str(ret, sizeof(b), b, op->do_verbose - 1); fprintf(stderr, "%s\n", b); } if (wrkBuf) free(wrkBuf); if (ptvp) destruct_scsi_pt_obj(ptvp); if (sg_fd >= 0) scsi_pt_close_device(sg_fd); return ret; } sg3_utils-1.40/src/sg_sync.c0000664000175000017500000002067612335513125014763 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" /* A utility program for the Linux OS SCSI subsystem. * * * This program issues the SCSI command SYNCHRONIZE CACHE(10 or 16) to the * given device. This command is defined for SCSI "direct access" devices * (e.g. disks). */ static const char * version_str = "1.11 20140516"; #define SYNCHRONIZE_CACHE16_CMD 0x91 #define SYNCHRONIZE_CACHE16_CMDLEN 16 #define SENSE_BUFF_LEN 64 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static struct option long_options[] = { {"16", no_argument, 0, 'S'}, {"count", required_argument, 0, 'c'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"immed", no_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"sync-nv", no_argument, 0, 's'}, {"timeout", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_sync [--16] [--count=COUNT] [--group=GN] [--help] " "[--immed]\n" " [--lba=LBA] [--sync-nv] [--timeout=SECS] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --16|-S calls SYNCHRONIZE CACHE(16) (def: is " "10 byte\n" " variant)\n" " --count=COUNT|-c COUNT number of blocks to sync (def: 0 " "which\n" " implies rest of device)\n" " --group=GN|-g GN set group number field to GN (def: 0)\n" " --help|-h print out usage message\n" " --immed|-i command returns immediately when set " "else wait\n" " for 'sync' to complete\n" " --lba=LBA|-l LBA logical block address to start sync " "operation\n" " from (def: 0)\n" " --sync-nv|-s synchronize to non-volatile storage " "(if distinct\n" " from medium). Obsolete in sbc3r35d.\n" " --timeout=SECS|-t SECS command timeout in seconds, only " "active\n" " if '--16' given (def: 60 seconds)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI SYNCHRONIZE CACHE(10 or 16) command\n" ); } static int ll_sync_cache_16(int sg_fd, int sync_nv, int immed, int group, uint64_t lba, unsigned int num_lb, int to_secs, int noisy, int verbose) { int res, ret, k, sense_cat; unsigned char scCmdBlk[SYNCHRONIZE_CACHE16_CMDLEN] = {SYNCHRONIZE_CACHE16_CMD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (sync_nv) scCmdBlk[1] |= 4; /* obsolete in sbc3r35d */ if (immed) scCmdBlk[1] |= 2; scCmdBlk[2] = (lba >> 56) & 0xff; scCmdBlk[3] = (lba >> 48) & 0xff; scCmdBlk[4] = (lba >> 40) & 0xff; scCmdBlk[5] = (lba >> 32) & 0xff; scCmdBlk[6] = (lba >> 24) & 0xff; scCmdBlk[7] = (lba >> 16) & 0xff; scCmdBlk[8] = (lba >> 8) & 0xff; scCmdBlk[9] = lba & 0xff; scCmdBlk[14] = group & 0x1f; scCmdBlk[10] = (num_lb >> 24) & 0xff; scCmdBlk[11] = (num_lb >> 16) & 0xff; scCmdBlk[12] = (num_lb >> 8) & 0xff; scCmdBlk[13] = num_lb & 0xff; if (verbose) { fprintf(stderr, " synchronize cache(16) cdb: "); for (k = 0; k < SYNCHRONIZE_CACHE16_CMDLEN; ++k) fprintf(stderr, "%02x ", scCmdBlk[k]); fprintf(sg_warnings_strm, "\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(stderr, "synchronize cache(16): out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, scCmdBlk, sizeof(scCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, to_secs, verbose); ret = sg_cmds_process_resp(ptvp, "synchronize cache(16)", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { int sg_fd, res, c; int64_t count = 0; unsigned int num_lb = 0; int do_16 = 0; int group = 0; int64_t lba = 0; int immed = 0; int sync_nv = 0; int to_secs = DEF_PT_TIMEOUT; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:g:hil:sSt:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': count = sg_get_llnum(optarg); if ((count < 0) || (count > UINT_MAX)) { fprintf(stderr, "bad argument to '--count'\n"); return SG_LIB_SYNTAX_ERROR; } num_lb = (unsigned int)count; break; case 'g': group = sg_get_num(optarg); if ((group < 0) || (group > 31)) { fprintf(stderr, "bad argument to '--group'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': immed = 1; break; case 'l': lba = sg_get_llnum(optarg); if (lba < 0) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': sync_nv = 1; break; case 'S': do_16 = 1; break; case 't': to_secs = sg_get_num(optarg); if (to_secs < 0) { fprintf(stderr, "bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (do_16) res = ll_sync_cache_16(sg_fd, sync_nv, immed, group, lba, num_lb, to_secs, 1, verbose); else res = sg_ll_sync_cache_10(sg_fd, sync_nv, immed, group, (unsigned int)lba, num_lb, 1, verbose); ret = res; if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Synchronize cache failed: %s\n", b); } res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_read_long.c0000664000175000017500000002057612335513125015740 0ustar douggdougg/* A utility program for the Linux OS SCSI subsystem. * Copyright (C) 2004-2014 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. This program issues the SCSI command READ LONG to a given SCSI device. It sends the command with the logical block address passed as the lba argument, and the transfer length set to the xfer_len argument. the buffer to be writen to the device filled with 0xff, this buffer includes the sector data and the ECC bytes. */ #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "1.19 20140516"; #define MAX_XFER_LEN 10000 #define ME "sg_read_long: " #define EBUFF_SZ 256 static struct option long_options[] = { {"16", 0, 0, 'S'}, {"correct", 0, 0, 'c'}, {"help", 0, 0, 'h'}, {"lba", 1, 0, 'l'}, {"out", 1, 0, 'o'}, {"pblock", 0, 0, 'p'}, {"readonly", 0, 0, 'r'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"xfer_len", 1, 0, 'x'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_read_long [--16] [--correct] [--help] [--lba=LBA] " "[--out=OF]\n" " [--pblock] [--readonly] [--verbose] " "[--version]\n" " [--xfer_len=BTL] DEVICE\n" " where:\n" " --16|-S do READ LONG(16) (default: " "READ LONG(10))\n" " --correct|-c use ECC to correct data " "(default: don't)\n" " --help|-h print out usage message\n" " --lba=LBA|-l LBA logical block address" " (default: 0)\n" " --out=OF|-o OF output in binary to file named OF\n" " --pblock|-p fetch physical block containing LBA\n" " --readonly|-r open DEVICE read-only (def: open it " "read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and" " exit\n" " --xfer_len=BTL|-x BTL byte transfer length (< 10000)" " default 520\n\n" "Perform a SCSI READ LONG (10 or 16) command. Reads a single " "block with\nassociated ECC data. User data could be scrambled.\n" ); } /* Returns 0 if successful */ static int process_read_long(int sg_fd, int do_16, int pblock, int correct, uint64_t llba, void * data_out, int xfer_len, int verbose) { int offset, res; const char * ten_or; char b[80]; if (do_16) res = sg_ll_read_long16(sg_fd, pblock, correct, llba, data_out, xfer_len, &offset, 1, verbose); else res = sg_ll_read_long10(sg_fd, pblock, correct, (unsigned int)llba, data_out, xfer_len, &offset, 1, verbose); ten_or = do_16 ? "16" : "10"; switch (res) { case 0: break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: fprintf(stderr, "<<< device indicates 'xfer_len' should be %d " ">>>\n", xfer_len - offset); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, " SCSI READ LONG (%s): %s\n", ten_or, b); break; } return res; } int main(int argc, char * argv[]) { int sg_fd, outfd, res, c; unsigned char * readLongBuff = NULL; void * rawp = NULL; int correct = 0; int xfer_len = 520; int do_16 = 0; int pblock = 0; uint64_t llba = 0; int readonly = 0; int verbose = 0; int64_t ll; int got_stdout; const char * device_name = NULL; char out_fname[256]; char ebuff[EBUFF_SZ]; int ret = 0; memset(out_fname, 0, sizeof out_fname); while (1) { int option_index = 0; c = getopt_long(argc, argv, "chl:o:prSvVx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': correct = 1; break; case 'h': case '?': usage(); return 0; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; break; case 'o': strncpy(out_fname, optarg, sizeof(out_fname) - 1); break; case 'p': pblock = 1; break; case 'r': ++readonly; break; case 'S': do_16 = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'x': xfer_len = sg_get_num(optarg); if (-1 == xfer_len) { fprintf(stderr, "bad argument to '--xfer_len'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (xfer_len >= MAX_XFER_LEN){ fprintf(stderr, "xfer_len (%d) is out of range ( < %d)\n", xfer_len, MAX_XFER_LEN); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (NULL == (rawp = malloc(MAX_XFER_LEN))) { fprintf(stderr, ME "out of memory\n"); sg_cmds_close_device(sg_fd); return SG_LIB_SYNTAX_ERROR; } readLongBuff = (unsigned char *)rawp; memset(rawp, 0x0, MAX_XFER_LEN); fprintf(stderr, ME "issue read long (%s) to device %s\n xfer_len=%d " "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 "), correct=%d\n", (do_16 ? "16" : "10"), device_name, xfer_len, xfer_len, llba, llba, correct); if ((ret = process_read_long(sg_fd, do_16, pblock, correct, llba, readLongBuff, xfer_len, verbose))) goto err_out; if ('\0' == out_fname[0]) dStrHex((const char *)rawp, xfer_len, 0); else { got_stdout = (0 == strcmp(out_fname, "-")) ? 1 : 0; if (got_stdout) outfd = STDOUT_FILENO; else { if ((outfd = open(out_fname, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", out_fname); perror(ebuff); goto err_out; } } if (sg_set_binary_mode(outfd) < 0) { perror("sg_set_binary_mode"); goto err_out; } res = write(outfd, readLongBuff, xfer_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't write to %s", out_fname); perror(ebuff); goto err_out; } if (! got_stdout) close(outfd); } err_out: if (rawp) free(rawp); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_reset_wp.c0000664000175000017500000001533712423733033015635 0ustar douggdougg/* * Copyright (c) 2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_unaligned.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues the SCSI RESET WRITE POINTER command to the given SCSI * device. Based on zbc-r01c.pdf . */ static const char * version_str = "1.02 20141028"; #define SERVICE_ACTION_OUT_16_CMD 0x9f #define SERVICE_ACTION_OUT_16_CMDLEN 16 #define RESET_WRITE_POINTER_SA 0x14 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"reset-all", no_argument, 0, 'R'}, {"reset_all", no_argument, 0, 'R'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"zone", required_argument, 0, 'z'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_reset_wp [--help] [--reset-all] [--verbose] [--version]\n" " [--zone=ID] DEVICE\n"); pr2serr(" where:\n" " --help|-h print out usage message\n" " --reset-all|-R sets the RESET ALL flag in the cdb\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" " --zone=ID|-z ID ID is the starting LBA of the zone " "whose\n" " write pointer is to be reset\n" "Performs a SCSI RESET WRITE POINTER command. ID is decimal by " "default,\nfor hex use a leading '0x' or a trailing 'h'. " "Either the --zone=ID\nor --reset-all needs to be given.\n"); } /* Invokes a SCSI RESET WRITE POINTER command (ZBC). Return of 0 -> success, * various SG_LIB_CAT_* positive values or -1 -> other errors */ static int sg_ll_reset_write_pointer(int sg_fd, uint64_t zid, int reset_all, int noisy, int verbose) { int k, ret, res, sense_cat; unsigned char rwpCmdBlk[SERVICE_ACTION_OUT_16_CMDLEN] = {SERVICE_ACTION_OUT_16_CMD, RESET_WRITE_POINTER_SA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; sg_put_unaligned_be64(zid, rwpCmdBlk + 2); if (reset_all) rwpCmdBlk[14] = 0x1; if (verbose) { pr2serr(" Reset write pointer cdb: "); for (k = 0; k < SERVICE_ACTION_OUT_16_CMDLEN; ++k) pr2serr("%02x ", rwpCmdBlk[k]); pr2serr("\n"); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("Reset write pointer: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, rwpCmdBlk, sizeof(rwpCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "reset write pointer", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { int sg_fd, res, c; int reset_all = 0; int verbose = 0; int zid_given = 0; uint64_t zid = 0; int64_t ll; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "hRvVz:", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': case '?': usage(); return 0; case 'R': ++reset_all; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; case 'z': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--zone=ID'\n"); return SG_LIB_SYNTAX_ERROR; } zid = (uint64_t)ll; ++zid_given; break; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if ((! zid_given) && (0 == reset_all)) { pr2serr("either the --zone=ID or --reset-all option is required\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } res = sg_ll_reset_write_pointer(sg_fd, zid, reset_all, 1, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("Reset write pointer command not supported\n"); else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("Reset write pointer command: %s\n", b); } } res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_get_config.c0000664000175000017500000012206512335513125016106 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_mmc.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program outputs information provided by a SCSI "Get Configuration" command [0x46] which is only defined for CD/DVDs (in MMC-2,3,4,5,6). */ static const char * version_str = "0.39 20140516"; /* mmc6r02 */ #define MX_ALLOC_LEN 8192 #define NAME_BUFF_SZ 64 #define ME "sg_get_config: " static unsigned char resp_buffer[MX_ALLOC_LEN]; static struct option long_options[] = { {"brief", 0, 0, 'b'}, {"current", 0, 0, 'c'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"inner-hex", 0, 0, 'i'}, {"list", 0, 0, 'l'}, {"raw", 0, 0, 'R'}, {"readonly", 0, 0, 'q'}, {"rt", 1, 0, 'r'}, {"starting", 1, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: sg_get_config [--brief] [--current] [--help] [--hex] " "[--inner-hex]\n" " [--list] [--raw] [--readonly] [--rt=RT]\n" " [--starting=FC] [--verbose] [--version] " "DEVICE\n" " where:\n" " --brief|-b only give feature names of DEVICE " "(don't decode)\n" " --current|-c equivalent to '--rt=1' (show " "current)\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex\n" " --inner-hex|-i decode to feature name, then output " "features in hex\n" " --list|-l list all known features + profiles " "(ignore DEVICE)\n" " --raw|-R output in binary (to stdout)\n" " --readonly|-q open DEVICE read-only (def: open it " "read-write)\n" " --rt=RT|-r RT default value is 0\n" " 0 -> all feature descriptors (regardless " "of currency)\n" " 1 -> all current feature descriptors\n" " 2 -> only feature descriptor matching " "'starting'\n" " --starting=FC|-s FC starting from feature " "code (FC) value\n" " --verbose|-v verbose\n" " --version|-V output version string\n\n" "Get configuration information for MMC drive and/or media\n"); } struct val_desc_t { int val; const char * desc; }; static struct val_desc_t profile_desc_arr[] = { {0x0, "No current profile"}, {0x1, "Non-removable disk (obs)"}, {0x2, "Removable disk"}, {0x3, "Magneto optical erasable"}, {0x4, "Optical write once"}, {0x5, "AS-MO"}, {0x8, "CD-ROM"}, {0x9, "CD-R"}, {0xa, "CD-RW"}, {0x10, "DVD-ROM"}, {0x11, "DVD-R sequential recording"}, {0x12, "DVD-RAM"}, {0x13, "DVD-RW restricted overwrite"}, {0x14, "DVD-RW sequential recording"}, {0x15, "DVD-R dual layer sequental recording"}, {0x16, "DVD-R dual layer jump recording"}, {0x17, "DVD-RW dual layer"}, {0x18, "DVD-Download disc recording"}, {0x1a, "DVD+RW"}, {0x1b, "DVD+R"}, {0x20, "DDCD-ROM"}, {0x21, "DDCD-R"}, {0x22, "DDCD-RW"}, {0x2a, "DVD+RW dual layer"}, {0x2b, "DVD+R dual layer"}, {0x40, "BD-ROM"}, {0x41, "BD-R SRM"}, {0x42, "BD-R RRM"}, {0x43, "BD-RE"}, {0x50, "HD DVD-ROM"}, {0x51, "HD DVD-R"}, {0x52, "HD DVD-RAM"}, {0x53, "HD DVD-RW"}, {0x58, "HD DVD-R dual layer"}, {0x5a, "HD DVD-RW dual layer"}, {0xffff, "Non-conforming profile"}, {-1, NULL}, }; static const char * get_profile_str(int profile_num, char * buff) { const struct val_desc_t * pdp; for (pdp = profile_desc_arr; pdp->desc; ++pdp) { if (pdp->val == profile_num) { strcpy(buff, pdp->desc); return buff; } } snprintf(buff, 64, "0x%x", profile_num); return buff; } static struct val_desc_t feature_desc_arr[] = { {0x0, "Profile list"}, {0x1, "Core"}, {0x2, "Morphing"}, {0x3, "Removable media"}, {0x4, "Write Protect"}, {0x10, "Random readable"}, {0x1d, "Multi-read"}, {0x1e, "CD read"}, {0x1f, "DVD read"}, {0x20, "Random writable"}, {0x21, "Incremental streaming writable"}, {0x22, "Sector erasable"}, {0x23, "Formattable"}, {0x24, "Hardware defect management"}, {0x25, "Write once"}, {0x26, "Restricted overwrite"}, {0x27, "CD-RW CAV write"}, {0x28, "MRW"}, /* Mount Rainier reWritable */ {0x29, "Enhanced defect reporting"}, {0x2a, "DVD+RW"}, {0x2b, "DVD+R"}, {0x2c, "Rigid restricted overwrite"}, {0x2d, "CD track-at-once"}, {0x2e, "CD mastering (session at once)"}, {0x2f, "DVD-R/-RW write"}, {0x30, "Double density CD read"}, {0x31, "Double density CD-R write"}, {0x32, "Double density CD-RW write"}, {0x33, "Layer jump recording"}, {0x34, "LJ rigid restricted oberwrite"}, {0x35, "Stop long operation"}, {0x37, "CD-RW media write support"}, {0x38, "BD-R POW"}, {0x3a, "DVD+RW dual layer"}, {0x3b, "DVD+R dual layer"}, {0x40, "BD read"}, {0x41, "BD write"}, {0x42, "TSR (timely safe recording)"}, {0x50, "HD DVD read"}, {0x51, "HD DVD write"}, {0x52, "HD DVD-RW fragment recording"}, {0x80, "Hybrid disc"}, {0x100, "Power management"}, {0x101, "SMART"}, {0x102, "Embedded changer"}, {0x103, "CD audio external play"}, {0x104, "Microcode upgrade"}, {0x105, "Timeout"}, {0x106, "DVD CSS"}, {0x107, "Real time streaming"}, {0x108, "Drive serial number"}, {0x109, "Media serial number"}, {0x10a, "Disc control blocks"}, {0x10b, "DVD CPRM"}, {0x10c, "Firmware information"}, {0x10d, "AACS"}, {0x10e, "DVD CSS managed recording"}, {0x110, "VCPS"}, {0x113, "SecurDisc"}, {0x120, "BD CPS"}, {0x142, "OSSC"}, }; static const char * get_feature_str(int feature_num, char * buff) { int k, num; num = sizeof(feature_desc_arr) / sizeof(feature_desc_arr[0]); for (k = 0; k < num; ++k) { if (feature_desc_arr[k].val == feature_num) { strcpy(buff, feature_desc_arr[k].desc); return buff; } } snprintf(buff, 64, "0x%x", feature_num); return buff; } static void dStrRaw(const char * str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static void decode_feature(int feature, unsigned char * ucp, int len) { int k, num, n, profile; char buff[128]; const char * cp; cp = ""; switch (feature) { case 0: /* Profile list */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 2), !!(ucp[2] & 1), feature); printf(" available profiles [more recent typically higher " "in list]:\n"); for (k = 4; k < len; k += 4) { profile = (ucp[k] << 8) + ucp[k + 1]; printf(" profile: %s , currentP=%d\n", get_profile_str(profile, buff), !!(ucp[k + 2] & 1)); } break; case 1: /* Core */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 2), !!(ucp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; switch (num) { case 0: cp = "unspecified"; break; case 1: cp = "SCSI family"; break; case 2: cp = "ATAPI"; break; case 3: cp = "IEEE 1394 - 1995"; break; case 4: cp = "IEEE 1394A"; break; case 5: cp = "Fibre channel"; break; case 6: cp = "IEEE 1394B"; break; case 7: cp = "Serial ATAPI"; break; case 8: cp = "USB (both 1 and 2)"; break; case 0xffff: cp = "vendor unique"; break; default: snprintf(buff, sizeof(buff), "[0x%x]", num); cp = buff; break; } printf(" Physical interface standard: %s", cp); if (len > 8) printf(", INQ2=%d, DBE=%d\n", !!(ucp[8] & 2), !!(ucp[8] & 1)); else printf("\n"); break; case 2: /* Morphing */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 2), !!(ucp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" OCEvent=%d, ASYNC=%d\n", !!(ucp[4] & 2), !!(ucp[4] & 1)); break; case 3: /* Removable medium */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 2), !!(ucp[2] & 1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = (ucp[4] >> 5) & 0x7; switch (num) { case 0: cp = "Caddy/slot type"; break; case 1: cp = "Tray type"; break; case 2: cp = "Pop-up type"; break; case 4: cp = "Embedded changer with individually changeable discs"; break; case 5: cp = "Embedded changer using a magazine"; break; default: snprintf(buff, sizeof(buff), "[0x%x]", num); cp = buff; break; } printf(" Loading mechanism: %s\n", cp); printf(" Load=%d, Eject=%d, Prevent jumper=%d, Lock=%d\n", !!(ucp[4] & 0x10), !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x1)); break; case 4: /* Write protect */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" DWP=%d, WDCB=%d, SPWP=%d, SSWPP=%d\n", !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); break; case 0x10: /* Random readable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 12) { printf(" additional length [%d] too short\n", len - 4); break; } num = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf(" Logical block size=0x%x, blocking=0x%x, PP=%d\n", num, ((ucp[8] << 8) + ucp[9]), !!(ucp[10] & 0x1)); break; case 0x1d: /* Multi-read */ case 0x22: /* Sector erasable */ case 0x26: /* Restricted overwrite */ case 0x27: /* CDRW CAV write */ case 0x35: /* Stop long operation */ case 0x38: /* BD-R pseudo-overwrite (POW) */ case 0x42: /* TSR (timely safe recording) */ case 0x100: /* Power management */ case 0x109: /* Media serial number */ case 0x110: /* VCPS */ case 0x113: /* SecurDisc */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); break; case 0x1e: /* CD read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" DAP=%d, C2 flags=%d, CD-Text=%d\n", !!(ucp[4] & 0x80), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); break; case 0x1f: /* DVD read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len > 7) printf(" MULTI110=%d, Dual-RW=%d, Dual-R=%d\n", !!(ucp[4] & 0x1), !!(ucp[6] & 0x2), !!(ucp[6] & 0x1)); break; case 0x20: /* Random writable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 16) { printf(" additional length [%d] too short\n", len - 4); break; } num = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; n = (ucp[8] << 24) + (ucp[9] << 16) + (ucp[10] << 8) + ucp[11]; printf(" Last lba=0x%x, Logical block size=0x%x, blocking=0x%x," " PP=%d\n", num, n, ((ucp[12] << 8) + ucp[13]), !!(ucp[14] & 0x1)); break; case 0x21: /* Incremental streaming writable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Data block types supported=0x%x, TRIO=%d, ARSV=%d, " "BUF=%d\n", ((ucp[4] << 8) + ucp[5]), !!(ucp[6] & 0x4), !!(ucp[6] & 0x2), !!(ucp[6] & 0x1)); num = ucp[7]; printf(" Number of link sizes=%d\n", num); for (k = 0; k < num; ++k) printf(" %d\n", ucp[8 + k]); break; /* case 0x22: Sector erasable -> see 0x1d entry */ case 0x23: /* Formattable */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len > 4) printf(" BD-RE: RENoSA=%d, Expand=%d, QCert=%d, Cert=%d, " "FRF=%d\n", !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1), !!(ucp[5] & 0x80)); if (len > 8) printf(" BD-R: RRM=%d\n", !!(ucp[8] & 0x1)); break; case 0x24: /* Hardware defect management */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len > 4) printf(" SSA=%d\n", !!(ucp[4] & 0x80)); break; case 0x25: /* Write once */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 12) { printf(" additional length [%d] too short\n", len - 4); break; } num = (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]; printf(" Logical block size=0x%x, blocking=0x%x, PP=%d\n", num, ((ucp[8] << 8) + ucp[9]), !!(ucp[10] & 0x1)); break; /* case 0x26: Restricted overwrite -> see 0x1d entry */ /* case 0x27: CDRW CAV write -> see 0x1d entry */ case 0x28: /* MRW (Mount Rainier reWriteable) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len > 4) printf(" DVD+Write=%d, DVD+Read=%d, Write=%d\n", !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); break; case 0x29: /* Enhanced defect reporting */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" DRT-DM=%d, number of DBI cache zones=0x%x, number of " "entries=0x%x\n", !!(ucp[4] & 0x1), ucp[5], ((ucp[6] << 8) + ucp[7])); break; case 0x2a: /* DVD+RW */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Write=%d, Quick start=%d, Close only=%d\n", !!(ucp[4] & 0x1), !!(ucp[5] & 0x2), !!(ucp[5] & 0x1)); break; case 0x2b: /* DVD+R */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Write=%d\n", !!(ucp[4] & 0x1)); break; case 0x2c: /* Rigid restricted overwrite */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" DSDG=%d, DSDR=%d, Intermediate=%d, Blank=%d\n", !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); break; case 0x2d: /* CD Track at once */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BUF=%d, R-W raw=%d, R-W pack=%d, Test write=%d\n", !!(ucp[4] & 0x40), !!(ucp[4] & 0x10), !!(ucp[4] & 0x8), !!(ucp[4] & 0x4)); printf(" CD-RW=%d, R-W sub-code=%d, Data type supported=%d\n", !!(ucp[4] & 0x2), !!(ucp[4] & 0x1), (ucp[6] << 8) + ucp[7]); break; case 0x2e: /* CD mastering (session at once) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BUF=%d, SAO=%d, Raw MS=%d, Raw=%d\n", !!(ucp[4] & 0x40), !!(ucp[4] & 0x20), !!(ucp[4] & 0x10), !!(ucp[4] & 0x8)); printf(" Test write=%d, CD-RW=%d, R-W=%d\n", !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); printf(" Maximum cue sheet length=0x%x\n", (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]); break; case 0x2f: /* DVD-R/-RW write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BUF=%d, RDL=%d, Test write=%d, DVD-RW SL=%d\n", !!(ucp[4] & 0x40), !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x2)); break; case 0x33: /* Layer jump recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } num = ucp[7]; printf(" Number of link sizes=%d\n", num); for (k = 0; k < num; ++k) printf(" %d\n", ucp[8 + k]); break; case 0x34: /* Layer jump rigid restricted overwrite */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CLJB=%d\n", !!(ucp[4] & 0x1)); printf(" Buffer block size=%d\n", ucp[7]); break; /* case 0x35: Stop long operation -> see 0x1d entry */ case 0x37: /* CD-RW media write support */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CD-RW media sub-type support (bitmask)=0x%x\n", ucp[5]); break; /* case 0x38: BD-R pseudo-overwrite (POW) -> see 0x1d entry */ case 0x3a: /* DVD+RW dual layer */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" write=%d, quick_start=%d, close_only=%d\n", !!(ucp[4] & 0x1), !!(ucp[5] & 0x2), !!(ucp[5] & 0x1)); break; case 0x3b: /* DVD+R dual layer */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" write=%d\n", !!(ucp[4] & 0x1)); break; case 0x40: /* BD Read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 32) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Bitmaps for BD-RE read support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[8] << 8) + ucp[9], (ucp[10] << 8) + ucp[11], (ucp[12] << 8) + ucp[13], (ucp[14] << 8) + ucp[15]); printf(" Bitmaps for BD-R read support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[16] << 8) + ucp[17], (ucp[18] << 8) + ucp[19], (ucp[20] << 8) + ucp[21], (ucp[22] << 8) + ucp[23]); printf(" Bitmaps for BD-ROM read support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[24] << 8) + ucp[25], (ucp[26] << 8) + ucp[27], (ucp[28] << 8) + ucp[29], (ucp[30] << 8) + ucp[31]); break; case 0x41: /* BD Write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 32) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" SVNR=%d\n", !!(ucp[4] & 0x1)); printf(" Bitmaps for BD-RE write support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[8] << 8) + ucp[9], (ucp[10] << 8) + ucp[11], (ucp[12] << 8) + ucp[13], (ucp[14] << 8) + ucp[15]); printf(" Bitmaps for BD-R write support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[16] << 8) + ucp[17], (ucp[18] << 8) + ucp[19], (ucp[20] << 8) + ucp[21], (ucp[22] << 8) + ucp[23]); printf(" Bitmaps for BD-ROM write support:\n"); printf(" Class 0=0x%x, Class 1=0x%x, Class 2=0x%x, " "Class 3=0x%x\n", (ucp[24] << 8) + ucp[25], (ucp[26] << 8) + ucp[27], (ucp[28] << 8) + ucp[29], (ucp[30] << 8) + ucp[31]); break; /* case 0x42: TSR (timely safe recording) -> see 0x1d entry */ case 0x50: /* HD DVD Read */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" HD DVD-R=%d, HD DVD-RAM=%d\n", !!(ucp[4] & 0x1), !!(ucp[6] & 0x1)); break; case 0x51: /* HD DVD Write */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" HD DVD-R=%d, HD DVD-RAM=%d\n", !!(ucp[4] & 0x1), !!(ucp[6] & 0x1)); break; case 0x52: /* HD DVD-RW fragment recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BGP=%d\n", !!(ucp[4] & 0x1)); break; case 0x80: /* Hybrid disc */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" RI=%d\n", !!(ucp[4] & 0x1)); break; /* case 0x100: Power management -> see 0x1d entry */ case 0x101: /* SMART */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" PP=%d\n", !!(ucp[4] & 0x1)); break; case 0x102: /* Embedded changer */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" SCC=%d, SDP=%d, highest slot number=%d\n", !!(ucp[4] & 0x10), !!(ucp[4] & 0x4), (ucp[7] & 0x1f)); break; case 0x103: /* CD audio external play (obsolete) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Scan=%d, SCM=%d, SV=%d, number of volume levels=%d\n", !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1), (ucp[6] << 8) + ucp[7]); break; case 0x104: /* Firmware upgrade */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 4) { printf(" additional length [%d] too short\n", len - 4); break; } if (len > 4) printf(" M5=%d\n", !!(ucp[4] & 0x1)); break; case 0x105: /* Timeout */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len > 7) { printf(" Group 3=%d, unit length=%d\n", !!(ucp[4] & 0x1), (ucp[6] << 8) + ucp[7]); } break; case 0x106: /* DVD CSS */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CSS version=%d\n", ucp[7]); break; case 0x107: /* Real time streaming */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" RBCB=%d, SCS=%d, MP2A=%d, WSPD=%d, SW=%d\n", !!(ucp[4] & 0x10), !!(ucp[4] & 0x8), !!(ucp[4] & 0x4), !!(ucp[4] & 0x2), !!(ucp[4] & 0x1)); break; case 0x108: /* Drive serial number */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); num = len - 4; n = sizeof(buff) - 1; n = ((num < n) ? num : n); strncpy(buff, (const char *)(ucp + 4), n); buff[n] = '\0'; printf(" Drive serial number: %s\n", buff); break; /* case 0x109: Media serial number -> see 0x1d entry */ case 0x10a: /* Disc control blocks */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); printf(" Disc control blocks:\n"); for (k = 4; k < len; k += 4) { printf(" 0x%x\n", ((unsigned int)ucp[k] << 24) + (ucp[k + 1] << 16) + (ucp[k + 2] << 8) + ucp[k + 3]); } break; case 0x10b: /* DVD CPRM */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" CPRM version=%d\n", ucp[7]); break; case 0x10c: /* firmware information */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 20) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" %.2s%.2s/%.2s/%.2s %.2s:%.2s:%.2s\n", ucp + 4, ucp + 6, ucp + 8, ucp + 10, ucp + 12, ucp + 14, ucp + 16); break; case 0x10d: /* AACS */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BNG=%d, Block count for binding nonce=%d\n", !!(ucp[4] & 0x1), ucp[5]); printf(" Number of AGIDs=%d, AACS version=%d\n", (ucp[6] & 0xf), ucp[7]); break; case 0x10e: /* DVD CSS managed recording */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" Maximum number of scrambled extent information " "entries=%d\n", ucp[4]); break; /* case 0x110: VCPS -> see 0x1d entry */ /* case 0x113: SecurDisc -> see 0x1d entry */ case 0x120: /* BD CPS */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" BD CPS major:minor version number=%d:%d, max open " "SACs=%d\n", ((ucp[5] >> 4) & 0xf), (ucp[5] & 0xf), ucp[6] & 0x3); break; case 0x142: /* OSSC (Optical Security Subsystem Class) */ printf(" version=%d, persist=%d, current=%d [0x%x]\n", ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1), feature); if (len < 8) { printf(" additional length [%d] too short\n", len - 4); break; } printf(" PSAU=%d, LOSPB=%d, ME=%d\n", !!(ucp[4] & 0x80), !!(ucp[4] & 0x40), !!(ucp[4] & 0x1)); num = ucp[5]; printf(" Profile numbers:\n"); for (k = 6; (num > 0) && (k < len); --num, k += 2) { printf(" %d\n", ((unsigned int)ucp[k] << 8) + ucp[k + 1]); } break; default: fprintf(stderr, " Unknown feature [0x%x], version=%d persist=%d, " "current=%d\n", feature, ((ucp[2] >> 2) & 0xf), !!(ucp[2] & 0x2), !!(ucp[2] & 0x1)); dStrHexErr((const char *)ucp, len, 1); break; } } static void decode_config(unsigned char * resp, int max_resp_len, int len, int brief, int inner_hex) { int k, curr_profile, extra_len, feature; unsigned char * ucp; char buff[128]; if (max_resp_len < len) { fprintf(stderr, "<<>>\n", len); len = max_resp_len; } if (len < 8) { fprintf(stderr, "response length too short: %d\n", len); return; } curr_profile = (resp[6] << 8) + resp[7]; if (0 == curr_profile) fprintf(stderr, "No current profile\n"); else printf("Current profile: %s\n", get_profile_str(curr_profile, buff)); printf("Features%s:\n", (brief ? " (in brief)" : "")); ucp = resp + 8; len -= 8; for (k = 0; k < len; k += extra_len, ucp += extra_len) { extra_len = 4 + ucp[3]; feature = (ucp[0] << 8) + ucp[1]; printf(" %s feature\n", get_feature_str(feature, buff)); if (brief) continue; if (inner_hex) { dStrHex((const char *)ucp, extra_len, 1); continue; } if (0 != (extra_len % 4)) printf(" additional length [%d] not a multiple of 4, ignore\n", extra_len - 4); else decode_feature(feature, ucp, extra_len); } } static void list_known(int brief) { int k, num; num = sizeof(feature_desc_arr) / sizeof(feature_desc_arr[0]); printf("Known features:\n"); for (k = 0; k < num; ++k) printf(" %s [0x%x]\n", feature_desc_arr[k].desc, feature_desc_arr[k].val); if (! brief) { printf("Known profiles:\n"); num = sizeof(profile_desc_arr) / sizeof(profile_desc_arr[0]); for (k = 0; k < num; ++k) printf(" %s [0x%x]\n", profile_desc_arr[k].desc, profile_desc_arr[k].val); } } int main(int argc, char * argv[]) { int sg_fd, res, c, len; int peri_type = 0; int brief = 0; int do_hex = 0; int inner_hex = 0; int list = 0; int do_raw = 0; int readonly = 0; int rt = 0; int starting = 0; int verbose = 0; const char * device_name = NULL; char buff[64]; const char * cp; struct sg_simple_inquiry_resp inq_resp; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "bchHilqr:Rs:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'b': brief = 1; break; case 'c': rt = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': inner_hex = 1; break; case 'l': list = 1; break; case 'q': ++readonly; break; case 'r': rt = sg_get_num(optarg); if ((rt < 0) || (rt > 3)) { fprintf(stderr, "bad argument to '--rt'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'R': ++do_raw; break; case 's': starting = sg_get_num(optarg); if ((starting < 0) || (starting > 0xffff)) { fprintf(stderr, "bad argument to '--starting'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (list) { list_known(brief); return 0; } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((sg_fd = sg_cmds_open_device(device_name, 1 /* ro */, verbose)) < 0) { fprintf(stderr, ME "error opening file: %s (ro): %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, verbose)) { if (0 == do_raw) printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); peri_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (0 == do_raw) { if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } } else { fprintf(stderr, ME "%s doesn't respond to a SCSI INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } sg_cmds_close_device(sg_fd); sg_fd = sg_cmds_open_device(device_name, readonly, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error (rw): %s\n", safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } res = sg_ll_get_config(sg_fd, rt, starting, resp_buffer, sizeof(resp_buffer), 1, verbose); ret = res; if (0 == res) { len = (resp_buffer[0] << 24) + (resp_buffer[1] << 16) + (resp_buffer[2] << 8) + resp_buffer[3] + 4; if (do_hex) { if (len > (int)sizeof(resp_buffer)) len = sizeof(resp_buffer); dStrHex((const char *)resp_buffer, len, 0); } else if (do_raw) dStrRaw((const char *)resp_buffer, len); else decode_config(resp_buffer, sizeof(resp_buffer), len, brief, inner_hex); } else { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Get Configuration command: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' option for more information\n"); } res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_safte.c0000664000175000017500000005054012335513125015102 0ustar douggdougg/* * Copyright (c) 2004-2014 Hannes Reinecke and Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program for the Linux OS SCSI subsystem. * * This program accesses a processor device which operates according * to the 'SCSI Accessed Fault-Tolerant Enclosures' (SAF-TE) spec. */ static const char * version_str = "0.25 20140516"; #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #define EBUFF_SZ 256 #define RB_MODE_DESC 3 #define RWB_MODE_DATA 2 #define RWB_MODE_VENDOR 1 #define RB_DESC_LEN 4 #define SAFTE_CFG_FLAG_DOORLOCK 1 #define SAFTE_CFG_FLAG_ALARM 2 #define SAFTE_CFG_FLAG_CELSIUS 3 struct safte_cfg_t { int fans; int psupplies; int slots; int temps; int thermostats; int vendor_specific; int flags; }; struct safte_cfg_t safte_cfg; static unsigned int buf_capacity = 64; static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Buffer ID 0x0: Read Enclosure Configuration (mandatory) */ static int read_safte_configuration(int sg_fd, unsigned char *rb_buff, unsigned int rb_len, int verbose) { int res; if (rb_len < buf_capacity) { fprintf(stderr,"SCSI BUFFER size too small (%d/%d bytes)\n", rb_len, buf_capacity); return SG_LIB_CAT_ILLEGAL_REQ; } if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=0 " "to fetch configuration\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 0, 0, rb_buff, rb_len, 1, verbose); if (res && res != SG_LIB_CAT_RECOVERED) return res; safte_cfg.fans = rb_buff[0]; safte_cfg.psupplies = rb_buff[1]; safte_cfg.slots = rb_buff[2]; safte_cfg.temps = rb_buff[4]; if (rb_buff[3]) safte_cfg.flags |= SAFTE_CFG_FLAG_DOORLOCK; if (rb_buff[5]) safte_cfg.flags |= SAFTE_CFG_FLAG_ALARM; if (rb_buff[6] & 0x80) safte_cfg.flags |= SAFTE_CFG_FLAG_CELSIUS; safte_cfg.thermostats = rb_buff[6] & 0x0f; safte_cfg.vendor_specific = rb_buff[63]; return 0; } static int print_safte_configuration(void) { printf("Enclosure Configuration:\n"); printf("\tNumber of Fans: %d\n", safte_cfg.fans); printf("\tNumber of Power Supplies: %d\n", safte_cfg.psupplies); printf("\tNumber of Device Slots: %d\n", safte_cfg.slots); printf("\tNumber of Temperature Sensors: %d\n", safte_cfg.temps); printf("\tNumber of Thermostats: %d\n", safte_cfg.thermostats); printf("\tVendor unique bytes: %d\n", safte_cfg.vendor_specific); return 0; } /* Buffer ID 0x01: Read Enclosure Status (mandatory) */ static int do_safte_encl_status(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i, offset; unsigned int rb_len; unsigned char *rb_buff; rb_len = safte_cfg.fans + safte_cfg.psupplies + safte_cfg.slots + safte_cfg.temps + 5 + safte_cfg.vendor_specific; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=1 " "to read enclosure status\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 1, 0, rb_buff, rb_len, 0, verbose); if (res && res != SG_LIB_CAT_RECOVERED) return res; if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Enclosure Status:\n"); offset = 0; for (i = 0; i < safte_cfg.fans; i++) { printf("\tFan %d status: ", i); switch(rb_buff[i]) { case 0: printf("operational\n"); break; case 1: printf("malfunctioning\n"); break; case 2: printf("not installed\n"); break; case 80: printf("not reportable\n"); break; default: printf("unknown\n"); break; } } offset += safte_cfg.fans; for (i = 0; i < safte_cfg.psupplies; i++) { printf("\tPower supply %d status: ", i); switch(rb_buff[i + offset]) { case 0: printf("operational / on\n"); break; case 1: printf("operational / off\n"); break; case 0x10: printf("malfunctioning / on\n"); break; case 0x11: printf("malfunctioning / off\n"); break; case 0x20: printf("not present\n"); break; case 0x21: printf("present\n"); break; case 0x80: printf("not reportable\n"); break; default: printf("unknown\n"); break; } } offset += safte_cfg.psupplies; for (i = 0; i < safte_cfg.slots; i++) { printf("\tDevice Slot %d: SCSI ID %d\n", i, rb_buff[i + offset]); } offset += safte_cfg.slots; if (safte_cfg.flags & SAFTE_CFG_FLAG_DOORLOCK) { switch(rb_buff[offset]) { case 0x0: printf("\tDoor lock status: locked\n"); break; case 0x01: printf("\tDoor lock status: unlocked\n"); break; case 0x80: printf("\tDoor lock status: not reportable\n"); break; } } else { printf("\tDoor lock status: not installed\n"); } offset++; if (!(safte_cfg.flags & SAFTE_CFG_FLAG_ALARM)) { printf("\tSpeaker status: not installed\n"); } else { switch(rb_buff[offset]) { case 0x0: printf("\tSpeaker status: off\n"); break; case 0x01: printf("\tSpeaker status: on\n"); break; } } offset++; for (i = 0; i < safte_cfg.temps; i++) { int temp = 0; if (!(safte_cfg.flags & SAFTE_CFG_FLAG_CELSIUS)) temp -= 10; printf("\tTemperature sensor %d: %d deg %c\n", i, rb_buff[i + offset], safte_cfg.flags & SAFTE_CFG_FLAG_CELSIUS?'C':'F'); } offset += safte_cfg.temps; if (safte_cfg.thermostats) { if (rb_buff[offset] & 0x80) { printf("\tEnclosure Temperature alert status: abnormal\n"); } else { printf("\tEnclosure Temperature alert status: normal\n"); } } return 0; } /* Buffer ID 0x02: Read Usage Statistics (optional) */ static int do_safte_usage_statistics(int sg_fd, int do_hex, int do_raw, int verbose) { int res; unsigned int rb_len; unsigned char *rb_buff; unsigned int minutes; rb_len = 16 + safte_cfg.vendor_specific; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=2 " "to read usage statistics\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 2, 0, rb_buff, rb_len, 0, verbose); if (res) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Usage Statistics:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Usage Statistics:\n"); minutes = (rb_buff[0] << 24) + (rb_buff[1] << 16) + (rb_buff[2] << 8) + rb_buff[3]; printf("\tPower on Minutes: %u\n", minutes); minutes = (rb_buff[4] << 24) + (rb_buff[5] << 16) + (rb_buff[6] << 8) + rb_buff[7]; printf("\tPower on Cycles: %u\n", minutes); free(rb_buff); return 0; } /* Buffer ID 0x03: Read Device Insertions (optional) */ static int do_safte_slot_insertions(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i; unsigned int rb_len; unsigned char *rb_buff, slot_status; rb_len = safte_cfg.slots * 2; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=3 " "to read device insertions\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 3, 0, rb_buff, rb_len, 0, verbose); if (res ) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Slot insertions:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Slot insertions:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = (rb_buff[i * 2] << 8) + rb_buff[i * 2]; printf("\tSlot %d: %d insertions", i, slot_status); } free(rb_buff); return 0; } /* Buffer ID 0x04: Read Device Slot Status (mandatory) */ static int do_safte_slot_status(int sg_fd, int do_hex, int do_raw, int verbose) { int res, i; unsigned int rb_len; unsigned char *rb_buff, slot_status; rb_len = safte_cfg.slots * 4; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=4 " "to read device slot status\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 4, 0, rb_buff, rb_len, 0, verbose); if (res && res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Slot status:\n"); for (i = 0; i < safte_cfg.slots; i++) { slot_status = rb_buff[i * 4 + 3]; printf("\tSlot %d: ", i); if (slot_status & 0x7) { if (slot_status & 0x1) printf("inserted "); if (slot_status & 0x2) printf("ready "); if (slot_status & 0x4) printf("activated "); printf("\n"); } else { printf("empty\n"); } } free(rb_buff); return 0; } /* Buffer ID 0x05: Read Global Flags (optional) */ static int do_safte_global_flags(int sg_fd, int do_hex, int do_raw, int verbose) { int res; unsigned int rb_len; unsigned char *rb_buff; rb_len = 16; rb_buff = (unsigned char *)malloc(rb_len); if (verbose > 1) fprintf(stderr, "Use READ BUFFER,mode=vendor_specific,buff_id=5 " "to read global flags\n"); res = sg_ll_read_buffer(sg_fd, RWB_MODE_VENDOR, 5, 0, rb_buff, rb_len, 0, verbose); if (res ) { if (res == SG_LIB_CAT_ILLEGAL_REQ) { printf("Global Flags:\n\tNot implemented\n"); return 0; } if (res != SG_LIB_CAT_RECOVERED) { free(rb_buff); return res; } } if (do_raw > 1) { dStrRaw((const char *)rb_buff, buf_capacity); return 0; } if (do_hex > 1) { dStrHex((const char *)rb_buff, buf_capacity, 1); return 0; } printf("Global Flags:\n"); printf("\tAudible Alarm Control: %s\n", rb_buff[0] & 0x1?"on":"off"); printf("\tGlobal Failure Indicator: %s\n", rb_buff[0] & 0x2?"on":"off"); printf("\tGlobal Warning Indicator: %s\n", rb_buff[0] & 0x4?"on":"off"); printf("\tEnclosure Power: %s\n", rb_buff[0] & 0x8?"on":"off"); printf("\tCooling Failure: %s\n", rb_buff[0] & 0x10?"yes":"no"); printf("\tPower Failure: %s\n", rb_buff[0] & 0x20?"yes":"no"); printf("\tDrive Failure: %s\n", rb_buff[0] & 0x40?"yes":"no"); printf("\tDrive Warning: %s\n", rb_buff[0] & 0x80?"yes":"no"); printf("\tArray Failure: %s\n", rb_buff[1] & 0x1?"yes":"no"); printf("\tArray Warning: %s\n", rb_buff[0] & 0x2?"yes":"no"); printf("\tEnclosure Lock: %s\n", rb_buff[0] & 0x4?"on":"off"); printf("\tEnclosure Identify: %s\n", rb_buff[0] & 0x8?"on":"off"); free(rb_buff); return 0; } static void usage() { fprintf(stderr, "Usage: sg_safte [--config] [--devstatus] [--encstatus] " "[--flags] [--help]\n" " [--hex] [--insertions] [--raw] [--usage] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --config|-c output enclosure configuration\n" " --devstatus|-d output device slot status\n" " --encstatus|-s output enclosure status\n" " --flags|-f output global flags\n" " --help|-h output command usage message then " "exit\n" " --hex|-H output enclosure config in hex\n" " --insertions|-i output insertion statistics\n" " --raw|-r output enclosure config in binary " "to stdout\n" " --usage|-u output usage statistics\n" " --verbose|-v increase verbosity\n" " --version|-v output version then exit\n\n" "Queries a SAF-TE processor device\n"); } static struct option long_options[] = { {"config", 0, 0, 'c'}, {"devstatus", 0, 0, 'd'}, {"encstatus", 0, 0, 's'}, {"flags", 0, 0, 'f'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"insertions", 0, 0, 'i'}, {"raw", 0, 0, 'r'}, {"usage", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; int main(int argc, char * argv[]) { int sg_fd, c, ret, peri_type, no_hex_raw; int res = SG_LIB_CAT_OTHER; const char * device_name = NULL; char ebuff[EBUFF_SZ]; unsigned char *rb_buff; int do_config = 0; int do_status = 0; int do_slots = 0; int do_flags = 0; int do_usage = 0; int do_hex = 0; int do_raw = 0; int verbose = 0; int do_insertions = 0; const char * cp; char buff[48]; char b[80]; struct sg_simple_inquiry_resp inq_resp; const char op_name[] = "READ BUFFER"; while (1) { int option_index = 0; c = getopt_long(argc, argv, "cdfhHirsuvV?", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': do_config = 1; break; case 'd': do_slots = 1; break; case 'f': do_flags = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'i': do_insertions = 1; break; case 'r': ++do_raw; break; case 's': do_status = 1; break; case 'u': do_usage = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, "Version string: %s\n", version_str); exit(0); default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if ((sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose)) < 0) { snprintf(ebuff, EBUFF_SZ, "sg_safte: error opening file: %s (rw)", device_name); perror(ebuff); return SG_LIB_FILE_ERROR; } no_hex_raw = ((0 == do_hex) && (0 == do_raw)); if (no_hex_raw) { if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, verbose)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); peri_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } else { fprintf(stderr, "sg_safte: %s doesn't respond to a SCSI " "INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } } rb_buff = (unsigned char *)malloc(buf_capacity); if (!rb_buff) goto err_out; memset(rb_buff, 0, buf_capacity); res = read_safte_configuration(sg_fd, rb_buff, buf_capacity, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } if (1 == do_raw) { dStrRaw((const char *)rb_buff, buf_capacity); res = 0; goto finish; } if (1 == do_hex) { dStrHex((const char *)rb_buff, buf_capacity, 1); res = 0; goto finish; } if (do_config && no_hex_raw) print_safte_configuration(); if (do_status) { res = do_safte_encl_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_usage) { res = do_safte_usage_statistics(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_insertions) { res = do_safte_slot_insertions(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_slots) { res = do_safte_slot_status(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } if (do_flags) { res = do_safte_global_flags(sg_fd, do_hex, do_raw, verbose); switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: goto err_out; } } finish: res = 0; err_out: switch (res) { case 0: case SG_LIB_CAT_RECOVERED: break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "%s failed: %s\n", op_name, b); break; } ret = res; res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_readcap.c0000664000175000017500000004550112335161436015404 0ustar douggdougg/* This code is does a SCSI READ CAPACITY command on the given device and outputs the result. * Copyright (C) 1999 - 2014 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. This program was originally written with Linux 2.4 kernel series. It now builds for the Linux 2.6 and 3 kernel series and various other operating systems. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" static const char * version_str = "3.92 20140515"; #define ME "sg_readcap: " #define RCAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 static struct option long_options[] = { {"brief", 0, 0, 'b'}, {"help", 0, 0, 'h'}, {"hex", 0, 0, 'H'}, {"lba", 1, 0, 'L'}, {"long", 0, 0, 'l'}, {"16", 0, 0, 'l'}, {"new", 0, 0, 'N'}, {"old", 0, 0, 'O'}, {"pmi", 0, 0, 'p'}, {"raw", 0, 0, 'r'}, {"readonly", 0, 0, 'R'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; struct opts_t { int do_brief; int do_help; int do_hex; int do_lba; int do_long; int do_pmi; int do_raw; int o_readonly; int do_verbose; int do_version; uint64_t llba; const char * device_name; int opt_new; }; static void usage() { fprintf(stderr, "Usage: sg_readcap [--brief] [--help] [--hex] " "[--lba=LBA] [--long] [--16]\n" " [--pmi] [--raw] [--readonly] [--verbose] " "[--version]\n" " DEVICE\n" " where:\n" " --brief|-b brief, two hex numbers: number of blocks " "and block size\n" " --help|-h print this usage message and exit\n" " --hex|-H output response in hexadecimal to stdout\n" " --lba=LBA|-L LBA yields the last block prior to (head " "movement) delay\n" " after LBA [in decimal (def: 0) " "valid with '--pmi']\n" " --long|-l use READ CAPACITY (16) cdb (def: use " "10 byte cdb)\n" " --16 use READ CAPACITY (16) cdb (same as " "--long)\n" " --pmi|-p partial medium indicator (without this " "option shows\n" " total disk capacity) [made obsolete in " "sbc3r26]\n" " --raw|-r output response in binary to stdout\n" " --readonly|-R open DEVICE read-only (def: RCAP(16) " "read-write)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Perform a SCSI READ CAPACITY (10 or 16) command\n"); } static void usage_old() { fprintf(stderr, "Usage: sg_readcap [-16] [-b] [-h] [-H] [-lba=LBA] " "[-pmi] [-r] [-R] [-v] [-V]\n" " DEVICE\n" " where:\n" " -16 use READ CAPACITY (16) cdb (def: use " "10 byte cdb)\n" " -b brief, two hex numbers: number of blocks " "and block size\n" " -h print this usage message and exit\n" " -H output response in hexadecimal to stdout\n" " -lba=LBA yields the last block prior to (head " "movement) delay\n" " after LBA [in hex (def: 0) " "valid with -pmi]\n" " -pmi partial medium indicator (without this option " "shows total\n" " disk capacity)\n" " -r output response in binary to stdout\n" " -R open DEVICE read-only (def: RCAP(16) read-write)\n" " -v increase verbosity\n" " -V print version string and exit\n\n" "Perform a SCSI READ CAPACITY command\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } static int process_cl_new(struct opts_t * op, int argc, char * argv[]) { int c; int a_one = 0; int64_t nn; while (1) { int option_index = 0; c = getopt_long(argc, argv, "16bhHlL:NOprRvV", long_options, &option_index); if (c == -1) break; switch (c) { case '1': ++a_one; break; case '6': if (a_one) ++op->do_long; break; case 'b': ++op->do_brief; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'l': ++op->do_long; break; case 'L': nn = sg_get_llnum(optarg); if (-1 == nn) { fprintf(stderr, "bad argument to '--lba='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } op->llba = nn; /* force READ_CAPACITY16 for large lbas */ if (op->llba > 0xfffffffeULL) ++op->do_long; ++op->do_lba; break; case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; case 'p': ++op->do_pmi; break; case 'r': ++op->do_raw; break; case 'R': ++op->o_readonly; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: fprintf(stderr, "unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->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 * op, int argc, char * argv[]) { int k, jmp_out, plen, num; const char * cp; uint64_t uu; 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 '1': if ('6' == *(cp + 1)) { ++op->do_long; ++cp; --plen; } else jmp_out = 1; break; case 'b': ++op->do_brief; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case 'p': if (0 == strncmp("pmi", cp, 3)) { ++op->do_pmi; cp += 2; plen -= 2; } else jmp_out = 1; break; case 'r': ++op->do_raw; break; case 'R': ++op->o_readonly; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; if (0 == strncmp("lba=", cp, 4)) { num = sscanf(cp + 4, "%" SCNx64 "", &uu); if (1 != num) { printf("Bad value after 'lba=' option\n"); usage(); return SG_LIB_SYNTAX_ERROR; } /* force READ_CAPACITY16 for large lbas */ if (uu > 0xfffffffeULL) ++op->do_long; op->llba = uu; ++op->do_lba; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { fprintf(stderr, "Unrecognized option: %s\n", cp); usage(); return SG_LIB_SYNTAX_ERROR; } } else if (0 == op->device_name) op->device_name = cp; else { fprintf(stderr, "too many arguments, got: %s, not expecting: " "%s\n", op->device_name, cp); usage(); return SG_LIB_SYNTAX_ERROR; } } return 0; } static int process_cl(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = process_cl_old(op, argc, argv); if ((0 == res) && op->opt_new) res = process_cl_new(op, argc, argv); } else { op->opt_new = 1; res = process_cl_new(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = process_cl_old(op, argc, argv); } return res; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, k, res, prot_en, p_type, lbppbe, rw_0_flag; uint64_t llast_blk_addr; int ret = 0; unsigned int last_blk_addr, block_size; unsigned char resp_buff[RCAP16_REPLY_LEN]; char b[80]; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); res = process_cl(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); return 0; } if (op->do_version) { fprintf(stderr, "Version string: %s\n", version_str); return 0; } if (NULL == op->device_name) { fprintf(stderr, "No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } memset(resp_buff, 0, sizeof(resp_buff)); if ((0 == op->do_pmi) && (op->llba > 0)) { fprintf(stderr, ME "lba can only be non-zero when '--pmi' is set\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_long) rw_0_flag = op->o_readonly; else rw_0_flag = 1; /* RCAP(10) has opened RO in past, so leave */ if ((sg_fd = sg_cmds_open_device(op->device_name, rw_0_flag, op->do_verbose)) < 0) { fprintf(stderr, ME "error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (! op->do_long) { res = sg_ll_readcap_10(sg_fd, op->do_pmi, (unsigned int)op->llba, resp_buff, RCAP_REPLY_LEN, 1, op->do_verbose); ret = res; if (0 == res) { if (op->do_hex || op->do_raw) { if (op->do_raw) dStrRaw((const char *)resp_buff, RCAP_REPLY_LEN); else dStrHex((const char *)resp_buff, RCAP_REPLY_LEN, 1); goto good; } last_blk_addr = ((resp_buff[0] << 24) | (resp_buff[1] << 16) | (resp_buff[2] << 8) | resp_buff[3]); if (0xffffffff != last_blk_addr) { block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) | (resp_buff[6] << 8) | resp_buff[7]); if (op->do_brief) { printf("0x%x 0x%x\n", last_blk_addr + 1, block_size); goto good; } printf("Read Capacity results:\n"); if (op->do_pmi) printf(" PMI mode: given lba=0x%" PRIx64 ", last lba " "before delay=0x%x\n", op->llba, last_blk_addr); else printf(" Last logical block address=%u (0x%x), Number " "of blocks=%u\n", last_blk_addr, last_blk_addr, last_blk_addr + 1); printf(" Logical block length=%u bytes\n", block_size); if (! op->do_pmi) { uint64_t total_sz = last_blk_addr + 1; double sz_mb, sz_gb; total_sz *= block_size; sz_mb = ((double)(last_blk_addr + 1) * block_size) / (double)(1048576); sz_gb = ((double)(last_blk_addr + 1) * block_size) / (double)(1000000000L); printf("Hence:\n"); #ifdef SG_LIB_MINGW printf(" Device size: %" PRIu64 " bytes, %g MiB, %g " "GB\n", total_sz, sz_mb, sz_gb); #else printf(" Device size: %" PRIu64 " bytes, %.1f MiB, " "%.2f GB\n", total_sz, sz_mb, sz_gb); #endif } goto good; } else { printf("READ CAPACITY (10) indicates device capacity too " "large\n now trying 16 byte cdb variant\n"); op->do_long = 1; } } else if (SG_LIB_CAT_INVALID_OP == res) { op->do_long = 1; sg_cmds_close_device(sg_fd); if ((sg_fd = sg_cmds_open_device(op->device_name, op->o_readonly, op->do_verbose)) < 0) { fprintf(stderr, ME "error re-opening file: %s (rw): %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->do_verbose) fprintf(stderr, "READ CAPACITY (10) not supported, trying " "READ CAPACITY (16)\n"); } else if (res) { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); fprintf(stderr, "READ CAPACITY (10) failed: %s\n", b); } } if (op->do_long) { res = sg_ll_readcap_16(sg_fd, op->do_pmi, op->llba, resp_buff, RCAP16_REPLY_LEN, 1, op->do_verbose); ret = res; if (0 == res) { if (op->do_hex || op->do_raw) { if (op->do_raw) dStrRaw((const char *)resp_buff, RCAP16_REPLY_LEN); else dStrHex((const char *)resp_buff, RCAP16_REPLY_LEN, 1); goto good; } for (k = 0, llast_blk_addr = 0; k < 8; ++k) { llast_blk_addr <<= 8; llast_blk_addr |= resp_buff[k]; } block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) | (resp_buff[10] << 8) | resp_buff[11]); if (op->do_brief) { printf("0x%" PRIx64 " 0x%x\n", llast_blk_addr + 1, block_size); goto good; } prot_en = !!(resp_buff[12] & 0x1); p_type = ((resp_buff[12] >> 1) & 0x7); printf("Read Capacity results:\n"); printf(" Protection: prot_en=%d, p_type=%d, p_i_exponent=%d", prot_en, p_type, ((resp_buff[13] >> 4) & 0xf)); if (prot_en) printf(" [type %d protection]\n", p_type + 1); else printf("\n"); printf(" Logical block provisioning: lbpme=%d, lbprz=%d\n", !!(resp_buff[14] & 0x80), !!(resp_buff[14] & 0x40)); if (op->do_pmi) printf(" PMI mode: given lba=0x%" PRIx64 ", last lba " "before delay=0x%" PRIx64 "\n", op->llba, llast_blk_addr); else printf(" Last logical block address=%" PRIu64 " (0x%" PRIx64 "), Number of logical blocks=%" PRIu64 "\n", llast_blk_addr, llast_blk_addr, llast_blk_addr + 1); printf(" Logical block length=%u bytes\n", block_size); lbppbe = resp_buff[13] & 0xf; printf(" Logical blocks per physical block exponent=%d", lbppbe); if (lbppbe > 0) printf(" [so physical block length=%u bytes]\n", block_size * (1 << lbppbe)); else printf("\n"); printf(" Lowest aligned logical block address=%d\n", ((resp_buff[14] & 0x3f) << 8) + resp_buff[15]); if (! op->do_pmi) { uint64_t total_sz = llast_blk_addr + 1; double sz_mb, sz_gb; total_sz *= block_size; sz_mb = ((double)(llast_blk_addr + 1) * block_size) / (double)(1048576); sz_gb = ((double)(llast_blk_addr + 1) * block_size) / (double)(1000000000L); printf("Hence:\n"); #ifdef SG_LIB_MINGW printf(" Device size: %" PRIu64 " bytes, %g MiB, %g GB\n", total_sz, sz_mb, sz_gb); #else printf(" Device size: %" PRIu64 " bytes, %.1f MiB, %.2f " "GB\n", total_sz, sz_mb, sz_gb); #endif } goto good; } else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "bad field in READ CAPACITY (16) cdb " "including unsupported service action\n"); else if (res) { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); fprintf(stderr, "READ CAPACITY (16) failed: %s\n", b); } } if (op->do_brief) printf("0x0 0x0\n"); good: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_compare_and_write.c0000664000175000017500000005243412363426266017500 0ustar douggdougg/* * Copyright (c) 2012-2014, Kaminario Technologies LTD * All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This command performs a SCSI COMPARE AND WRITE. See SBC-3 at * http://www.t10.org * */ #ifndef __sun #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #endif #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" static const char * version_str = "1.09 20140715"; #define DEF_BLOCK_SIZE 512 #define DEF_NUM_BLOCKS (1) #define DEF_BLOCKS_PER_TRANSFER 8 #define DEF_TIMEOUT_SECS 60 #define COMPARE_AND_WRITE_OPCODE (0x89) #define COMPARE_AND_WRITE_CDB_SIZE (16) #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define ME "sg_compare_and_write: " static struct option long_options[] = { {"dpo", no_argument, 0, 'd'}, {"fua", no_argument, 0, 'f'}, {"fua_nv", no_argument, 0, 'F'}, {"group", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'i'}, {"inc", required_argument, 0, 'C'}, {"inw", required_argument, 0, 'D'}, {"lba", required_argument, 0, 'l'}, {"num", required_argument, 0, 'n'}, {"quiet", no_argument, 0, 'q'}, {"timeout", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wrprotect", required_argument, 0, 'w'}, {"xferlen", required_argument, 0, 'x'}, {0, 0, 0, 0}, }; struct caw_flags { int dpo; int fua; int fua_nv; int group; int wrprotect; }; struct opts_t { const char * ifn; const char * wfn; int wfn_given; uint64_t lba; int numblocks; int quiet; int verbose; int timeout; int xfer_len; const char * device_name; struct caw_flags flags; }; static void usage() { fprintf(stderr, "Usage: " "sg_compare_and_write [--dpo] [--fua] [--fua_nv] " "[--group=GN] [--help]\n" " --in=IF [--inw=WF] --lba=LBA " "[--num=NUM]\n" " [--quiet] [--timeout=TO] " "[--verbose] [--version]\n" " [--wrpotect=WP] [--xferlen=LEN] " "DEVICE\n" " where:\n" " --dpo|-d set the dpo bit in cdb (def: " "clear)\n" " --fua|-f set the fua bit in cdb (def: " "clear)\n" " --fua_nv|-F set the fua_nv bit in cdb (def: " "clear)\n" " --group=GN|-g GN GN is GROUP NUMBER to set in " "cdb (def: 0)\n" " --help|-h print out usage message\n" " --in=IF|-i IF IF is a file containing a compare " "buffer and\n" " optionally a write buffer (when " "--inw=WF is\n" " not given)\n" " --inw=WF|-D WF WF is a file containing a write " "buffer\n" " --lba=LBA|-l LBA LBA of the first block to compare " "and write\n" " --num=NUM|-n NUM number of blocks to " "compare/write (def: 1)\n" " --quiet|-q suppress MISCOMPARE report to " "stderr,\n" " still sets exit status of 14\n" " --timeout=TO|-t TO timeout for the command " "(def: 60 secs)\n" " --verbose|-v increase verbosity (use '-vv' for " "more)\n" " --version|-V print version string then exit\n" " --wrprotect=WP|-w WP write protect information " "(def: 0)\n" " --xferlen=LEN|-x LEN number of bytes to transfer. " "Default is\n" " (2 * NUM * 512) or 1024 when " "NUM is 1\n" "\n" "Performs a SCSI COMPARE AND WRITE operation.\n"); } static int parse_args(int argc, char* argv[], struct opts_t * op) { int c; int lba_given = 0; int if_given = 0; int64_t ll; op->numblocks = DEF_NUM_BLOCKS; /* COMPARE AND WRITE defines 2*buffers compare + write */ op->xfer_len = 0; op->timeout = DEF_TIMEOUT_SECS; op->device_name = NULL; while (1) { int option_index = 0; c = getopt_long(argc, argv, "C:dD:fFg:hi:l:n:qt:vVw:x:", long_options, &option_index); if (c == -1) break; switch (c) { case 'C': case 'i': op->ifn = optarg; if_given = 1; break; case 'd': op->flags.dpo = 1; break; case 'D': op->wfn = optarg; op->wfn_given = 1; break; case 'F': op->flags.fua_nv = 1; break; case 'f': op->flags.fua = 1; break; case 'g': op->flags.group = sg_get_num(optarg); if ((op->flags.group < 0) || (op->flags.group > 31)) { fprintf(stderr, "argument to '--group' " "expected to be 0 to 31\n"); goto out_err_no_usage; } break; case 'h': case '?': usage(); exit(0); case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); goto out_err_no_usage; } op->lba = (uint64_t)ll; lba_given = 1; break; case 'n': op->numblocks = sg_get_num(optarg); if ((op->numblocks < 0) || (op->numblocks > 255)) { fprintf(stderr, "bad argument to '--num', " "expect 0 to 255\n"); goto out_err_no_usage; } break; case 'q': ++op->quiet; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { fprintf(stderr, "bad argument to " "'--timeout'\n"); goto out_err_no_usage; } break; case 'v': ++op->verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); exit(0); case 'w': op->flags.wrprotect = sg_get_num(optarg); if (op->flags.wrprotect >> 3) { fprintf(stderr, "bad argument to " "'--wrprotect' not in range 0-7\n"); goto out_err_no_usage; } break; case 'x': op->xfer_len = sg_get_num(optarg); if (op->xfer_len < 0) { fprintf(stderr, "bad argument to " "'--xferlen'\n"); goto out_err_no_usage; } break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); goto out_err; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: " "%s\n", argv[optind]); goto out_err; } } if (NULL == op->device_name) { fprintf(stderr, "missing device name!\n"); goto out_err; } if (!if_given) { fprintf(stderr, "missing input file\n"); goto out_err; } if (!lba_given) { fprintf(stderr, "missing lba\n"); goto out_err; } if (0 == op->xfer_len) op->xfer_len = 2 * op->numblocks * DEF_BLOCK_SIZE; return 0; out_err: usage(); out_err_no_usage: exit(1); } #define FLAG_FUA (0x8) #define FLAG_FUA_NV (0x2) #define FLAG_DPO (0x10) #define WRPROTECT_MASK (0x7) #define WRPROTECT_SHIFT (5) static int sg_build_scsi_cdb(unsigned char * cdbp, unsigned int blocks, int64_t start_block, struct caw_flags flags) { memset(cdbp, 0, COMPARE_AND_WRITE_CDB_SIZE); cdbp[0] = COMPARE_AND_WRITE_OPCODE; cdbp[1] = (flags.wrprotect & WRPROTECT_MASK) << WRPROTECT_SHIFT; if (flags.dpo) cdbp[1] |= FLAG_DPO; if (flags.fua) cdbp[1] |= FLAG_FUA; if (flags.fua_nv) cdbp[1] |= FLAG_FUA_NV; cdbp[2] = (unsigned char)((start_block >> 56) & 0xff); cdbp[3] = (unsigned char)((start_block >> 48) & 0xff); cdbp[4] = (unsigned char)((start_block >> 40) & 0xff); cdbp[5] = (unsigned char)((start_block >> 32) & 0xff); cdbp[6] = (unsigned char)((start_block >> 24) & 0xff); cdbp[7] = (unsigned char)((start_block >> 16) & 0xff); cdbp[8] = (unsigned char)((start_block >> 8) & 0xff); cdbp[9] = (unsigned char)(start_block & 0xff); /* cdbp[10-12] are reserved */ cdbp[13] = (unsigned char)(blocks & 0xff); cdbp[14] = (unsigned char)(flags.group & 0x1f); return 0; } /* Returns 0 for success, SG_LIB_CAT_MISCOMPARE if compare fails, * various other SG_LIB_CAT_*, otherwise -1 . */ static int sg_compare_and_write(int sg_fd, unsigned char * buff, int blocks, int64_t lba, int xfer_len, struct caw_flags flags, int noisy, int verbose) { int k, sense_cat, valid, slen, res, ret; unsigned char cawCmd[COMPARE_AND_WRITE_CDB_SIZE]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; uint64_t ull = 0; if (sg_build_scsi_cdb(cawCmd, blocks, lba, flags)) { fprintf(stderr, ME "bad cdb build, lba=0x%" PRIx64 ", " "blocks=%d\n", lba, blocks); return -1; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Could not construct scsit_pt_obj, " "out of " "memory\n"); return -1; } set_scsi_pt_cdb(ptvp, cawCmd, COMPARE_AND_WRITE_CDB_SIZE); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, buff, xfer_len); if (verbose > 1) { fprintf(stderr, " Compare and write cdb: "); for (k = 0; k < COMPARE_AND_WRITE_CDB_SIZE; ++k) fprintf(stderr, "%02x ", cawCmd[k]); fprintf(stderr, "\n"); } if ((verbose > 2) && (xfer_len > 0)) { fprintf(stderr, " Data-out buffer contents:\n"); dStrHexErr((const char *)buff, xfer_len, 1); } res = do_scsi_pt(ptvp, sg_fd, DEF_TIMEOUT_SECS, verbose); ret = sg_cmds_process_resp(ptvp, "COMPARE AND WRITE", res, 0, sense_b, noisy, verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) fprintf(stderr, "Medium or hardware " "error starting at lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); else fprintf(stderr, "Medium or hardware " "error\n"); ret = sense_cat; break; case SG_LIB_CAT_MISCOMPARE: ret = sense_cat; if (! (noisy || verbose)) break; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) fprintf(stderr, "Miscompare at byte offset: %" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); else fprintf(stderr, "Miscompare reported\n"); break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } static int open_if(const char * fn, int got_stdin) { int fd; if (got_stdin) fd = STDIN_FILENO; else { fd = open(fn, O_RDONLY); if (fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", fn, safe_strerror(errno)); return -SG_LIB_FILE_ERROR; } } if (sg_set_binary_mode(fd) < 0) { perror("sg_set_binary_mode"); return -SG_LIB_FILE_ERROR; } return fd; } static int open_dev(const char * outf, int verbose) { int sg_fd = sg_cmds_open_device(outf, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", outf, safe_strerror(-sg_fd)); return -SG_LIB_FILE_ERROR; } return sg_fd; } int main(int argc, char * argv[]) { int res, half_xlen, ifn_stdin; int infd = -1; int wfd = -1; int devfd = -1; unsigned char * wrkBuff = NULL; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); res = parse_args(argc, argv, op); if (res != 0) { fprintf(stderr, "Failed parsing args\n"); goto out; } if (op->verbose) { fprintf(stderr, "Running COMPARE AND WRITE command with the " "following options:\n in=%s ", op->ifn); if (op->wfn_given) fprintf(stderr, "inw=%s ", op->wfn); fprintf(stderr, "device=%s\n lba=0x%" PRIx64 " num_blocks=%d xfer_len=%d timeout=%d\n", op->device_name, op->lba, op->numblocks, op->xfer_len, op->timeout); } ifn_stdin = ((1 == strlen(op->ifn)) && ('-' == op->ifn[0])); infd = open_if(op->ifn, ifn_stdin); if (infd < 0) { res = -infd; goto out; } if (op->wfn_given) { if ((1 == strlen(op->wfn)) && ('-' == op->wfn[0])) { fprintf(stderr, ME "don't allow stdin for write " "file\n"); res = SG_LIB_FILE_ERROR; goto out; } wfd = open_if(op->wfn, 0); if (wfd < 0) { res = -wfd; goto out; } } devfd = open_dev(op->device_name, op->verbose); if (devfd < 0) { res = -devfd; goto out; } wrkBuff = (unsigned char *)malloc(op->xfer_len); if (0 == wrkBuff) { fprintf(stderr, "Not enough user memory\n"); res = SG_LIB_CAT_OTHER; goto out; } if (op->wfn_given) { half_xlen = op->xfer_len / 2; res = read(infd, wrkBuff, half_xlen); if (res < 0) { fprintf(stderr, "Could not read from %s", op->ifn); goto out; } else if (res < half_xlen) { fprintf(stderr, "Read only %d bytes (expected %d) " "from %s\n", res, half_xlen, op->ifn); goto out; } res = read(wfd, wrkBuff + half_xlen, half_xlen); if (res < 0) { fprintf(stderr, "Could not read from %s", op->wfn); goto out; } else if (res < half_xlen) { fprintf(stderr, "Read only %d bytes (expected %d) " "from %s\n", res, half_xlen, op->wfn); goto out; } } else { res = read(infd, wrkBuff, op->xfer_len); if (res < 0) { fprintf(stderr, "Could not read from %s", op->ifn); goto out; } else if (res < op->xfer_len) { fprintf(stderr, "Read only %d bytes (expected %d) " "from %s\n", res, op->xfer_len, op->ifn); goto out; } } res = sg_compare_and_write(devfd, wrkBuff, op->numblocks, op->lba, op->xfer_len, op->flags, !op->quiet, op->verbose); out: if (0 != res) { char b[80]; switch (res) { case SG_LIB_CAT_MEDIUM_HARD: case SG_LIB_CAT_MISCOMPARE: case SG_LIB_FILE_ERROR: break; /* already reported */ default: sg_get_category_sense_str(res, sizeof(b), b, op->verbose); fprintf(stderr, ME "SCSI COMPARE AND WRITE: %s\n", b); break; } } if (wrkBuff) free(wrkBuff); if ((infd >= 0) && (! ifn_stdin)) close(infd); if (wfd >= 0) close(wfd); if (devfd >= 0) close(devfd); return res; } sg3_utils-1.40/src/sg_unmap.c0000664000175000017500000004233312326640175015127 0ustar douggdougg/* * Copyright (c) 2009-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This utility invokes the UNMAP SCSI command to unmap one or more * logical blocks. */ static const char * version_str = "1.07 20140423"; #define DEF_TIMEOUT_SECS 60 #define MAX_NUM_ADDR 128 #ifndef UINT32_MAX #define UINT32_MAX ((uint32_t)-1) #endif static struct option long_options[] = { {"anchor", no_argument, 0, 'a'}, {"grpnum", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'I'}, {"lba", required_argument, 0, 'l'}, {"num", required_argument, 0, 'n'}, {"timeout", required_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_unmap [--anchor] [--grpnum=GN] [--help] [--in=FILE]\n" " [--lba=LBA,LBA...] [--num=NUM,NUM...] " "[--timeout=TO]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --anchor|-a set anchor field in cdb\n" " --grpnum=GN|-g GN GN is group number field (def: 0)\n" " --help|-h print out usage message\n" " --in=FILE|-I FILE read LBA, NUM pairs from FILE (if " "FILE is '-'\n" " then stdin is read)\n" " --lba=LBA,LBA...|-l LBA,LBA... LBA is the logical block " "address\n" " to start NUM unmaps\n" " --num=NUM,NUM...|-n NUM,NUM... NUM is number of logical " "blocks to\n" " unmap starting at " "corresponding LBA\n" " --timeout=TO|-t TO command timeout (unit: seconds) " "(def: 60)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Perform a SCSI UNMAP command. LBA, NUM and the values in FILE " "are assumed\n" "to be decimal. Use '0x' prefix or 'h' suffix for hex values.\n" "Example to unmap LBA 0x12345:\n" " sg_unmap --lba=0x12345 --num=1 /dev/sdb\n" ); } #if 0 /* Trying to decode multipliers as sg_get_llnum() [in sg_libs] does would * only confuse things here, so use this local trimmed version */ static int64_t get_llnum(const char * buf) { int res, len; int64_t num; uint64_t unum; if ((NULL == buf) || ('\0' == buf[0])) return -1LL; len = strspn(buf, "0123456789aAbBcCdDeEfFhHxX"); if (0 == len) return -1LL; if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { res = sscanf(buf + 2, "%" SCNx64 "", &unum); num = unum; } else if ('H' == toupper(buf[len - 1])) { res = sscanf(buf, "%" SCNx64 "", &unum); num = unum; } else res = sscanf(buf, "%" SCNd64 "", &num); if (1 == res) return num; else return -1LL; } #endif /* Read numbers (up to 64 bits in size) from command line (comma (or * (single) space) separated list). Assumed decimal unless prefixed * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex). * Returns 0 if ok, or 1 if error. */ static int build_lba_arr(const char * inp, uint64_t * lba_arr, int * lba_arr_len, int max_arr_len) { int in_len, k; const char * lcp; int64_t ll; char * cp; char * c2p; if ((NULL == inp) || (NULL == lba_arr) || (NULL == lba_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *lba_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ pr2serr("'--lba' cannot be read from stdin\n"); return 1; } else { /* list of numbers (default decimal) on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, "); if (in_len != k) { pr2serr("build_lba_arr: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { ll = sg_get_llnum(lcp); if (-1 != ll) { lba_arr[k] = (uint64_t)ll; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { pr2serr("build_lba_arr: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *lba_arr_len = k + 1; if (k == max_arr_len) { pr2serr("build_lba_arr: array length exceeded\n"); return 1; } } return 0; } /* Read numbers (up to 32 bits in size) from command line (comma (or * (single) space) separated list). Assumed decimal unless prefixed * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex). * Returns 0 if ok, or 1 if error. */ static int build_num_arr(const char * inp, uint32_t * num_arr, int * num_arr_len, int max_arr_len) { int in_len, k; const char * lcp; int64_t ll; char * cp; char * c2p; if ((NULL == inp) || (NULL == num_arr) || (NULL == num_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *num_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ pr2serr("'--len' cannot be read from stdin\n"); return 1; } else { /* list of numbers (default decimal) on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP, "); if (in_len != k) { pr2serr("build_num_arr: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { ll = sg_get_llnum(lcp); if (-1 != ll) { if (ll > UINT32_MAX) { pr2serr("build_num_arr: number exceeds 32 bits at pos " "%d\n", (int)(lcp - inp + 1)); return 1; } num_arr[k] = (uint32_t)ll; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { pr2serr("build_num_arr: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *num_arr_len = k + 1; if (k == max_arr_len) { pr2serr("build_num_arr: array length exceeded\n"); return 1; } } return 0; } /* Read numbers from filename (or stdin) line by line (comma (or * (single) space) separated list). Assumed decimal unless prefixed * by '0x', '0X' or contains trailing 'h' or 'H' (which indicate hex). * Returns 0 if ok, or 1 if error. */ static int build_joint_arr(const char * file_name, uint64_t * lba_arr, uint32_t * num_arr, int * arr_len, int max_arr_len) { char line[1024]; int off = 0; int in_len, k, j, m, have_stdin, ind, bit0; char * lcp; FILE * fp; int64_t ll; have_stdin = ((1 == strlen(file_name)) && ('-' == file_name[0])); if (have_stdin) fp = stdin; else { fp = fopen(file_name, "r"); if (NULL == fp) { pr2serr("build_joint_arr: unable to open %s\n", file_name); return 1; } } for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; // could improve with carry_over logic if sizeof(line) too small in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; } } if (in_len < 1) continue; lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfFhHxXiIkKmMgGtTpP ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("build_joint_arr: syntax error at line %d, pos %d\n", j + 1, m + k + 1); return 1; } for (k = 0; k < 1024; ++k) { ll = sg_get_llnum(lcp); if (-1 != ll) { ind = ((off + k) >> 1); bit0 = 0x1 & (off + k); if (ind >= max_arr_len) { pr2serr("build_joint_arr: array length exceeded\n"); return 1; } if (bit0) { if (ll > UINT32_MAX) { pr2serr("build_joint_arr: number exceeds 32 bits in " "line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } num_arr[ind] = (uint32_t)ll; } else lba_arr[ind] = (uint64_t)ll; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("build_joint_arr: error on line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } } off += (k + 1); } if (0x1 & off) { pr2serr("build_joint_arr: expect LBA,NUM pairs but decoded odd " "number\n from %s\n", have_stdin ? "stdin" : file_name); return 1; } *arr_len = off >> 1; return 0; } int main(int argc, char * argv[]) { int sg_fd, res, c, num, k, j; int grpnum = 0; const char * lba_op = NULL; const char * num_op = NULL; const char * in_op = NULL; int addr_arr_len = 0; int num_arr_len = 0; int anchor = 0; int timeout = DEF_TIMEOUT_SECS; int verbose = 0; const char * device_name = NULL; uint64_t addr_arr[MAX_NUM_ADDR]; uint32_t num_arr[MAX_NUM_ADDR]; unsigned char param_arr[8 + (MAX_NUM_ADDR * 16)]; int param_len = 4; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ag:hIHl:n:t:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++anchor; break; case 'g': num = sscanf(optarg, "%d", &res); if ((1 == num) && (res >= 0) && (res <= 31)) grpnum = res; else { pr2serr("value for '--grpnum=' must be 0 to 31\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'I': in_op = optarg; break; case 'l': lba_op = optarg; break; case 'n': num_op = optarg; break; case 't': timeout = sg_get_num(optarg); if (timeout < 0) { pr2serr("bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } else if (0 == timeout) timeout = DEF_TIMEOUT_SECS; break; case 'v': ++verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { pr2serr("missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (in_op && (lba_op || num_op)) { pr2serr("expect '--in=' by itself, or both '--lba=' and '--num='\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else if (in_op || (lba_op && num_op)) ; else { if (lba_op) pr2serr("since '--lba=' is given, also need '--num='\n"); else pr2serr("expect either both '--lba=' and '--num=', or " "'--in=' by itself\n"); usage(); return SG_LIB_SYNTAX_ERROR; } memset(addr_arr, 0, sizeof(addr_arr)); memset(num_arr, 0, sizeof(num_arr)); addr_arr_len = 0; if (lba_op && num_op) { if (0 != build_lba_arr(lba_op, addr_arr, &addr_arr_len, MAX_NUM_ADDR)) { pr2serr("bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } if (0 != build_num_arr(num_op, num_arr, &num_arr_len, MAX_NUM_ADDR)) { pr2serr("bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } if ((addr_arr_len != num_arr_len) || (num_arr_len <= 0)) { pr2serr("need same number of arguments to '--lba=' " "and '--num=' options\n"); return SG_LIB_SYNTAX_ERROR; } } if (in_op) { if (0 != build_joint_arr(in_op, addr_arr, num_arr, &addr_arr_len, MAX_NUM_ADDR)) { pr2serr("bad argument to '--in'\n"); return SG_LIB_SYNTAX_ERROR; } if (addr_arr_len <= 0) { pr2serr("no addresses found in '--in=' argument, file: %s\n", in_op); return SG_LIB_SYNTAX_ERROR; } } param_len = 8 + (16 * addr_arr_len); memset(param_arr, 0, param_len); k = 8; for (j = 0; j < addr_arr_len; ++j) { param_arr[k++] = (addr_arr[j] >> 56) & 0xff; param_arr[k++] = (addr_arr[j] >> 48) & 0xff; param_arr[k++] = (addr_arr[j] >> 40) & 0xff; param_arr[k++] = (addr_arr[j] >> 32) & 0xff; param_arr[k++] = (addr_arr[j] >> 24) & 0xff; param_arr[k++] = (addr_arr[j] >> 16) & 0xff; param_arr[k++] = (addr_arr[j] >> 8) & 0xff; param_arr[k++] = addr_arr[j] & 0xff; param_arr[k++] = (num_arr[j] >> 24) & 0xff; param_arr[k++] = (num_arr[j] >> 16) & 0xff; param_arr[k++] = (num_arr[j] >> 8) & 0xff; param_arr[k++] = num_arr[j] & 0xff; k += 4; } k = 0; num = param_len - 2; param_arr[k++] = (num >> 8) & 0xff; param_arr[k++] = num & 0xff; num = param_len - 8; param_arr[k++] = (num >> 8) & 0xff; param_arr[k++] = num & 0xff; sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } res = sg_ll_unmap_v2(sg_fd, anchor, grpnum, timeout, param_arr, param_len, 1, verbose); ret = res; if (SG_LIB_CAT_NOT_READY == res) { pr2serr("UNMAP failed, device not ready\n"); goto err_out; } else if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("UNMAP, unit attention\n"); goto err_out; } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("UNMAP, aborted command\n"); goto err_out; } else if (SG_LIB_CAT_INVALID_OP == res) { pr2serr("UNMAP not supported\n"); goto err_out; } else if (SG_LIB_CAT_ILLEGAL_REQ == res) { pr2serr("bad field in UNMAP cdb\n"); goto err_out; } else if (0 != res) { pr2serr("UNMAP failed (use '-v' to get more information)\n"); goto err_out; } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_map26.c0000664000175000017500000013074112142450532014725 0ustar douggdougg/* * Copyright (c) 2005-2013 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ /* A utility program for the Linux OS SCSI subsystem. * * * This program maps a primary SCSI device node name to the corresponding * SCSI generic device node name (or vice versa). Targets linux * kernel 2.6 or 3 series. Sysfs device names can also be mapped. */ /* #define _XOPEN_SOURCE 500 */ /* needed to see DT_REG and friends when compiled with: c99 pedantic */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" static const char * version_str = "1.09 20130507"; #define ME "sg_map26: " #define NT_NO_MATCH 0 #define NT_SD 1 #define NT_SR 2 #define NT_HD 3 #define NT_ST 4 #define NT_OSST 5 #define NT_SG 6 #define NT_CH 7 #define NT_REG 8 #define NT_DIR 9 #define NAME_LEN_MAX 260 #define D_NAME_LEN_MAX 516 #ifndef SCSI_CHANGER_MAJOR #define SCSI_CHANGER_MAJOR 86 #endif #ifndef OSST_MAJOR #define OSST_MAJOR 206 #endif /* scandir() and stat() categories */ #define FT_OTHER 0 #define FT_REGULAR 1 #define FT_BLOCK 2 #define FT_CHAR 3 #define FT_DIR 4 /* older major.h headers may not have these */ #ifndef SCSI_DISK8_MAJOR #define SCSI_DISK8_MAJOR 128 #define SCSI_DISK9_MAJOR 129 #define SCSI_DISK10_MAJOR 130 #define SCSI_DISK11_MAJOR 131 #define SCSI_DISK12_MAJOR 132 #define SCSI_DISK13_MAJOR 133 #define SCSI_DISK14_MAJOR 134 #define SCSI_DISK15_MAJOR 135 #endif /* st minor decodes from Kai Makisara 20081008 */ #define ST_NBR_MODE_BITS 2 #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) #define TAPE_NR(minor) ( (((minor) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \ ((minor) & ~(-1 << ST_MODE_SHIFT)) ) static const char * sys_sg_dir = "/sys/class/scsi_generic/"; static const char * sys_sd_dir = "/sys/block/"; static const char * sys_sr_dir = "/sys/block/"; static const char * sys_hd_dir = "/sys/block/"; static const char * sys_st_dir = "/sys/class/scsi_tape/"; static const char * sys_sch_dir = "/sys/class/scsi_changer/"; static const char * sys_osst_dir = "/sys/class/onstream_tape/"; static const char * def_dev_dir = "/dev"; static struct option long_options[] = { {"dev_dir", 1, 0, 'd'}, {"given_is", 1, 0, 'g'}, {"help", 0, 0, 'h'}, {"result", 1, 0, 'r'}, {"symlink", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static const char * nt_names[] = { "No matching", "disk", "cd/dvd", "hd", "tape", "tape (osst)", "generic (sg)", "changer", "regular file", "directory", }; static void usage() { fprintf(stderr, "Usage: " "sg_map26 [--dev_dir=DIR] [--given_is=0...1] [--help] " "[--result=0...3]\n" " [--symlink] [--verbose] [--version] " "DEVICE\n" " where:\n" " --dev_dir=DIR | -d DIR search in DIR for " "resulting special\n" " (def: directory of DEVICE " "or '/dev')\n" " --given_is=0...1 | -g 0...1 variety of given " "DEVICE\n" " 0->block or char special " "(or symlink to)\n" " 1->sysfs device, 'dev' or " "parent\n" " --help | -h print out usage message\n" " --result=0...3 | -r 0...3 variety of file(s) to " "find\n" " 0->mapped block or char " "special(def)\n" " 1->mapped sysfs path\n" " 2->matching block or " "char special\n" " 3->matching sysfs " "path\n" " --symlink | -s symlinks to special included in " "result\n" " --verbose | -v increase verbosity of output\n" " --version | -V print version string and exit\n\n" "Maps SCSI device node to corresponding generic node (and " "vv)\n" ); } /* ssafe_strerror() contributed by Clayton Weaver Allows for situation in which strerror() is given a wild value (or the C library is incomplete) and returns NULL. Still not thread safe. */ static char safe_errbuf[64] = {'u', 'n', 'k', 'n', 'o', 'w', 'n', ' ', 'e', 'r', 'r', 'n', 'o', ':', ' ', 0}; static char * ssafe_strerror(int errnum) { size_t len; char * errstr; errstr = strerror(errnum); if (NULL == errstr) { len = strlen(safe_errbuf); snprintf(safe_errbuf + len, sizeof(safe_errbuf) - len, "%i", errnum); safe_errbuf[sizeof(safe_errbuf) - 1] = '\0'; /* bombproof */ return safe_errbuf; } return errstr; } static int nt_typ_from_filename(const char * filename, int * majj, int * minn) { struct stat st; int ma, mi; if (stat(filename, &st) < 0) return -errno; ma = major(st.st_rdev); mi = minor(st.st_rdev); if (majj) *majj = ma; if (minn) *minn = mi; if (S_ISCHR(st.st_mode)) { switch(ma) { case OSST_MAJOR: return NT_OSST; case SCSI_GENERIC_MAJOR: return NT_SG; case SCSI_TAPE_MAJOR: return NT_ST; case SCSI_CHANGER_MAJOR: return NT_CH; default: return NT_NO_MATCH; } } else if (S_ISBLK(st.st_mode)) { switch(ma) { case SCSI_DISK0_MAJOR: case SCSI_DISK1_MAJOR: case SCSI_DISK2_MAJOR: case SCSI_DISK3_MAJOR: case SCSI_DISK4_MAJOR: case SCSI_DISK5_MAJOR: case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_DISK8_MAJOR: case SCSI_DISK9_MAJOR: case SCSI_DISK10_MAJOR: case SCSI_DISK11_MAJOR: case SCSI_DISK12_MAJOR: case SCSI_DISK13_MAJOR: case SCSI_DISK14_MAJOR: case SCSI_DISK15_MAJOR: return NT_SD; case SCSI_CDROM_MAJOR: return NT_SR; case IDE0_MAJOR: case IDE1_MAJOR: case IDE2_MAJOR: case IDE3_MAJOR: case IDE4_MAJOR: case IDE5_MAJOR: case IDE6_MAJOR: case IDE7_MAJOR: case IDE8_MAJOR: case IDE9_MAJOR: return NT_HD; default: return NT_NO_MATCH; } } else if (S_ISREG(st.st_mode)) return NT_REG; else if (S_ISDIR(st.st_mode)) return NT_DIR; return NT_NO_MATCH; } static int nt_typ_from_major(int ma) { switch(ma) { case SCSI_DISK0_MAJOR: case SCSI_DISK1_MAJOR: case SCSI_DISK2_MAJOR: case SCSI_DISK3_MAJOR: case SCSI_DISK4_MAJOR: case SCSI_DISK5_MAJOR: case SCSI_DISK6_MAJOR: case SCSI_DISK7_MAJOR: case SCSI_DISK8_MAJOR: case SCSI_DISK9_MAJOR: case SCSI_DISK10_MAJOR: case SCSI_DISK11_MAJOR: case SCSI_DISK12_MAJOR: case SCSI_DISK13_MAJOR: case SCSI_DISK14_MAJOR: case SCSI_DISK15_MAJOR: return NT_SD; case SCSI_CDROM_MAJOR: return NT_SR; case IDE0_MAJOR: case IDE1_MAJOR: case IDE2_MAJOR: case IDE3_MAJOR: case IDE4_MAJOR: case IDE5_MAJOR: case IDE6_MAJOR: case IDE7_MAJOR: case IDE8_MAJOR: case IDE9_MAJOR: return NT_HD; case OSST_MAJOR: return NT_OSST; case SCSI_GENERIC_MAJOR: return NT_SG; case SCSI_TAPE_MAJOR: return NT_ST; case SCSI_CHANGER_MAJOR: return NT_CH; default: return NT_NO_MATCH; } return NT_NO_MATCH; } struct node_match_item { const char * dir_name; int file_type; int majj; int minn; int follow_symlink; }; static struct node_match_item nd_match; static int nd_match_scandir_select(const struct dirent * s) { struct stat st; char name[D_NAME_LEN_MAX]; int symlnk = 0; switch (s->d_type) { case DT_BLK: if (FT_BLOCK != nd_match.file_type) return 0; break; case DT_CHR: if (FT_CHAR != nd_match.file_type) return 0; break; case DT_DIR: return (FT_DIR == nd_match.file_type) ? 1 : 0; case DT_REG: return (FT_REGULAR == nd_match.file_type) ? 1 : 0; case DT_LNK: /* follow symlinks */ if (! nd_match.follow_symlink) return 0; symlnk = 1; break; default: return 0; } if ((! symlnk) && (-1 == nd_match.majj) && (-1 == nd_match.minn)) return 1; strncpy(name, nd_match.dir_name, NAME_LEN_MAX); strcat(name, "/"); strncat(name, s->d_name, NAME_LEN_MAX); memset(&st, 0, sizeof(st)); if (stat(name, &st) < 0) return 0; if (symlnk) { if (S_ISCHR(st.st_mode)) { if (FT_CHAR != nd_match.file_type) return 0; } else if (S_ISBLK(st.st_mode)) { if (FT_BLOCK != nd_match.file_type) return 0; } else return 0; } return (((-1 == nd_match.majj) || ((unsigned)major(st.st_rdev) == (unsigned)nd_match.majj)) && ((-1 == nd_match.minn) || ((unsigned)minor(st.st_rdev) == (unsigned)nd_match.minn))) ? 1 : 0; } static int list_matching_nodes(const char * dir_name, int file_type, int majj, int minn, int follow_symlink, int verbose) { struct dirent ** namelist; int num, k; nd_match.dir_name = dir_name; nd_match.file_type = file_type; nd_match.majj = majj; nd_match.minn = minn; nd_match.follow_symlink = follow_symlink; num = scandir(dir_name, &namelist, nd_match_scandir_select, NULL); if (num < 0) { if (verbose) fprintf(stderr, "scandir: %s %s\n", dir_name, ssafe_strerror(errno)); return -errno; } for (k = 0; k < num; ++k) { printf("%s/%s\n", dir_name, namelist[k]->d_name); free(namelist[k]); } free(namelist); return num; } struct sg_item_t { char name[NAME_LEN_MAX]; int ft; int nt; int d_type; }; static struct sg_item_t for_first; static int first_scandir_select(const struct dirent * s) { if (FT_OTHER != for_first.ft) return 0; if ((DT_LNK != s->d_type) && ((DT_DIR != s->d_type) || ('.' == s->d_name[0]))) return 0; strncpy(for_first.name, s->d_name, NAME_LEN_MAX); for_first.ft = FT_CHAR; /* dummy */ for_first.d_type = s->d_type; return 1; } /* scan for directory entry that is either a symlink or a directory */ static int scan_for_first(const char * dir_name, int verbose) { char name[NAME_LEN_MAX]; struct dirent ** namelist; int num, k; for_first.ft = FT_OTHER; num = scandir(dir_name, &namelist, first_scandir_select, NULL); if (num < 0) { if (verbose > 0) { snprintf(name, NAME_LEN_MAX, "scandir: %s", dir_name); perror(name); } return -1; } for (k = 0; k < num; ++k) free(namelist[k]); free(namelist); return num; } static struct sg_item_t from_sg; static int from_sg_scandir_select(const struct dirent * s) { int len; if (FT_OTHER != from_sg.ft) return 0; if ((DT_LNK != s->d_type) && ((DT_DIR != s->d_type) || ('.' == s->d_name[0]))) return 0; from_sg.d_type = s->d_type; if (0 == strncmp("scsi_changer", s->d_name, 12)) { strncpy(from_sg.name, s->d_name, NAME_LEN_MAX); from_sg.ft = FT_CHAR; from_sg.nt = NT_CH; return 1; } else if (0 == strncmp("block", s->d_name, 5)) { strncpy(from_sg.name, s->d_name, NAME_LEN_MAX); from_sg.ft = FT_BLOCK; return 1; } else if (0 == strcmp("tape", s->d_name)) { strcpy(from_sg.name, s->d_name); from_sg.ft = FT_CHAR; from_sg.nt = NT_ST; return 1; } else if (0 == strncmp("scsi_tape:st", s->d_name, 12)) { len = strlen(s->d_name); if (isdigit(s->d_name[len - 1])) { /* want 'st' symlink only */ strcpy(from_sg.name, s->d_name); from_sg.ft = FT_CHAR; from_sg.nt = NT_ST; return 1; } else return 0; } else if (0 == strncmp("onstream_tape:os", s->d_name, 16)) { strcpy(from_sg.name, s->d_name); from_sg.ft = FT_CHAR; from_sg.nt = NT_OSST; return 1; } else return 0; } static int from_sg_scan(const char * dir_name, int verbose) { struct dirent ** namelist; int num, k; from_sg.ft = FT_OTHER; from_sg.nt = NT_NO_MATCH; num = scandir(dir_name, &namelist, from_sg_scandir_select, NULL); if (num < 0) { if (verbose) fprintf(stderr, "scandir: %s %s\n", dir_name, ssafe_strerror(errno)); return -errno; } if (verbose) { for (k = 0; k < num; ++k) fprintf(stderr, " %s/%s\n", dir_name, namelist[k]->d_name); } for (k = 0; k < num; ++k) free(namelist[k]); free(namelist); return num; } static struct sg_item_t to_sg; static int to_sg_scandir_select(const struct dirent * s) { if (FT_OTHER != to_sg.ft) return 0; if (DT_LNK != s->d_type) return 0; if (0 == strncmp("scsi_generic", s->d_name, 12)) { strncpy(to_sg.name, s->d_name, NAME_LEN_MAX); to_sg.ft = FT_CHAR; to_sg.nt = NT_SG; return 1; } else return 0; } static int to_sg_scan(const char * dir_name) { struct dirent ** namelist; int num, k; to_sg.ft = FT_OTHER; to_sg.nt = NT_NO_MATCH; num = scandir(dir_name, &namelist, to_sg_scandir_select, NULL); if (num < 0) return -errno; for (k = 0; k < num; ++k) free(namelist[k]); free(namelist); return num; } /* Return 1 if directory, else 0 */ static int if_directory_chdir(const char * dir_name, const char * base_name) { char buff[D_NAME_LEN_MAX]; struct stat a_stat; strcpy(buff, dir_name); strcat(buff, "/"); strcat(buff, base_name); if (stat(buff, &a_stat) < 0) return 0; if (S_ISDIR(a_stat.st_mode)) { if (chdir(buff) < 0) return 0; return 1; } return 0; } /* Return 1 if directory, else 0 */ static int if_directory_ch2generic(const char * dir_name) { char buff[NAME_LEN_MAX]; struct stat a_stat; const char * old_name = "generic"; strcpy(buff, dir_name); strcat(buff, "/"); strcat(buff, old_name); if ((stat(buff, &a_stat) >= 0) && S_ISDIR(a_stat.st_mode)) { if (chdir(buff) < 0) return 0; return 1; } /* No "generic", so now look for "scsi_generic:sg" */ if (1 != to_sg_scan(dir_name)) return 0; strcpy(buff, dir_name); strcat(buff, "/"); strcat(buff, to_sg.name); if (stat(buff, &a_stat) < 0) return 0; if (S_ISDIR(a_stat.st_mode)) { if (chdir(buff) < 0) return 0; return 1; } return 0; } /* Return 1 if found, else 0 if problems */ static int get_value(const char * dir_name, const char * base_name, char * value, int max_value_len) { char buff[D_NAME_LEN_MAX]; FILE * f; int len; if ((NULL == dir_name) && (NULL == base_name)) return 0; if (dir_name) { strcpy(buff, dir_name); if (base_name && (strlen(base_name) > 0)) { strcat(buff, "/"); strcat(buff, base_name); } } else strcpy(buff, base_name); if (NULL == (f = fopen(buff, "r"))) { return 0; } if (NULL == fgets(value, max_value_len, f)) { fclose(f); return 0; } len = strlen(value); if ((len > 0) && (value[len - 1] == '\n')) value[len - 1] = '\0'; fclose(f); return 1; } static int map_hd(const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { char c, num; if (2 == result) { num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } switch (ma) { case IDE0_MAJOR: c = 'a'; break; case IDE1_MAJOR: c = 'c'; break; case IDE2_MAJOR: c = 'e'; break; case IDE3_MAJOR: c = 'g'; break; case IDE4_MAJOR: c = 'i'; break; case IDE5_MAJOR: c = 'k'; break; case IDE6_MAJOR: c = 'm'; break; case IDE7_MAJOR: c = 'o'; break; case IDE8_MAJOR: c = 'q'; break; case IDE9_MAJOR: c = 's'; break; default: c = '?'; break; } if (mi > 63) ++c; printf("%shd%c\n", sys_hd_dir, c); return 0; } static int map_sd(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int index, m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } if (SCSI_DISK0_MAJOR == ma) index = mi / 16; else if (ma >= SCSI_DISK8_MAJOR) index = (mi / 16) + 128 + ((ma - SCSI_DISK8_MAJOR) * 16); else index = (mi / 16) + 16 + ((ma - SCSI_DISK1_MAJOR) * 16); if (index < 26) snprintf(name, sizeof(name), "%ssd%c", sys_sd_dir, 'a' + index % 26); else if (index < (26 + 1) * 26) snprintf(name, sizeof(name), "%ssd%c%c", sys_sd_dir, 'a' + index / 26 - 1,'a' + index % 26); else { const unsigned int m1 = (index / 26 - 1) / 26 - 1; const unsigned int m2 = (index / 26 - 1) % 26; const unsigned int m3 = index % 26; snprintf(name, sizeof(name), "%ssd%c%c%c", sys_sd_dir, 'a' + m1, 'a' + m2, 'a' + m3); } if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs sd dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs generic" "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "sd device: %s does not match any " "SCSI generic device\n", device_name); fprintf(stderr, " perhaps sg module is not " "loaded\n"); return 1; } } static int map_sr(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_BLOCK, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } snprintf(name, sizeof(name), "%ssr%d", sys_sr_dir, mi); if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs sr dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs generic" "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, FT_BLOCK, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "sr device: %s does not match any " "SCSI generic device\n", device_name); fprintf(stderr, " perhaps sg module is not " "loaded\n"); return 1; } } static int map_st(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_CHAR, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } snprintf(name, sizeof(name), "%sst%d", sys_st_dir, TAPE_NR(mi)); if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs st dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs generic" "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "st device: %s does not match any " "SCSI generic device\n", device_name); fprintf(stderr, " perhaps sg module is not " "loaded\n"); return 1; } } static int map_osst(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_CHAR, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } snprintf(name, sizeof(name), "%sosst%d", sys_osst_dir, TAPE_NR(mi)); if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs osst dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs generic" "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "osst device: %s does not match any " "SCSI generic device\n", device_name); fprintf(stderr, " perhaps sg module is not " "loaded\n"); return 1; } } static int map_ch(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_CHAR, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } snprintf(name, sizeof(name), "%ssch%d", sys_sch_dir, mi); if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs sch dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if (if_directory_ch2generic(".")) { if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs generic" "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, FT_CHAR, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "sch device: %s does not match any " "SCSI generic device\n", device_name); fprintf(stderr, " perhaps sg module is not " "loaded\n"); return 1; } } static int map_sg(const char * device_name, const char * device_dir, int ma, int mi, int result, int follow_symlink, int verbose) { int m_mi, m_ma, num; char value[D_NAME_LEN_MAX]; char name[D_NAME_LEN_MAX]; if (2 == result) { num = list_matching_nodes(device_dir, FT_CHAR, ma, mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } snprintf(name, sizeof(name), "%ssg%d", sys_sg_dir, mi); if (3 == result) { printf("%s\n", name); return 0; } if (! get_value(name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs match for " "device: %s\n", device_name); return 1; } if (verbose) fprintf(stderr, "sysfs sg dev: %s\n", value); if (! if_directory_chdir(name, "device")) { fprintf(stderr, "sysfs problem with device: %s\n", device_name); return 1; } if ((1 == from_sg_scan(".", verbose)) && (if_directory_chdir(".", from_sg.name))) { if (DT_DIR == from_sg.d_type) { if ((1 == scan_for_first(".", verbose)) && (if_directory_chdir(".", for_first.name))) { ; } else { fprintf(stderr, "unexpected scan_for_first " "error\n"); } } if (1 == result) { if (NULL == getcwd(value, sizeof(value))) value[0] = '\0'; printf("%s\n", value); return 0; } if (! get_value(".", "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't find sysfs block " "dev\n"); return 1; } if (verbose) printf("matching dev: %s\n", value); if (2 != sscanf(value, "%d:%d", &m_ma, &m_mi)) { fprintf(stderr, "Couldn't decode mapped " "dev\n"); return 1; } num = list_matching_nodes(device_dir, from_sg.ft, m_ma, m_mi, follow_symlink, verbose); return (num > 0) ? 0 : 1; } else { fprintf(stderr, "sg device: %s does not match any " "other SCSI device\n", device_name); return 1; } } int main(int argc, char * argv[]) { int c, num, tt, cont, res; int do_dev_dir = 0; int given_is = -1; int result = 0; int follow_symlink = 0; int verbose = 0; char device_name[D_NAME_LEN_MAX]; char device_dir[D_NAME_LEN_MAX]; char value[D_NAME_LEN_MAX]; int ret = 1; int ma, mi; memset(device_name, 0, sizeof(device_name)); memset(device_dir, 0, sizeof(device_dir)); while (1) { int option_index = 0; c = getopt_long(argc, argv, "d:hg:r:svV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': strncpy(device_dir, optarg, sizeof(device_dir)); do_dev_dir = 1; break; case 'g': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((0 == res) || (1 == res))) given_is = res; else { fprintf(stderr, "value for '--given_to=' " "must be 0 or 1\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'r': num = sscanf(optarg, "%d", &res); if ((1 == num) && (res >= 0) && (res < 4)) result = res; else { fprintf(stderr, "value for '--result=' " "must be 0..3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': follow_symlink = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if ('\0' == device_name[0]) { strncpy(device_name, argv[optind], sizeof(device_name) - 1); device_name[sizeof(device_name) - 1] = '\0'; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument: " "%s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (0 == device_name[0]) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } ma = 0; mi = 0; if (do_dev_dir) { if (if_directory_chdir(".", device_dir)) { if (getcwd(device_dir, sizeof(device_dir))) device_dir[sizeof(device_dir) - 1] = '\0'; else device_dir[0] = '\0'; if (verbose > 1) fprintf(stderr, "Absolute path to " "dev_dir: %s\n", device_dir); } else { fprintf(stderr, "dev_dir: %s invalid\n", device_dir); return SG_LIB_FILE_ERROR; } } else { strcpy(device_dir, device_name); dirname(device_dir); if (0 == strcmp(device_dir, device_name)) { if (NULL == getcwd(device_dir, sizeof(device_dir))) device_dir[0] = '\0'; } } ret = nt_typ_from_filename(device_name, &ma, &mi); if (ret < 0) { fprintf(stderr, "stat failed on %s: %s\n", device_name, ssafe_strerror(-ret)); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, " %s: %s device [maj=%d, min=%d]\n", device_name, nt_names[ret], ma, mi); res = 0; switch (ret) { case NT_SD: case NT_SR: case NT_HD: if (given_is > 0) { fprintf(stderr, "block special but '--given_is=' " "suggested sysfs device\n"); return SG_LIB_FILE_ERROR; } break; case NT_ST: case NT_OSST: case NT_CH: case NT_SG: if (given_is > 0) { fprintf(stderr, "character special but '--given_is=' " "suggested sysfs device\n"); return SG_LIB_FILE_ERROR; } break; case NT_REG: if (0 == given_is) { fprintf(stderr, "regular file but '--given_is=' " "suggested block or char special\n"); return SG_LIB_FILE_ERROR; } strcpy(device_dir, def_dev_dir); break; case NT_DIR: if (0 == given_is) { fprintf(stderr, "directory but '--given_is=' " "suggested block or char special\n"); return SG_LIB_FILE_ERROR; } strcpy(device_dir, def_dev_dir); break; default: break; } tt = NT_NO_MATCH; do { cont = 0; switch (ret) { case NT_NO_MATCH: res = 1; break; case NT_SD: res = map_sd(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_SR: res = map_sr(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_HD: if (result < 2) { fprintf(stderr, "a hd device does not map " "to a sg device\n"); return SG_LIB_FILE_ERROR; } res = map_hd(device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_ST: res = map_st(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_OSST: res = map_osst(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_CH: res = map_ch(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_SG: res = map_sg(device_name, device_dir, ma, mi, result, follow_symlink, verbose); break; case NT_REG: if (! get_value(NULL, device_name, value, sizeof(value))) { fprintf(stderr, "Couldn't fetch value " "from: %s\n", device_name); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, "value: %s\n", value); if (2 != sscanf(value, "%d:%d", &ma, &mi)) { fprintf(stderr, "Couldn't decode value\n"); return SG_LIB_FILE_ERROR; } tt = nt_typ_from_major(ma); cont = 1; break; case NT_DIR: if (! get_value(device_name, "dev", value, sizeof(value))) { fprintf(stderr, "Couldn't fetch value from: " "%s/dev\n", device_name); return SG_LIB_FILE_ERROR; } if (verbose) fprintf(stderr, "value: %s\n", value); if (2 != sscanf(value, "%d:%d", &ma, &mi)) { fprintf(stderr, "Couldn't decode value\n"); return SG_LIB_FILE_ERROR; } tt = nt_typ_from_major(ma); cont = 1; break; default: break; } ret = tt; } while (cont); return res; } sg3_utils-1.40/src/sg_sanitize.c0000664000175000017500000006007212414667052015636 0ustar douggdougg/* * Copyright (c) 2011-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "0.96 20141006"; /* Not all environments support the Unix sleep() */ #if defined(MSC_VER) || defined(__MINGW32__) #define HAVE_MS_SLEEP #endif #ifdef HAVE_MS_SLEEP #include #define sleep_for(seconds) Sleep( (seconds) * 1000) #else #define sleep_for(seconds) sleep(seconds) #endif #define ME "sg_sanitize: " #define SANITIZE_OP 0x48 #define SANITIZE_OP_LEN 10 #define SANITIZE_SA_OVERWRITE 0x1 #define SANITIZE_SA_BLOCK_ERASE 0x2 #define SANITIZE_SA_CRYPTO_ERASE 0x3 #define SANITIZE_SA_EXIT_FAIL_MODE 0x1f #define DEF_REQS_RESP_LEN 252 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define MAX_XFER_LEN 65535 #define EBUFF_SZ 256 #define SHORT_TIMEOUT 20 /* 20 seconds unless immed=0 ... */ #define LONG_TIMEOUT (15 * 3600) /* 15 hours ! */ /* Seagate ST32000444SS 2TB disk takes 9.5 hours to format */ #define POLL_DURATION_SECS 60 static struct option long_options[] = { {"ause", no_argument, 0, 'A'}, {"block", no_argument, 0, 'B'}, {"count", required_argument, 0, 'c'}, {"crypto", no_argument, 0, 'C'}, {"desc", no_argument, 0, 'd'}, {"early", no_argument, 0, 'e'}, {"fail", no_argument, 0, 'F'}, {"help", no_argument, 0, 'h'}, {"invert", no_argument, 0, 'I'}, {"ipl", required_argument, 0, 'i'}, {"overwrite", no_argument, 0, 'O'}, {"pattern", required_argument, 0, 'p'}, {"quick", no_argument, 0, 'Q'}, {"test", required_argument, 0, 'T'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wait", no_argument, 0, 'w'}, {"zero", no_argument, 0, 'z'}, {0, 0, 0, 0}, }; struct opts_t { int ause; int block; int count; int crypto; int desc; int early; int fail; int invert; int ipl; /* initialization pattern length */ int overwrite; int test; int quick; int verbose; int wait; int zero; const char * pattern_fn; }; static void usage() { fprintf(stderr, "Usage: " "sg_sanitize [--ause] [--block] [--count=OC] [--crypto] [--early]\n" " [--fail] [--help] [--invert] [--ipl=LEN] " "[--overwrite]\n" " [--pattern=PF] [--quick] [--test=TE] " "[--verbose]\n" " [--version] [--wait] DEVICE\n" " where:\n" " --ause|-A set AUSE bit in cdb\n" " --block|-B do BLOCK ERASE sanitize\n" " --count=OC|-c OC OC is overwrite count field (from 1 " "(def) to 31)\n" " --crypto|-C do CRYPTOGRAPHIC ERASE sanitize\n" " --desc|-d polling request sense sets 'desc' " "field\n" " (def: clear 'desc' field)\n" " --early|-e exit once sanitize started (IMMED set " "in cdb)\n" " user can monitor progress with REQUEST " "SENSE\n" " --fail|-F do EXIT FAILURE MODE sanitize\n" " --help|-h print out usage message\n" " --invert|-I set INVERT bit in OVERWRITE parameter " "list\n" " --ipl=LEN|-i LEN initialization pattern length (in " "bytes)\n" " --overwrite|-O do OVERWRITE sanitize\n" " --pattern=PF|-p PF PF is file containing initialization " "pattern\n" " for OVERWRITE\n" " --quick|-Q start sanitize without pause for user\n" " intervention (i.e. no time to " "reconsider)\n" " --test=TE|-T TE TE is placed in TEST field of " "OVERWRITE\n" " parameter list (def: 0)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --wait|-w wait for command to finish (could " "take hours)\n" " --zero|-z use pattern of zeros for " "OVERWRITE\n\n" "Performs a SCSI SANITIZE command.\n <<>>: all data " "on DEVICE will be lost.\nDefault action is to give user time to " "reconsider; then execute SANITIZE\ncommand with IMMED bit set; " "then use REQUEST SENSE command every 60\nseconds to poll for a " "progress indication; then exit when there is no\nmore progress " "indication.\n" ); } /* Invoke SCSI SANITIZE command. Returns 0 if successful, otherwise error */ static int do_sanitize(int sg_fd, const struct opts_t * op, const void * param_lstp, int param_lst_len) { int k, ret, res, sense_cat, immed; unsigned char sanCmdBlk[SANITIZE_OP_LEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; if (op->early || op->wait) immed = op->early ? 1 : 0; else immed = 1; memset(sanCmdBlk, 0, sizeof(sanCmdBlk)); sanCmdBlk[0] = SANITIZE_OP; if (op->overwrite) sanCmdBlk[1] = SANITIZE_SA_OVERWRITE; else if (op->block) sanCmdBlk[1] = SANITIZE_SA_BLOCK_ERASE; else if (op->crypto) sanCmdBlk[1] = SANITIZE_SA_CRYPTO_ERASE; else if (op->fail) sanCmdBlk[1] = SANITIZE_SA_EXIT_FAIL_MODE; else return SG_LIB_SYNTAX_ERROR; if (immed) sanCmdBlk[1] |= 0x80; if (op->ause) sanCmdBlk[1] |= 0x20; sanCmdBlk[7] = ((param_lst_len >> 8) & 0xff); sanCmdBlk[8] = (param_lst_len & 0xff); if (op->verbose > 1) { fprintf(stderr, " Sanitize cmd: "); for (k = 0; k < SANITIZE_OP_LEN; ++k) fprintf(stderr, "%02x ", sanCmdBlk[k]); fprintf(stderr, "\n"); } if ((op->verbose > 2) && (param_lst_len > 0)) { fprintf(stderr, " Parameter list contents:\n"); dStrHexErr((const char *)param_lstp, param_lst_len, 1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Sanitize: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, sanCmdBlk, sizeof(sanCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)param_lstp, param_lst_len); res = do_scsi_pt(ptvp, sg_fd, (immed ? SHORT_TIMEOUT : LONG_TIMEOUT), op->verbose); ret = sg_cmds_process_resp(ptvp, "Sanitize", res, 0, sense_b, 1 /*noisy */, op->verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { int valid, slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) fprintf(stderr, "Medium or hardware error starting at " "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } #define VPD_DEVICE_ID 0x83 #define VPD_ASSOC_LU 0 #define VPD_ASSOC_TPORT 1 #define TPROTO_ISCSI 5 static char * get_lu_name(const unsigned char * ucp, int u_len, char * b, int b_len) { int len, off, sns_dlen, dlen, k; unsigned char u_sns[512]; char * cp; len = u_len - 4; ucp += 4; off = -1; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { sns_dlen = ucp[off + 3]; memcpy(u_sns, ucp + off + 4, sns_dlen); /* now want to check if this is iSCSI */ off = -1; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_TPORT, 8 /* SCSI name string (sns) */, 3 /* UTF-8 */)) { if ((0x80 & ucp[1]) && (TPROTO_ISCSI == (ucp[0] >> 4))) { snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } } } else sns_dlen = 0; if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 3 /* NAA */, 1 /* binary */)) { dlen = ucp[off + 3]; if (! ((8 == dlen) || (16 ==dlen))) return b; cp = b; for (k = 0; ((k < dlen) && (b_len > 1)); ++k) { snprintf(cp, b_len, "%02x", ucp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (0 == sg_vpd_dev_id_iter(ucp, len, &off, VPD_ASSOC_LU, 2 /* EUI */, 1 /* binary */)) { dlen = ucp[off + 3]; if (! ((8 == dlen) || (12 == dlen) || (16 ==dlen))) return b; cp = b; for (k = 0; ((k < dlen) && (b_len > 1)); ++k) { snprintf(cp, b_len, "%02x", ucp[off + 4 + k]); cp += 2; b_len -= 2; } } else if (sns_dlen > 0) snprintf(b, b_len, "%.*s", sns_dlen, u_sns); return b; } #define SAFE_STD_INQ_RESP_LEN 36 #define VPD_SUPPORTED_VPDS 0x0 #define VPD_UNIT_SERIAL_NUM 0x80 #define VPD_DEVICE_ID 0x83 static int print_dev_id(int fd, unsigned char * sinq_resp, int max_rlen, int verbose) { int res, k, n, verb, pdt, has_sn, has_di; unsigned char b[256]; char a[256]; char pdt_name[64]; verb = (verbose > 1) ? verbose - 1 : 0; memset(sinq_resp, 0, max_rlen); res = sg_ll_inquiry(fd, 0, 0 /* evpd */, 0 /* pg_op */, b, SAFE_STD_INQ_RESP_LEN, 1, verb); if (res) return res; n = b[4] + 5; if (n > SAFE_STD_INQ_RESP_LEN) n = SAFE_STD_INQ_RESP_LEN; memcpy(sinq_resp, b, (n < max_rlen) ? n : max_rlen); if (n == SAFE_STD_INQ_RESP_LEN) { pdt = b[0] & 0x1f; printf(" %.8s %.16s %.4s peripheral_type: %s [0x%x]\n", (const char *)(b + 8), (const char *)(b + 16), (const char *)(b + 32), sg_get_pdt_str(pdt, sizeof(pdt_name), pdt_name), pdt); if (verbose) printf(" PROTECT=%d\n", !!(b[5] & 1)); if (b[5] & 1) printf(" << supports protection information>>\n"); } else { fprintf(stderr, "Short INQUIRY response: %d bytes, expect at least " "36\n", n); return SG_LIB_CAT_OTHER; } res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_SUPPORTED_VPDS, b, SAFE_STD_INQ_RESP_LEN, 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS gave res=%d\n", res); return 0; } if (VPD_SUPPORTED_VPDS != b[1]) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (SAFE_STD_INQ_RESP_LEN - 4)) n = (SAFE_STD_INQ_RESP_LEN - 4); for (k = 0, has_sn = 0, has_di = 0; k < n; ++k) { if (VPD_UNIT_SERIAL_NUM == b[4 + k]) { if (has_di) { if (verbose) fprintf(stderr, "VPD_SUPPORTED_VPDS dis-ordered\n"); return 0; } ++has_sn; } else if (VPD_DEVICE_ID == b[4 + k]) { ++has_di; break; } } if (has_sn) { res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_UNIT_SERIAL_NUM, b, sizeof(b), 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_UNIT_SERIAL_NUM gave res=%d\n", res); return 0; } if (VPD_UNIT_SERIAL_NUM != b[1]) { if (verbose) fprintf(stderr, "VPD_UNIT_SERIAL_NUM corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (int)(sizeof(b) - 4)) n = (sizeof(b) - 4); printf(" Unit serial number: %.*s\n", n, (const char *)(b + 4)); } if (has_di) { res = sg_ll_inquiry(fd, 0, 1 /* evpd */, VPD_DEVICE_ID, b, sizeof(b), 1, verb); if (res) { if (verbose) fprintf(stderr, "VPD_DEVICE_ID gave res=%d\n", res); return 0; } if (VPD_DEVICE_ID != b[1]) { if (verbose) fprintf(stderr, "VPD_DEVICE_ID corrupted\n"); return 0; } n = (b[2] << 8) + b[3]; if (n > (int)(sizeof(b) - 4)) n = (sizeof(b) - 4); n = strlen(get_lu_name(b, n + 4, a, sizeof(a))); if (n > 0) printf(" LU name: %.*s\n", n, a); } return 0; } int main(int argc, char * argv[]) { int sg_fd, k, res, c, infd, progress, vb, n, resp_len; int got_stdin = 0; int param_lst_len = 0; const char * device_name = NULL; char ebuff[EBUFF_SZ]; char b[80]; unsigned char requestSenseBuff[DEF_REQS_RESP_LEN]; unsigned char * wBuff = NULL; int ret = -1; struct opts_t opts; struct opts_t * op; struct stat a_stat; unsigned char inq_resp[SAFE_STD_INQ_RESP_LEN]; op = &opts; memset(op, 0, sizeof(opts)); op->count = 1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ABc:CdeFhi:IOp:QT:vVwz", long_options, &option_index); if (c == -1) break; switch (c) { case 'A': ++op->ause; break; case 'B': ++op->block; break; case 'c': op->count = sg_get_num(optarg); if ((op->count < 1) || (op->count > 31)) { fprintf(stderr, "bad argument to '--count', expect 1 to " "31\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': ++op->crypto; break; case 'd': ++op->desc; break; case 'e': ++op->early; break; case 'F': ++op->fail; break; case 'h': case '?': usage(); return 0; case 'i': op->ipl = sg_get_num(optarg); if ((op->ipl < 1) || (op->ipl > 65535)) { fprintf(stderr, "bad argument to '--ipl', expect 1 to " "65535\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'I': ++op->invert; break; case 'O': ++op->overwrite; break; case 'p': op->pattern_fn = optarg; break; case 'Q': ++op->quick; break; case 'T': op->test = sg_get_num(optarg); if ((op->test < 0) || (op->test > 3)) { fprintf(stderr, "bad argument to '--test', expect 0 to 3\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': ++op->verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'w': ++op->wait; break; case 'z': ++op->zero; break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } vb = op->verbose; n = !!op->block + !!op->crypto + !!op->fail + !!op->overwrite; if (1 != n) { fprintf(stderr, "one and only one of '--block', '--crypto', " "'--fail' or '--overwrite' please\n"); return SG_LIB_SYNTAX_ERROR; } if (op->overwrite) { if (op->zero) { if (op->pattern_fn) { fprintf(stderr, "confused: both '--pattern=PF' and '--zero' " "options\n"); return SG_LIB_SYNTAX_ERROR; } op->ipl = 4; } else { if (NULL == op->pattern_fn) { fprintf(stderr, "'--overwrite' requires '--pattern=PF' " "or '--zero' option\n"); return SG_LIB_SYNTAX_ERROR; } got_stdin = (0 == strcmp(op->pattern_fn, "-")) ? 1 : 0; if (! got_stdin) { memset(&a_stat, 0, sizeof(a_stat)); if (stat(op->pattern_fn, &a_stat) < 0) { fprintf(stderr, "pattern file: unable to stat(%s): %s\n", op->pattern_fn, safe_strerror(errno)); return SG_LIB_FILE_ERROR; } if (op->ipl <= 0) { op->ipl = (int)a_stat.st_size; if (op->ipl > MAX_XFER_LEN) { fprintf(stderr, "pattern file length exceeds 65535 " "bytes, need '--ipl=LEN' option\n"); return SG_LIB_FILE_ERROR; } } } if (op->ipl < 1) { fprintf(stderr, "'--overwrite' requires '--ipl=LEN' " "option if can't get PF length\n"); return SG_LIB_SYNTAX_ERROR; } } } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, vb); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } ret = print_dev_id(sg_fd, inq_resp, sizeof(inq_resp), op->verbose); if (ret) goto err_out; if (op->overwrite) { param_lst_len = op->ipl + 4; wBuff = (unsigned char*)calloc(op->ipl + 4, 1); if (NULL == wBuff) { fprintf(stderr, "unable to allocate %d bytes of memory with " "calloc()\n", op->ipl + 4); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->zero) { if (2 == op->zero) /* treat -zz as fill with 0xff bytes */ memset(wBuff + 4, 0xff, op->ipl); else memset(wBuff + 4, 0, op->ipl); } else { if (got_stdin) { infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { if ((infd = open(op->pattern_fn, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for " "reading", op->pattern_fn); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } res = read(infd, wBuff + 4, op->ipl); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", op->pattern_fn); perror(ebuff); if (! got_stdin) close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } if (res < op->ipl) { fprintf(stderr, "tried to read %d bytes from %s, got %d " "bytes\n", op->ipl, op->pattern_fn, res); fprintf(stderr, " so pad with 0x0 bytes and continue\n"); } if (! got_stdin) close(infd); } wBuff[0] = op->count & 0x1f;; if (op->test) wBuff[0] |= ((op->test & 0x3) << 5); if (op->invert) wBuff[0] |= 0x80; wBuff[2] = ((op->ipl >> 8) & 0xff); wBuff[3] = (op->ipl & 0xff); } if ((0 == op->quick) && (! op->fail)) { printf("\nA SANITIZE will commence in 15 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); printf("\nA SANITIZE will commence in 10 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); printf("\nA SANITIZE will commence in 5 seconds\n"); printf(" ALL data on %s will be DESTROYED\n", device_name); printf(" Press control-C to abort\n"); sleep_for(5); } ret = do_sanitize(sg_fd, op, wBuff, param_lst_len); if (ret) { sg_get_category_sense_str(ret, sizeof(b), b, vb); fprintf(stderr, "Sanitize failed: %s\n", b); } if ((0 == ret) && (0 == op->early) && (0 == op->wait)) { for (k = 0 ;; ++k) { sleep_for(POLL_DURATION_SECS); memset(requestSenseBuff, 0x0, sizeof(requestSenseBuff)); res = sg_ll_request_sense(sg_fd, op->desc, requestSenseBuff, sizeof(requestSenseBuff), 1, vb); if (res) { ret = res; if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Request Sense command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) { fprintf(stderr, "bad field in Request Sense cdb\n"); if (1 == op->desc) { fprintf(stderr, "Descriptor type sense may not be " "supported, try again with fixed type\n"); op->desc = 0; continue; } } else { sg_get_category_sense_str(res, sizeof(b), b, vb); fprintf(stderr, "Request Sense: %s\n", b); if (0 == vb) fprintf(stderr, " try the '-v' option for " "more information\n"); } break; } /* "Additional sense length" same in descriptor and fixed */ resp_len = requestSenseBuff[7] + 8; if (vb > 2) { fprintf(stderr, "Parameter data in hex\n"); dStrHexErr((const char *)requestSenseBuff, resp_len, 1); } progress = -1; sg_get_sense_progress_fld(requestSenseBuff, resp_len, &progress); if (progress < 0) { ret = res; if (vb > 1) fprintf(stderr, "No progress indication found, " "iteration %d\n", k + 1); /* N.B. exits first time there isn't a progress indication */ break; } else printf("Progress indication: %d%% done\n", (progress * 100) / 65536); } } err_out: if (wBuff) free(wBuff); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_test_rwbuf.c0000664000175000017500000004447312142450532016172 0ustar douggdougg/* * (c) 2000 Kurt Garloff * heavily based on Douglas Gilbert's sg_rbuf program. * (c) 1999-2008 Douglas Gilbert * * Program to test the SCSI host adapter by issueing * write and read operations on a device's buffer * and calculating checksums. * NOTE: If you can not reserve the buffer of the device * for this purpose (SG_GET_RESERVED_SIZE), you risk * serious data corruption, if the device is accessed by * somebody else in the meantime. * * 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. * * $Id: sg_test_rwbuf.c,v 1.1 2000/03/02 13:50:03 garloff Exp $ * * 2003/11/11 switch sg3_utils version to use SG_IO ioctl [dpg] * 2004/06/08 remove SG_GET_VERSION_NUM check [dpg] */ #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_io_linux.h" static const char * version_str = "1.07 20130507"; #define BPI (signed)(sizeof(int)) #define RB_MODE_DESC 3 #define RWB_MODE_DATA 2 #define RB_DESC_LEN 4 /* The microcode in a SCSI device is _not_ modified by doing a WRITE BUFFER * with mode set to "data" (0x2) as done by this utility. Therefore this * utility is safe in that respect. [Mode values 0x4, 0x5, 0x6 and 0x7 are * the dangerous ones :-)] */ #define ME "sg_test_rwbuf: " static int base = 0x12345678; static int buf_capacity = 0; static int buf_granul = 255; static unsigned char *cmpbuf = NULL; /* Options */ static int size = -1; static char do_quick = 0; static int addwrite = 0; static int addread = 0; static int verbose = 0; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"quick", 0, 0, 'q'}, {"addrd", 1, 0, 'r'}, {"size", 1, 0, 's'}, {"times", 1, 0, 't'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"addwr", 1, 0, 'w'}, {0, 0, 0, 0}, }; int find_out_about_buffer (int sg_fd) { unsigned char rbCmdBlk[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char rbBuff[RB_DESC_LEN]; unsigned char sense_buffer[32]; struct sg_io_hdr io_hdr; int k, res; rbCmdBlk[1] = RB_MODE_DESC; rbCmdBlk[8] = RB_DESC_LEN; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rbCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = RB_DESC_LEN; io_hdr.dxferp = rbBuff; io_hdr.cmdp = rbCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { fprintf(stderr, " read buffer [mode desc] cdb: "); for (k = 0; k < (int)sizeof(rbCmdBlk); ++k) fprintf(stderr, "%02x ", rbCmdBlk[k]); fprintf(stderr, "\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "SG_IO READ BUFFER descriptor error"); return -1; } /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("READ BUFFER descriptor, continuing", &io_hdr, 1); /* fall through */ case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER descriptor error", &io_hdr, 1); return res; } buf_capacity = ((rbBuff[1] << 16) | (rbBuff[2] << 8) | rbBuff[3]); buf_granul = (unsigned char)rbBuff[0]; #if 0 printf("READ BUFFER reports: %02x %02x %02x %02x\n", rbBuff[0], rbBuff[1], rbBuff[2], rbBuff[3]); #endif if (verbose) printf("READ BUFFER reports: buffer capacity=%d, offset " "boundary=%d\n", buf_capacity, buf_granul); return 0; } int mymemcmp (unsigned char *bf1, unsigned char *bf2, int len) { int df; for (df = 0; df < len; df++) if (bf1[df] != bf2[df]) return df; return 0; } /* return 0 if good, else 2222 */ int do_checksum (int *buf, int len, int quiet) { int sum = base; int i; int rln = len; for (i = 0; i < len/BPI; i++) sum += buf[i]; while (rln%BPI) sum += ((char*)buf)[--rln]; if (sum != 0x12345678) { if (!quiet) printf ("sg_test_rwbuf: Checksum error (sz=%i):" " %08x\n", len, sum); if (cmpbuf && !quiet) { int diff = mymemcmp (cmpbuf, (unsigned char*)buf, len); printf ("Differ at pos %i/%i:\n", diff, len); for (i = 0; i < 24 && i+diff < len; i++) printf (" %02x", cmpbuf[i+diff]); printf ("\n"); for (i = 0; i < 24 && i+diff < len; i++) printf (" %02x", ((unsigned char*)buf)[i+diff]); printf ("\n"); } return 2222; } else { if (verbose > 1) printf("Checksum value: 0x%x\n", sum); return 0; } } void do_fill_buffer (int *buf, int len) { int sum; int i; int rln = len; srand (time (0)); retry: if (len >= BPI) base = 0x12345678 + rand (); else base = 0x12345678 + (char) rand (); sum = base; for (i = 0; i < len/BPI - 1; i++) { /* we rely on rand() giving full range of int */ buf[i] = rand (); sum += buf[i]; } while (rln%BPI) { ((char*)buf)[--rln] = rand (); sum += ((char*)buf)[rln]; } if (len >= BPI) buf[len/BPI - 1] = 0x12345678 - sum; else ((char*)buf)[0] = 0x12345678 + ((char*)buf)[0] - sum; if (do_checksum (buf, len, 1)) { if (len < BPI) goto retry; printf ("sg_test_rwbuf: Memory corruption?\n"); exit (1); } if (cmpbuf) memcpy (cmpbuf, (char*)buf, len); } int read_buffer (int sg_fd, unsigned size) { int res, k; unsigned char rbCmdBlk[] = {READ_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int bufSize = size + addread; unsigned char * rbBuff = (unsigned char *)malloc(bufSize); unsigned char sense_buffer[32]; struct sg_io_hdr io_hdr; if (NULL == rbBuff) return -1; rbCmdBlk[1] = RWB_MODE_DATA; rbCmdBlk[6] = 0xff & (bufSize >> 16); rbCmdBlk[7] = 0xff & (bufSize >> 8); rbCmdBlk[8] = 0xff & bufSize; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(rbCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_FROM_DEV; io_hdr.dxfer_len = bufSize; io_hdr.dxferp = rbBuff; io_hdr.cmdp = rbCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.pack_id = 2; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { fprintf(stderr, " read buffer [mode data] cdb: "); for (k = 0; k < (int)sizeof(rbCmdBlk); ++k) fprintf(stderr, "%02x ", rbCmdBlk[k]); fprintf(stderr, "\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "SG_IO READ BUFFER data error"); free(rbBuff); return -1; } /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("READ BUFFER data, continuing", &io_hdr, 1); /* fall through */ case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("READ BUFFER data error", &io_hdr, 1); free(rbBuff); return res; } res = do_checksum ((int*)rbBuff, size, 0); free(rbBuff); return res; } int write_buffer (int sg_fd, unsigned size) { unsigned char wbCmdBlk[] = {WRITE_BUFFER, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int bufSize = size + addwrite; unsigned char * wbBuff = (unsigned char *)malloc(bufSize); unsigned char sense_buffer[32]; struct sg_io_hdr io_hdr; int k, res; if (NULL == wbBuff) return -1; memset(wbBuff, 0, bufSize); do_fill_buffer ((int*)wbBuff, size); wbCmdBlk[1] = RWB_MODE_DATA; wbCmdBlk[6] = 0xff & (bufSize >> 16); wbCmdBlk[7] = 0xff & (bufSize >> 8); wbCmdBlk[8] = 0xff & bufSize; memset(&io_hdr, 0, sizeof(struct sg_io_hdr)); io_hdr.interface_id = 'S'; io_hdr.cmd_len = sizeof(wbCmdBlk); io_hdr.mx_sb_len = sizeof(sense_buffer); io_hdr.dxfer_direction = SG_DXFER_TO_DEV; io_hdr.dxfer_len = bufSize; io_hdr.dxferp = wbBuff; io_hdr.cmdp = wbCmdBlk; io_hdr.sbp = sense_buffer; io_hdr.pack_id = 1; io_hdr.timeout = 60000; /* 60000 millisecs == 60 seconds */ if (verbose) { fprintf(stderr, " write buffer [mode data] cdb: "); for (k = 0; k < (int)sizeof(wbCmdBlk); ++k) fprintf(stderr, "%02x ", wbCmdBlk[k]); fprintf(stderr, "\n"); } if (ioctl(sg_fd, SG_IO, &io_hdr) < 0) { perror(ME "SG_IO WRITE BUFFER data error"); free(wbBuff); return -1; } /* now for the error processing */ res = sg_err_category3(&io_hdr); switch (res) { case SG_LIB_CAT_RECOVERED: sg_chk_n_print3("WRITE BUFFER data, continuing", &io_hdr, 1); /* fall through */ case SG_LIB_CAT_CLEAN: break; default: /* won't bother decoding other categories */ sg_chk_n_print3("WRITE BUFFER data error", &io_hdr, 1); free(wbBuff); return res; } free(wbBuff); return res; } void usage () { printf ("Usage: sg_test_rwbuf [--addrd=AR] [--addwr=AW] [--help] " "[--quick]\n"); printf (" --size=SZ [--times=NUM] [--verbose] " "[--version]\n" " DEVICE\n" " or\n" " sg_test_rwbuf DEVICE SZ [AW] [AR]\n"); printf (" where:\n" " --addrd=AR extra bytes to fetch during READ " "BUFFER\n" " --addwr=AW extra bytes to send to WRITE BUFFER\n" " --help output this usage message then exit\n" " --quick output read buffer size then exit\n" " --size=SZ size of buffer (in bytes) to write " "then read back\n" " --times=NUM number of times to run test " "(default 1)\n" " --verbose increase verbosity of output\n" " --version output version then exit\n"); printf ("\nWARNING: If you access the device at the same time, e.g. " "because it's a\n"); printf (" mounted hard disk, the device's buffer may be used by the " "device itself\n"); printf (" for other data at the same time, and overwriting it may or " "may not\n"); printf (" cause data corruption!\n"); printf ("(c) Douglas Gilbert, Kurt Garloff, 2000-2007, GNU GPL\n"); } int main (int argc, char * argv[]) { int sg_fd, res; const char * device_name = NULL; int times = 1; int ret = 0; int k = 0; while (1) { int option_index = 0; int c; c = getopt_long(argc, argv, "hqr:s:t:w:vV", long_options, &option_index); if (c == -1) break; switch (c) { case 'h': usage(); return 0; case 'q': do_quick = 1; break; case 'r': addread = sg_get_num(optarg); if (-1 == addread) { fprintf(stderr, "bad argument to '--addrd'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': size = sg_get_num(optarg); if (-1 == size) { fprintf(stderr, "bad argument to '--size'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 't': times = sg_get_num(optarg); if (-1 == times) { fprintf(stderr, "bad argument to '--times'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'v': verbose++; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'w': addwrite = sg_get_num(optarg); if (-1 == addwrite) { fprintf(stderr, "bad argument to '--addwr'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } } if (optind < argc) { if (-1 == size) { size = sg_get_num(argv[optind]); if (-1 == size) { fprintf(stderr, "bad \n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addwrite = sg_get_num(argv[optind]); if (-1 == addwrite) { fprintf(stderr, "bad [addwr]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (++optind < argc) { addread = sg_get_num(argv[optind]); if (-1 == addread) { fprintf(stderr, "bad [addrd]\n"); usage(); return SG_LIB_SYNTAX_ERROR; } } } } if (optind < argc) { for (; optind < argc; ++optind) fprintf(stderr, "Unexpected extra argument" ": %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == device_name) { fprintf(stderr, "no device name given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((size <= 0) && (! do_quick)) { fprintf(stderr, "must give '--size' or '--quick' options " "or argument\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = open(device_name, O_RDWR | O_NONBLOCK); if (sg_fd < 0) { perror("sg_test_rwbuf: open error"); return SG_LIB_FILE_ERROR; } ret = find_out_about_buffer(sg_fd); if (ret) goto err_out; if (do_quick) { printf ("READ BUFFER read descriptor reports a buffer " "of %d bytes [%d KiB]\n", buf_capacity, buf_capacity / 1024); goto err_out; } if (size > buf_capacity) { fprintf (stderr, ME "sz=%i > buf_capacity=%i\n", size, buf_capacity); ret = SG_LIB_CAT_OTHER; goto err_out; } cmpbuf = (unsigned char *)malloc(size); for (k = 0; k < times; ++k) { ret = write_buffer (sg_fd, size); if (ret) { goto err_out; } ret = read_buffer (sg_fd, size); if (ret) { if (2222 == ret) ret = SG_LIB_CAT_MALFORMED; goto err_out; } } err_out: if (cmpbuf) free(cmpbuf); res = close(sg_fd); if (res < 0) { perror(ME "close error"); if (0 == ret) ret = SG_LIB_FILE_ERROR; } if ((0 == ret) && (! do_quick)) printf ("Success\n"); else if (times > 1) printf ("Failed after %d successful cycles\n", k); return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sgp_dd.c0000664000175000017500000016415212335513125014554 0ustar douggdougg/* A utility program for copying files. Specialised for "files" that * represent devices that understand the SCSI command set. * * Copyright (C) 1999 - 2014 D. Gilbert and P. Allworth * 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. * * This program is a specialisation of the Unix "dd" command in which * one or both of the given files is a scsi generic device or a raw * device. A block size ('bs') is assumed to be 512 if not given. This * program complains if 'ibs' or 'obs' are given with some other value * than 'bs'. If 'if' is not given or 'if=-' then stdin is assumed. If * 'of' is not given or 'of=-' then stdout assumed. * * A non-standard argument "bpt" (blocks per transfer) is added to control * the maximum number of blocks in each transfer. The default value is 128. * For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB * in this case) are transferred to or from the sg device in a single SCSI * command. * * This version is designed for the linux kernel 2.4, 2.6 and 3 series. */ #define _XOPEN_SOURCE 500 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include #include /* */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_io_linux.h" static const char * version_str = "5.47 20140516"; #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 ME "sgp_dd: " /* #define SG_DEBUG */ #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #ifndef SERVICE_ACTION_IN #define SERVICE_ACTION_IN 0x9e #endif #ifndef SAI_READ_CAPACITY_16 #define SAI_READ_CAPACITY_16 0x10 #endif #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #define SGP_READ10 0x28 #define SGP_WRITE10 0x2a #define DEF_NUM_THREADS 4 #define MAX_NUM_THREADS SG_MAX_QUEUE #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikely value */ #endif #define FT_OTHER 1 /* filetype other than one of the following */ #define FT_SG 2 /* filetype is sg char device */ #define FT_RAW 4 /* filetype is raw char device */ #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */ #define FT_ST 16 /* filetype is st char device (tape) */ #define FT_BLOCK 32 /* filetype is a block device */ #define FT_ERROR 64 /* couldn't "stat" file */ #define DEV_NULL_MINOR_NUM 3 #define EBUFF_SZ 512 struct flags_t { int append; int coe; int dio; int direct; int dpo; int dsync; int excl; int fua; }; typedef struct request_collection { /* one instance visible to all threads */ int infd; int64_t skip; int in_type; int cdbsz_in; struct flags_t in_flags; int64_t in_blk; /* -\ next block address to read */ int64_t in_count; /* | blocks remaining for next read */ int64_t in_rem_count; /* | count of remaining in blocks */ int in_partial; /* | */ int in_stop; /* | */ pthread_mutex_t in_mutex; /* -/ */ int outfd; int64_t seek; int out_type; int cdbsz_out; struct flags_t out_flags; int64_t out_blk; /* -\ next block address to write */ int64_t out_count; /* | blocks remaining for next write */ int64_t out_rem_count; /* | count of remaining out blocks */ int out_partial; /* | */ int out_stop; /* | */ pthread_mutex_t out_mutex; /* | */ pthread_cond_t out_sync_cv; /* -/ hold writes until "in order" */ int bs; int bpt; int dio_incomplete; /* -\ */ int sum_of_resids; /* | */ pthread_mutex_t aux_mutex; /* -/ (also serializes some printf()s */ int debug; } Rq_coll; typedef struct request_element { /* one instance per worker thread */ int infd; int outfd; int wr; int64_t blk; int num_blks; unsigned char * buffp; unsigned char * alloc_bp; struct sg_io_hdr io_hdr; unsigned char cmd[MAX_SCSI_CDBSZ]; unsigned char sb[SENSE_BUFF_LEN]; int bs; int dio_incomplete; int resid; int cdbsz_in; int cdbsz_out; struct flags_t in_flags; struct flags_t out_flags; int debug; } Rq_elem; static sigset_t signal_set; static pthread_t sig_listen_thread_id; static const char * proc_allow_dio = "/proc/scsi/sg/allow_dio"; static void sg_in_operation(Rq_coll * clp, Rq_elem * rep); static void sg_out_operation(Rq_coll * clp, Rq_elem * rep); static int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks); static void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks); static int sg_start_io(Rq_elem * rep); static int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp); #define STRERR_BUFF_LEN 128 static pthread_mutex_t strerr_mut = PTHREAD_MUTEX_INITIALIZER; static int do_time = 0; static Rq_coll rcoll; static struct timeval start_tm; static int64_t dd_count = -1; static int num_threads = DEF_NUM_THREADS; static int do_sync = 0; static int exit_status = 0; static void calc_duration_throughput(int contin) { struct timeval end_tm, 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)rcoll.bs * (dd_count - rcoll.out_rem_count); fprintf(stderr, "time to transfer data %s %d.%06d secs", (contin ? "so far" : "was"), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) fprintf(stderr, ", %.2f MB/sec\n", b / (a * 1000000.0)); else fprintf(stderr, "\n"); } static void print_stats(const char * str) { int64_t infull, outfull; if (0 != rcoll.out_rem_count) fprintf(stderr, " remaining block count=%" PRId64 "\n", rcoll.out_rem_count); infull = dd_count - rcoll.in_rem_count; fprintf(stderr, "%s%" PRId64 "+%d records in\n", str, infull - rcoll.in_partial, rcoll.in_partial); outfull = dd_count - rcoll.out_rem_count; fprintf(stderr, "%s%" PRId64 "+%d records out\n", str, outfull - rcoll.out_partial, rcoll.out_partial); } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(sig, &sigact, NULL); fprintf(stderr, "Interrupted by signal,"); if (do_time) calc_duration_throughput(0); print_stats(""); kill(getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ fprintf(stderr, "Progress report, continuing ...\n"); if (do_time) calc_duration_throughput(1); print_stats(" "); } static void install_handler(int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } /* Make safe_strerror() thread safe */ static char * tsafe_strerror(int code, char * ebp) { char * cp; pthread_mutex_lock(&strerr_mut); cp = safe_strerror(code); strncpy(ebp, cp, STRERR_BUFF_LEN); pthread_mutex_unlock(&strerr_mut); ebp[STRERR_BUFF_LEN - 1] = '\0'; return ebp; } /* Following macro from D.R. Butenhof's POSIX threads book: * ISBN 0-201-63392-2 . [Highly recommended book.] Changed __FILE__ * to __func__ */ #define err_exit(code,text) do { \ char strerr_buff[STRERR_BUFF_LEN]; \ fprintf(stderr, "%s at \"%s\":%d: %s\n", \ text, __func__, __LINE__, tsafe_strerror(code, strerr_buff)); \ exit(1); \ } while (0) static int dd_filetype(const char * filename) { struct stat st; size_t len = strlen(filename); if ((1 == len) && ('.' == filename[0])) return FT_DEV_NULL; if (stat(filename, &st) < 0) return FT_ERROR; if (S_ISCHR(st.st_mode)) { if ((MEM_MAJOR == major(st.st_rdev)) && (DEV_NULL_MINOR_NUM == minor(st.st_rdev))) return FT_DEV_NULL; if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; } else if (S_ISBLK(st.st_mode)) return FT_BLOCK; return FT_OTHER; } static void usage() { fprintf(stderr, "Usage: " "sgp_dd [bs=BS] [count=COUNT] [ibs=BS] [if=IFILE]" " [iflag=FLAGS]\n" " [obs=BS] [of=OFILE] [oflag=FLAGS] " "[seek=SEEK] [skip=SKIP]\n" " [--help] [--version]\n\n"); fprintf(stderr, " [bpt=BPT] [cdbsz=6|10|12|16] [coe=0|1] " "[deb=VERB] [dio=0|1]\n" " [fua=0|1|2|3] [sync=0|1] [thr=THR] " "[time=0|1] [verbose=VERB]\n" " where:\n" " bpt is blocks_per_transfer (default is 128)\n" " bs must be device block size (default 512)\n" " cdbsz size of SCSI READ or WRITE cdb (default is 10)\n" " coe continue on error, 0->exit (def), " "1->zero + continue\n" " count number of blocks to copy (def: device size)\n" " deb for debug, 0->none (def), > 0->varying degrees of " "debug\n"); fprintf(stderr, " dio is direct IO, 1->attempt, 0->indirect IO (def)\n" " fua force unit access: 0->don't(def), 1->OFILE, " "2->IFILE,\n" " 3->OFILE+IFILE\n" " if file or device to read from (def: stdin)\n" " iflag comma separated list from: [coe,dio,direct,dpo," "dsync,excl,\n" " fua, null]\n" " of file or device to write to (def: stdout), " "OFILE of '.'\n" " treated as /dev/null\n" " oflag comma separated list from: [append,coe,dio,direct," "dpo,dsync,\n" " excl,fua,null]\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " sync 0->no sync(def), 1->SYNCHRONIZE CACHE on OFILE " "after copy\n" " thr is number of threads, must be > 0, default 4, " "max 16\n" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose same as 'deb=VERB': increase verbosity\n" " --help output this usage message then exit\n" " --version output version string then exit\n" "Copy from IFILE to OFILE, similar to dd command\n" "specialized for SCSI devices, uses multiple POSIX threads\n"); } static void guarded_stop_in(Rq_coll * clp) { pthread_mutex_lock(&clp->in_mutex); clp->in_stop = 1; pthread_mutex_unlock(&clp->in_mutex); } static void guarded_stop_out(Rq_coll * clp) { pthread_mutex_lock(&clp->out_mutex); clp->out_stop = 1; pthread_mutex_unlock(&clp->out_mutex); } static void guarded_stop_both(Rq_coll * clp) { guarded_stop_in(clp); guarded_stop_out(clp); } /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { int k, res; unsigned int ui; unsigned char rcBuff[RCAP16_REPLY_LEN]; res = sg_ll_readcap_10(sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 0, 0); if (0 != res) return res; if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { int64_t ls; res = sg_ll_readcap_16(sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 0, 0); if (0 != res) return res; for (k = 0, ls = 0; k < 8; ++k) { ls <<= 8; ls |= rcBuff[k]; } *num_sect = ls + 1; *sect_sz = (rcBuff[8] << 24) | (rcBuff[9] << 16) | (rcBuff[10] << 8) | rcBuff[11]; } else { ui = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]); /* take care not to sign extend values > 0x7fffffff */ *num_sect = (int64_t)ui + 1; *sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | (rcBuff[6] << 8) | rcBuff[7]; } return 0; } /* Return of 0 -> success, -1 -> failure. BLKGETSIZE64, BLKGETSIZE and */ /* BLKSSZGET macros problematic (from or ). */ static int read_blkdev_capacity(int sg_fd, int64_t * num_sect, int * sect_sz) { #ifdef BLKSSZGET if ((ioctl(sg_fd, BLKSSZGET, sect_sz) < 0) && (*sect_sz > 0)) { perror("BLKSSZGET ioctl error"); return -1; } else { #ifdef BLKGETSIZE64 uint64_t ull; if (ioctl(sg_fd, BLKGETSIZE64, &ull) < 0) { perror("BLKGETSIZE64 ioctl error"); return -1; } *num_sect = ((int64_t)ull / (int64_t)*sect_sz); #else unsigned long ul; if (ioctl(sg_fd, BLKGETSIZE, &ul) < 0) { perror("BLKGETSIZE ioctl error"); return -1; } *num_sect = (int64_t)ul; #endif } return 0; #else *num_sect = 0; *sect_sz = 0; return -1; #endif } static void * sig_listen_thread(void * v_clp) { Rq_coll * clp = (Rq_coll *)v_clp; int sig_number; while (1) { sigwait(&signal_set, &sig_number); if (SIGINT == sig_number) { fprintf(stderr, ME "interrupted by SIGINT\n"); guarded_stop_both(clp); pthread_cond_broadcast(&clp->out_sync_cv); } } return NULL; } static void cleanup_in(void * v_clp) { Rq_coll * clp = (Rq_coll *)v_clp; fprintf(stderr, "thread cancelled while in mutex held\n"); clp->in_stop = 1; pthread_mutex_unlock(&clp->in_mutex); guarded_stop_out(clp); pthread_cond_broadcast(&clp->out_sync_cv); } static void cleanup_out(void * v_clp) { Rq_coll * clp = (Rq_coll *)v_clp; fprintf(stderr, "thread cancelled while out mutex held\n"); clp->out_stop = 1; pthread_mutex_unlock(&clp->out_mutex); guarded_stop_in(clp); pthread_cond_broadcast(&clp->out_sync_cv); } static void * read_write_thread(void * v_clp) { Rq_coll * clp; Rq_elem rel; Rq_elem * rep = &rel; size_t psz = 0; int sz; volatile int stop_after_write = 0; int64_t seek_skip; int blocks, status; clp = (Rq_coll *)v_clp; sz = clp->bpt * clp->bs; seek_skip = clp->seek - clp->skip; memset(rep, 0, sizeof(Rq_elem)); #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE) psz = sysconf(_SC_PAGESIZE); /* POSIX.1 (was getpagesize()) */ #else psz = 4096; /* give up, pick likely figure */ #endif if (NULL == (rep->alloc_bp = (unsigned char *)malloc(sz + psz))) err_exit(ENOMEM, "out of memory creating user buffers\n"); rep->buffp = (unsigned char *)(((unsigned long)rep->alloc_bp + psz - 1) & (~(psz - 1))); /* Follow clp members are constant during lifetime of thread */ rep->bs = clp->bs; rep->infd = clp->infd; rep->outfd = clp->outfd; rep->debug = clp->debug; rep->cdbsz_in = clp->cdbsz_in; rep->cdbsz_out = clp->cdbsz_out; rep->in_flags = clp->in_flags; rep->out_flags = clp->out_flags; while(1) { status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); if (clp->in_stop || (clp->in_count <= 0)) { /* no more to do, exit loop then thread */ status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); break; } blocks = (clp->in_count > clp->bpt) ? clp->bpt : clp->in_count; rep->wr = 0; rep->blk = clp->in_blk; rep->num_blks = blocks; clp->in_blk += blocks; clp->in_count -= blocks; pthread_cleanup_push(cleanup_in, (void *)clp); if (FT_SG == clp->in_type) sg_in_operation(clp, rep); /* lets go of in_mutex mid operation */ else { stop_after_write = normal_in_operation(clp, rep, blocks); status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); } pthread_cleanup_pop(0); status = pthread_mutex_lock(&clp->out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); if (FT_DEV_NULL != clp->out_type) { while ((! clp->out_stop) && ((rep->blk + seek_skip) != clp->out_blk)) { /* if write would be out of sequence then wait */ pthread_cleanup_push(cleanup_out, (void *)clp); status = pthread_cond_wait(&clp->out_sync_cv, &clp->out_mutex); if (0 != status) err_exit(status, "cond out_sync_cv"); pthread_cleanup_pop(0); } } if (clp->out_stop || (clp->out_count <= 0)) { if (! clp->out_stop) clp->out_stop = 1; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); break; } if (stop_after_write) clp->out_stop = 1; rep->wr = 1; rep->blk = clp->out_blk; clp->out_blk += blocks; clp->out_count -= blocks; if (0 == rep->num_blks) { clp->out_stop = 1; stop_after_write = 1; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); break; /* read nothing so leave loop */ } pthread_cleanup_push(cleanup_out, (void *)clp); if (FT_SG == clp->out_type) sg_out_operation(clp, rep); /* releases out_mutex mid operation */ else if (FT_DEV_NULL == clp->out_type) { /* skip actual write operation */ clp->out_rem_count -= blocks; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); } else { normal_out_operation(clp, rep, blocks); status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); } pthread_cleanup_pop(0); if (stop_after_write) break; pthread_cond_broadcast(&clp->out_sync_cv); } /* end of while loop */ if (rep->alloc_bp) free(rep->alloc_bp); status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); if (! clp->in_stop) clp->in_stop = 1; /* flag other workers to stop */ status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); pthread_cond_broadcast(&clp->out_sync_cv); return stop_after_write ? NULL : clp; } static int normal_in_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; int stop_after_write = 0; char strerr_buff[STRERR_BUFF_LEN]; /* enters holding in_mutex */ while (((res = read(clp->infd, rep->buffp, blocks * clp->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { if (clp->in_flags.coe) { memset(rep->buffp, 0, rep->num_blks * rep->bs); fprintf(stderr, ">> substituted zeros for in blk=%" PRId64 " for " "%d bytes, %s\n", rep->blk, rep->num_blks * rep->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * clp->bs; } else { fprintf(stderr, "error in normal read, %s\n", tsafe_strerror(errno, strerr_buff)); clp->in_stop = 1; guarded_stop_out(clp); return 1; } } if (res < blocks * clp->bs) { int o_blocks = blocks; stop_after_write = 1; blocks = res / clp->bs; if ((res % clp->bs) > 0) { blocks++; clp->in_partial++; } /* Reverse out + re-apply blocks on clp */ clp->in_blk -= o_blocks; clp->in_count += o_blocks; rep->num_blks = blocks; clp->in_blk += blocks; clp->in_count -= blocks; } clp->in_rem_count -= blocks; return stop_after_write; } static void normal_out_operation(Rq_coll * clp, Rq_elem * rep, int blocks) { int res; char strerr_buff[STRERR_BUFF_LEN]; /* enters holding out_mutex */ while (((res = write(clp->outfd, rep->buffp, rep->num_blks * clp->bs)) < 0) && (EINTR == errno)) ; if (res < 0) { if (clp->out_flags.coe) { fprintf(stderr, ">> ignored error for out blk=%" PRId64 " for " "%d bytes, %s\n", rep->blk, rep->num_blks * rep->bs, tsafe_strerror(errno, strerr_buff)); res = rep->num_blks * clp->bs; } else { fprintf(stderr, "error normal write, %s\n", tsafe_strerror(errno, strerr_buff)); guarded_stop_in(clp); clp->out_stop = 1; return; } } if (res < blocks * clp->bs) { blocks = res / clp->bs; if ((res % clp->bs) > 0) { blocks++; clp->out_partial++; } rep->num_blks = blocks; } clp->out_rem_count -= blocks; } static int sg_build_scsi_cdb(unsigned char * cdbp, int cdb_sz, unsigned int blocks, int64_t start_block, int write_true, int fua, int dpo) { int rd_opcode[] = {0x8, 0x28, 0xa8, 0x88}; int wr_opcode[] = {0xa, 0x2a, 0xaa, 0x8a}; int sz_ind; memset(cdbp, 0, cdb_sz); if (dpo) cdbp[1] |= 0x10; if (fua) cdbp[1] |= 0x8; switch (cdb_sz) { case 6: sz_ind = 0; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[1] = (unsigned char)((start_block >> 16) & 0x1f); cdbp[2] = (unsigned char)((start_block >> 8) & 0xff); cdbp[3] = (unsigned char)(start_block & 0xff); cdbp[4] = (256 == blocks) ? 0 : (unsigned char)blocks; if (blocks > 256) { fprintf(stderr, ME "for 6 byte commands, maximum number of " "blocks is 256\n"); return 1; } if ((start_block + blocks - 1) & (~0x1fffff)) { fprintf(stderr, ME "for 6 byte commands, can't address blocks" " beyond %d\n", 0x1fffff); return 1; } if (dpo || fua) { fprintf(stderr, ME "for 6 byte commands, neither dpo nor fua" " bits supported\n"); return 1; } break; case 10: sz_ind = 1; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[7] = (unsigned char)((blocks >> 8) & 0xff); cdbp[8] = (unsigned char)(blocks & 0xff); if (blocks & (~0xffff)) { fprintf(stderr, ME "for 10 byte commands, maximum number of " "blocks is %d\n", 0xffff); return 1; } break; case 12: sz_ind = 2; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 24) & 0xff); cdbp[3] = (unsigned char)((start_block >> 16) & 0xff); cdbp[4] = (unsigned char)((start_block >> 8) & 0xff); cdbp[5] = (unsigned char)(start_block & 0xff); cdbp[6] = (unsigned char)((blocks >> 24) & 0xff); cdbp[7] = (unsigned char)((blocks >> 16) & 0xff); cdbp[8] = (unsigned char)((blocks >> 8) & 0xff); cdbp[9] = (unsigned char)(blocks & 0xff); break; case 16: sz_ind = 3; cdbp[0] = (unsigned char)(write_true ? wr_opcode[sz_ind] : rd_opcode[sz_ind]); cdbp[2] = (unsigned char)((start_block >> 56) & 0xff); cdbp[3] = (unsigned char)((start_block >> 48) & 0xff); cdbp[4] = (unsigned char)((start_block >> 40) & 0xff); cdbp[5] = (unsigned char)((start_block >> 32) & 0xff); cdbp[6] = (unsigned char)((start_block >> 24) & 0xff); cdbp[7] = (unsigned char)((start_block >> 16) & 0xff); cdbp[8] = (unsigned char)((start_block >> 8) & 0xff); cdbp[9] = (unsigned char)(start_block & 0xff); cdbp[10] = (unsigned char)((blocks >> 24) & 0xff); cdbp[11] = (unsigned char)((blocks >> 16) & 0xff); cdbp[12] = (unsigned char)((blocks >> 8) & 0xff); cdbp[13] = (unsigned char)(blocks & 0xff); break; default: fprintf(stderr, ME "expected cdb size of 6, 10, 12, or 16 but got" " %d\n", cdb_sz); return 1; } return 0; } static void sg_in_operation(Rq_coll * clp, Rq_elem * rep) { int res; int status; /* enters holding in_mutex */ while (1) { res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting in command"); else if (res < 0) { fprintf(stderr, ME "inputting to sg failed, blk=%" PRId64 "\n", rep->blk); status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); guarded_stop_both(clp); return; } /* Now release in mutex to let other reads run in parallel */ status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); switch (res) { case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: /* try again with same addr, count info */ /* now re-acquire in mutex for balance */ /* N.B. This re-read could now be out of read sequence */ status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); break; case SG_LIB_CAT_MEDIUM_HARD: if (0 == clp->in_flags.coe) { fprintf(stderr, "error finishing sg in command (medium)\n"); if (exit_status <= 0) exit_status = res; guarded_stop_both(clp); return; } else { memset(rep->buffp, 0, rep->num_blks * rep->bs); fprintf(stderr, ">> substituted zeros for in blk=%" PRId64 " for %d bytes\n", rep->blk, rep->num_blks * rep->bs); } /* fall through */ case 0: if (rep->dio_incomplete || rep->resid) { status = pthread_mutex_lock(&clp->aux_mutex); if (0 != status) err_exit(status, "lock aux_mutex"); clp->dio_incomplete += rep->dio_incomplete; clp->sum_of_resids += rep->resid; status = pthread_mutex_unlock(&clp->aux_mutex); if (0 != status) err_exit(status, "unlock aux_mutex"); } status = pthread_mutex_lock(&clp->in_mutex); if (0 != status) err_exit(status, "lock in_mutex"); clp->in_rem_count -= rep->num_blks; status = pthread_mutex_unlock(&clp->in_mutex); if (0 != status) err_exit(status, "unlock in_mutex"); return; default: fprintf(stderr, "error finishing sg in command (%d)\n", res); if (exit_status <= 0) exit_status = res; guarded_stop_both(clp); return; } } } static void sg_out_operation(Rq_coll * clp, Rq_elem * rep) { int res; int status; /* enters holding out_mutex */ while (1) { res = sg_start_io(rep); if (1 == res) err_exit(ENOMEM, "sg starting out command"); else if (res < 0) { fprintf(stderr, ME "outputting from sg failed, blk=%" PRId64 "\n", rep->blk); status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); guarded_stop_both(clp); return; } /* Now release in mutex to let other reads run in parallel */ status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); res = sg_finish_io(rep->wr, rep, &clp->aux_mutex); switch (res) { case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: /* try again with same addr, count info */ /* now re-acquire out mutex for balance */ /* N.B. This re-write could now be out of write sequence */ status = pthread_mutex_lock(&clp->out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); break; case SG_LIB_CAT_MEDIUM_HARD: if (0 == clp->out_flags.coe) { fprintf(stderr, "error finishing sg out command (medium)\n"); if (exit_status <= 0) exit_status = res; guarded_stop_both(clp); return; } else fprintf(stderr, ">> ignored error for out blk=%" PRId64 " for %d bytes\n", rep->blk, rep->num_blks * rep->bs); /* fall through */ case 0: if (rep->dio_incomplete || rep->resid) { status = pthread_mutex_lock(&clp->aux_mutex); if (0 != status) err_exit(status, "lock aux_mutex"); clp->dio_incomplete += rep->dio_incomplete; clp->sum_of_resids += rep->resid; status = pthread_mutex_unlock(&clp->aux_mutex); if (0 != status) err_exit(status, "unlock aux_mutex"); } status = pthread_mutex_lock(&clp->out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); clp->out_rem_count -= rep->num_blks; status = pthread_mutex_unlock(&clp->out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); return; default: fprintf(stderr, "error finishing sg out command (%d)\n", res); if (exit_status <= 0) exit_status = res; guarded_stop_both(clp); return; } } } static int sg_start_io(Rq_elem * rep) { struct sg_io_hdr * hp = &rep->io_hdr; int fua = rep->wr ? rep->out_flags.fua : rep->in_flags.fua; int dpo = rep->wr ? rep->out_flags.dpo : rep->in_flags.dpo; int dio = rep->wr ? rep->out_flags.dio : rep->in_flags.dio; int cdbsz = rep->wr ? rep->cdbsz_out : rep->cdbsz_in; int res; if (sg_build_scsi_cdb(rep->cmd, cdbsz, rep->num_blks, rep->blk, rep->wr, fua, dpo)) { fprintf(stderr, ME "bad cdb build, start_blk=%" PRId64 ", blocks=%d\n", rep->blk, rep->num_blks); return -1; } memset(hp, 0, sizeof(struct sg_io_hdr)); hp->interface_id = 'S'; hp->cmd_len = cdbsz; hp->cmdp = rep->cmd; hp->dxfer_direction = rep->wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; hp->dxfer_len = rep->bs * rep->num_blks; hp->dxferp = rep->buffp; hp->mx_sb_len = sizeof(rep->sb); hp->sbp = rep->sb; hp->timeout = DEF_TIMEOUT; hp->usr_ptr = rep; hp->pack_id = (int)rep->blk; if (dio) hp->flags |= SG_FLAG_DIRECT_IO; if (rep->debug > 8) { fprintf(stderr, "sg_start_io: SCSI %s, blk=%" PRId64 " num_blks=%d\n", rep->wr ? "WRITE" : "READ", rep->blk, rep->num_blks); sg_print_command(hp->cmdp); } while (((res = write(rep->wr ? rep->outfd : rep->infd, hp, sizeof(struct sg_io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { if (ENOMEM == errno) return 1; perror("starting io on sg device, error"); return -1; } return 0; } /* 0 -> successful, SG_LIB_CAT_UNIT_ATTENTION or SG_LIB_CAT_ABORTED_COMMAND -> try again, SG_LIB_CAT_NOT_READY, SG_LIB_CAT_MEDIUM_HARD, -1 other errors */ static int sg_finish_io(int wr, Rq_elem * rep, pthread_mutex_t * a_mutp) { int res, status; struct sg_io_hdr io_hdr; struct sg_io_hdr * hp; #if 0 static int testing = 0; /* thread dubious! */ #endif memset(&io_hdr, 0 , sizeof(struct sg_io_hdr)); /* FORCE_PACK_ID active set only read packet with matching pack_id */ io_hdr.interface_id = 'S'; io_hdr.dxfer_direction = wr ? SG_DXFER_TO_DEV : SG_DXFER_FROM_DEV; io_hdr.pack_id = (int)rep->blk; while (((res = read(wr ? rep->outfd : rep->infd, &io_hdr, sizeof(struct sg_io_hdr))) < 0) && (EINTR == errno)) ; if (res < 0) { perror("finishing io on sg device, error"); return -1; } if (rep != (Rq_elem *)io_hdr.usr_ptr) err_exit(0, "sg_finish_io: bad usr_ptr, request-response mismatch\n"); memcpy(&rep->io_hdr, &io_hdr, sizeof(struct sg_io_hdr)); hp = &rep->io_hdr; res = sg_err_category3(hp); switch (res) { case SG_LIB_CAT_CLEAN: break; case SG_LIB_CAT_RECOVERED: sg_chk_n_print3((wr ? "writing continuing": "reading continuing"), hp, 0); break; case SG_LIB_CAT_ABORTED_COMMAND: case SG_LIB_CAT_UNIT_ATTENTION: if (rep->debug > 8) sg_chk_n_print3((wr ? "writing": "reading"), hp, 0); return res; case SG_LIB_CAT_NOT_READY: default: { char ebuff[EBUFF_SZ]; snprintf(ebuff, EBUFF_SZ, "%s blk=%" PRId64, wr ? "writing": "reading", rep->blk); status = pthread_mutex_lock(a_mutp); if (0 != status) err_exit(status, "lock aux_mutex"); sg_chk_n_print3(ebuff, hp, 0); status = pthread_mutex_unlock(a_mutp); if (0 != status) err_exit(status, "unlock aux_mutex"); return res; } } #if 0 if (0 == (++testing % 100)) return -1; #endif if ((wr ? rep->out_flags.dio : rep->in_flags.dio) && ((hp->info & SG_INFO_DIRECT_IO_MASK) != SG_INFO_DIRECT_IO)) rep->dio_incomplete = 1; /* count dios done as indirect IO */ else rep->dio_incomplete = 0; rep->resid = hp->resid; if (rep->debug > 8) fprintf(stderr, "sg_finish_io: completed %s\n", wr ? "WRITE" : "READ"); return 0; } static int sg_prepare(int fd, int bs, int bpt) { int res, t; res = ioctl(fd, SG_GET_VERSION_NUM, &t); if ((res < 0) || (t < 30000)) { fprintf(stderr, ME "sg driver prior to 3.x.y\n"); return 1; } res = 0; t = bs * bpt; res = ioctl(fd, SG_SET_RESERVED_SIZE, &t); if (res < 0) perror(ME "SG_SET_RESERVED_SIZE error"); t = 1; res = ioctl(fd, SG_SET_FORCE_PACK_ID, &t); if (res < 0) perror(ME "SG_SET_FORCE_PACK_ID error"); return 0; } static int process_flags(const char * arg, struct flags_t * fp) { char buff[256]; char * cp; char * np; strncpy(buff, arg, sizeof(buff)); buff[sizeof(buff) - 1] = '\0'; if ('\0' == buff[0]) { fprintf(stderr, "no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = 1; else if (0 == strcmp(cp, "coe")) fp->coe = 1; else if (0 == strcmp(cp, "dio")) fp->dio = 1; else if (0 == strcmp(cp, "direct")) fp->direct = 1; else if (0 == strcmp(cp, "dpo")) fp->dpo = 1; else if (0 == strcmp(cp, "dsync")) fp->dsync = 1; else if (0 == strcmp(cp, "excl")) fp->excl = 1; else if (0 == strcmp(cp, "fua")) fp->fua = 1; else if (0 == strcmp(cp, "null")) ; else { fprintf(stderr, "unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } #define STR_SZ 1024 #define INOUTF_SZ 512 int main(int argc, char * argv[]) { int64_t skip = 0; int64_t seek = 0; int ibs = 0; int obs = 0; int bpt_given = 0; int cdbsz_given = 0; char str[STR_SZ]; char * key; char * buf; char inf[INOUTF_SZ]; char outf[INOUTF_SZ]; int res, k; int64_t in_num_sect = 0; int64_t out_num_sect = 0; pthread_t threads[MAX_NUM_THREADS]; int in_sect_sz, out_sect_sz, status, n, flags; void * vp; char ebuff[EBUFF_SZ]; memset(&rcoll, 0, sizeof(Rq_coll)); rcoll.bpt = DEF_BLOCKS_PER_TRANSFER; rcoll.in_type = FT_OTHER; rcoll.out_type = FT_OTHER; rcoll.cdbsz_in = DEF_SCSI_CDBSZ; rcoll.cdbsz_out = DEF_SCSI_CDBSZ; inf[0] = '\0'; outf[0] = '\0'; for (k = 1; k < argc; k++) { if (argv[k]) { strncpy(str, argv[k], STR_SZ); str[STR_SZ - 1] = '\0'; } else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; if (0 == strcmp(key,"bpt")) { rcoll.bpt = sg_get_num(buf); if (-1 == rcoll.bpt) { fprintf(stderr, ME "bad argument to 'bpt='\n"); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key,"bs")) { rcoll.bs = sg_get_num(buf); if (-1 == rcoll.bs) { fprintf(stderr, ME "bad argument to 'bs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"cdbsz")) { rcoll.cdbsz_in = sg_get_num(buf); rcoll.cdbsz_out = rcoll.cdbsz_in; cdbsz_given = 1; } else if (0 == strcmp(key,"coe")) { rcoll.in_flags.coe = sg_get_num(buf); rcoll.out_flags.coe = rcoll.in_flags.coe; } else if (0 == strcmp(key,"count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if (-1LL == dd_count) { fprintf(stderr, ME "bad argument to 'count='\n"); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if ((0 == strncmp(key,"deb", 3)) || (0 == strncmp(key,"verb", 4))) rcoll.debug = sg_get_num(buf); else if (0 == strcmp(key,"dio")) { rcoll.in_flags.dio = sg_get_num(buf); rcoll.out_flags.dio = rcoll.in_flags.dio; } else if (0 == strcmp(key,"fua")) { n = sg_get_num(buf); if (n & 1) rcoll.out_flags.fua = 1; if (n & 2) rcoll.in_flags.fua = 1; } else if (0 == strcmp(key,"ibs")) { ibs = sg_get_num(buf); if (-1 == ibs) { fprintf(stderr, ME "bad argument to 'ibs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"if") == 0) { if ('\0' != inf[0]) { fprintf(stderr, "Second 'if=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(inf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &rcoll.in_flags)) { fprintf(stderr, ME "bad argument to 'iflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"obs")) { obs = sg_get_num(buf); if (-1 == obs) { fprintf(stderr, ME "bad argument to 'obs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (strcmp(key,"of") == 0) { if ('\0' != outf[0]) { fprintf(stderr, "Second 'of=' argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(outf, buf, INOUTF_SZ); } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &rcoll.out_flags)) { fprintf(stderr, ME "bad argument to 'oflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"seek")) { seek = sg_get_llnum(buf); if (-1LL == seek) { fprintf(stderr, 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) { fprintf(stderr, ME "bad argument to 'skip='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key,"sync")) do_sync = sg_get_num(buf); else if (0 == strcmp(key,"thr")) num_threads = sg_get_num(buf); else if (0 == strcmp(key,"time")) do_time = sg_get_num(buf); else if ((0 == strncmp(key, "--help", 7)) || (0 == strncmp(key, "-h", 2)) || (0 == strcmp(key, "-?"))) { usage(); return 0; } else if ((0 == strncmp(key, "--vers", 6)) || (0 == strcmp(key, "-V"))) { fprintf(stderr, ME ": %s\n", version_str); return 0; } else { fprintf(stderr, "Unrecognized option '%s'\n", key); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (rcoll.bs <= 0) { rcoll.bs = DEF_BLOCK_SIZE; fprintf(stderr, "Assume default 'bs' (block size) of %d bytes\n", rcoll.bs); } if ((ibs && (ibs != rcoll.bs)) || (obs && (obs != rcoll.bs))) { fprintf(stderr, "If 'ibs' or 'obs' given must be same as 'bs'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((skip < 0) || (seek < 0)) { fprintf(stderr, "skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if ((rcoll.out_flags.append > 0) && (seek > 0)) { fprintf(stderr, "Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (rcoll.bpt < 1) { fprintf(stderr, "bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } /* defaulting transfer size to 128*2048 for CD/DVDs is too large for the block layer in lk 2.6 and results in an EIO on the SG_IO ioctl. So reduce it in that case. */ if ((rcoll.bs >= 2048) && (0 == bpt_given)) rcoll.bpt = DEF_BLOCKS_PER_2048TRANSFER; if ((num_threads < 1) || (num_threads > MAX_NUM_THREADS)) { fprintf(stderr, "too few or too many threads requested\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (rcoll.debug) fprintf(stderr, ME "if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", inf, skip, outf, seek, dd_count); install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); rcoll.infd = STDIN_FILENO; rcoll.outfd = STDOUT_FILENO; if (inf[0] && ('-' != inf[0])) { rcoll.in_type = dd_filetype(inf); if (FT_ERROR == rcoll.in_type) { fprintf(stderr, ME "unable to access %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_ST == rcoll.in_type) { fprintf(stderr, ME "unable to use scsi tape device %s\n", inf); return SG_LIB_FILE_ERROR; } else if (FT_SG == rcoll.in_type) { flags = O_RDWR; if (rcoll.in_flags.direct) flags |= O_DIRECT; if (rcoll.in_flags.excl) flags |= O_EXCL; if (rcoll.in_flags.dsync) flags |= O_SYNC; if ((rcoll.infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (sg_prepare(rcoll.infd, rcoll.bs, rcoll.bpt)) return SG_LIB_FILE_ERROR; } else { flags = O_RDONLY; if (rcoll.in_flags.direct) flags |= O_DIRECT; if (rcoll.in_flags.excl) flags |= O_EXCL; if (rcoll.in_flags.dsync) flags |= O_SYNC; if ((rcoll.infd = open(inf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } else if (skip > 0) { off64_t offset = skip; offset *= rcoll.bs; /* could exceed 32 here! */ if (lseek64(rcoll.infd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't skip to required position on %s", inf); perror(ebuff); return SG_LIB_FILE_ERROR; } } } } if (outf[0] && ('-' != outf[0])) { rcoll.out_type = dd_filetype(outf); if (FT_ST == rcoll.out_type) { fprintf(stderr, ME "unable to use scsi tape device %s\n", outf); return SG_LIB_FILE_ERROR; } else if (FT_SG == rcoll.out_type) { flags = O_RDWR; if (rcoll.out_flags.direct) flags |= O_DIRECT; if (rcoll.out_flags.excl) flags |= O_EXCL; if (rcoll.out_flags.dsync) flags |= O_SYNC; if ((rcoll.outfd = open(outf, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } if (sg_prepare(rcoll.outfd, rcoll.bs, rcoll.bpt)) return SG_LIB_FILE_ERROR; } else if (FT_DEV_NULL == rcoll.out_type) rcoll.outfd = -1; /* don't bother opening */ else { if (FT_RAW != rcoll.out_type) { flags = O_WRONLY | O_CREAT; if (rcoll.out_flags.direct) flags |= O_DIRECT; if (rcoll.out_flags.excl) flags |= O_EXCL; if (rcoll.out_flags.dsync) flags |= O_SYNC; if (rcoll.out_flags.append) flags |= O_APPEND; if ((rcoll.outfd = open(outf, flags, 0666)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } else { /* raw output file */ if ((rcoll.outfd = open(outf, O_WRONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for raw writing", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } if (seek > 0) { off64_t offset = seek; offset *= rcoll.bs; /* could exceed 32 bits here! */ if (lseek64(rcoll.outfd, offset, SEEK_SET) < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't seek to required position on %s", outf); perror(ebuff); return SG_LIB_FILE_ERROR; } } } } if ((STDIN_FILENO == rcoll.infd) && (STDOUT_FILENO == rcoll.outfd)) { fprintf(stderr, "Won't default both IFILE to stdin _and_ OFILE to " "stdout\n"); fprintf(stderr, "For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if (dd_count < 0) { in_num_sect = -1; if (FT_SG == rcoll.in_type) { res = scsi_read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(in), continuing\n"); res = scsi_read_capacity(rcoll.infd, &in_num_sect, &in_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) fprintf(stderr, "read capacity not supported on %s\n", inf); else if (res == SG_LIB_CAT_NOT_READY) fprintf(stderr, "read capacity failed, %s not ready\n", inf); else fprintf(stderr, "Unable to read capacity on %s\n", inf); in_num_sect = -1; } } else if (FT_BLOCK == rcoll.in_type) { if (0 != read_blkdev_capacity(rcoll.infd, &in_num_sect, &in_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", inf); in_num_sect = -1; } if (rcoll.bs != in_sect_sz) { fprintf(stderr, "block size on %s confusion; bs=%d, from " "device=%d\n", inf, rcoll.bs, in_sect_sz); in_num_sect = -1; } } if (in_num_sect > skip) in_num_sect -= skip; out_num_sect = -1; if (FT_SG == rcoll.out_type) { res = scsi_read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); if (2 == res) { fprintf(stderr, "Unit attention, media changed(out), continuing\n"); res = scsi_read_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) fprintf(stderr, "read capacity not supported on %s\n", outf); else if (res == SG_LIB_CAT_NOT_READY) fprintf(stderr, "read capacity failed, %s not ready\n", outf); else fprintf(stderr, "Unable to read capacity on %s\n", outf); out_num_sect = -1; } } else if (FT_BLOCK == rcoll.out_type) { if (0 != read_blkdev_capacity(rcoll.outfd, &out_num_sect, &out_sect_sz)) { fprintf(stderr, "Unable to read block capacity on %s\n", outf); out_num_sect = -1; } if (rcoll.bs != out_sect_sz) { fprintf(stderr, "block size on %s confusion: bs=%d, from " "device=%d\n", outf, rcoll.bs, out_sect_sz); out_num_sect = -1; } } if (out_num_sect > seek) out_num_sect -= seek; if (in_num_sect > 0) { if (out_num_sect > 0) dd_count = (in_num_sect > out_num_sect) ? out_num_sect : in_num_sect; else dd_count = in_num_sect; } else dd_count = out_num_sect; } if (rcoll.debug > 1) fprintf(stderr, "Start of loop, count=%" PRId64 ", in_num_sect=%" PRId64 ", out_num_sect=%" PRId64 "\n", dd_count, in_num_sect, out_num_sect); if (dd_count < 0) { fprintf(stderr, "Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if (! cdbsz_given) { if ((FT_SG == rcoll.in_type) && (MAX_SCSI_CDBSZ != rcoll.cdbsz_in) && (((dd_count + skip) > UINT_MAX) || (rcoll.bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'if')\n"); rcoll.cdbsz_in = MAX_SCSI_CDBSZ; } if ((FT_SG == rcoll.out_type) && (MAX_SCSI_CDBSZ != rcoll.cdbsz_out) && (((dd_count + seek) > UINT_MAX) || (rcoll.bpt > USHRT_MAX))) { fprintf(stderr, "Note: SCSI command size increased to 16 bytes " "(for 'of')\n"); rcoll.cdbsz_out = MAX_SCSI_CDBSZ; } } rcoll.in_count = dd_count; rcoll.in_rem_count = dd_count; rcoll.skip = skip; rcoll.in_blk = skip; rcoll.out_count = dd_count; rcoll.out_rem_count = dd_count; rcoll.seek = seek; rcoll.out_blk = seek; status = pthread_mutex_init(&rcoll.in_mutex, NULL); if (0 != status) err_exit(status, "init in_mutex"); status = pthread_mutex_init(&rcoll.out_mutex, NULL); if (0 != status) err_exit(status, "init out_mutex"); status = pthread_mutex_init(&rcoll.aux_mutex, NULL); if (0 != status) err_exit(status, "init aux_mutex"); status = pthread_cond_init(&rcoll.out_sync_cv, NULL); if (0 != status) err_exit(status, "init out_sync_cv"); sigemptyset(&signal_set); sigaddset(&signal_set, SIGINT); status = pthread_sigmask(SIG_BLOCK, &signal_set, NULL); if (0 != status) err_exit(status, "pthread_sigmask"); status = pthread_create(&sig_listen_thread_id, NULL, sig_listen_thread, (void *)&rcoll); if (0 != status) err_exit(status, "pthread_create, sig..."); if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } /* vvvvvvvvvvv Start worker threads vvvvvvvvvvvvvvvvvvvvvvvv */ if ((rcoll.out_rem_count > 0) && (num_threads > 0)) { /* Run 1 work thread to shake down infant retryable stuff */ status = pthread_mutex_lock(&rcoll.out_mutex); if (0 != status) err_exit(status, "lock out_mutex"); status = pthread_create(&threads[0], NULL, read_write_thread, (void *)&rcoll); if (0 != status) err_exit(status, "pthread_create"); if (rcoll.debug) fprintf(stderr, "Starting worker thread k=0\n"); /* wait for any broadcast */ pthread_cleanup_push(cleanup_out, (void *)&rcoll); status = pthread_cond_wait(&rcoll.out_sync_cv, &rcoll.out_mutex); if (0 != status) err_exit(status, "cond out_sync_cv"); pthread_cleanup_pop(0); status = pthread_mutex_unlock(&rcoll.out_mutex); if (0 != status) err_exit(status, "unlock out_mutex"); /* now start the rest of the threads */ for (k = 1; k < num_threads; ++k) { status = pthread_create(&threads[k], NULL, read_write_thread, (void *)&rcoll); if (0 != status) err_exit(status, "pthread_create"); if (rcoll.debug) fprintf(stderr, "Starting worker thread k=%d\n", k); } /* now wait for worker threads to finish */ for (k = 0; k < num_threads; ++k) { status = pthread_join(threads[k], &vp); if (0 != status) err_exit(status, "pthread_join"); if (rcoll.debug) fprintf(stderr, "Worker thread k=%d terminated\n", k); } } if ((do_time) && (start_tm.tv_sec || start_tm.tv_usec)) calc_duration_throughput(0); if (do_sync) { if (FT_SG == rcoll.out_type) { fprintf(stderr, ">> Synchronizing cache on %s\n", outf); res = sg_ll_sync_cache_10(rcoll.outfd, 0, 0, 0, 0, 0, 0, 0); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Unit attention(out), continuing\n"); res = sg_ll_sync_cache_10(rcoll.outfd, 0, 0, 0, 0, 0, 0, 0); } if (0 != res) fprintf(stderr, "Unable to synchronize cache\n"); } } status = pthread_cancel(sig_listen_thread_id); if (0 != status) err_exit(status, "pthread_cancel"); if (STDIN_FILENO != rcoll.infd) close(rcoll.infd); if ((STDOUT_FILENO != rcoll.outfd) && (FT_DEV_NULL != rcoll.out_type)) close(rcoll.outfd); res = exit_status; if (0 != rcoll.out_count) { fprintf(stderr, ">>>> Some error occurred, remaining blocks=%" PRId64 "\n", rcoll.out_count); if (0 == res) res = SG_LIB_CAT_OTHER; } print_stats(""); if (rcoll.dio_incomplete) { int fd; char c; fprintf(stderr, ">> Direct IO requested but incomplete %d times\n", rcoll.dio_incomplete); if ((fd = open(proc_allow_dio, O_RDONLY)) >= 0) { if (1 == read(fd, &c, 1)) { if ('0' == c) fprintf(stderr, ">>> %s set to '0' but should be set " "to '1' for direct IO\n", proc_allow_dio); } close(fd); } } if (rcoll.sum_of_resids) fprintf(stderr, ">> Non-zero sum of residual counts=%d\n", rcoll.sum_of_resids); return (res >= 0) ? res : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_wr_mode.c0000664000175000017500000004735712336421514015451 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * This program writes the given mode page contents to the corresponding * mode page on the given device. */ static const char * version_str = "1.14 20140518"; #define ME "sg_wr_mode: " #define MX_ALLOC_LEN 2048 #define SHORT_ALLOC_LEN 252 #define EBUFF_SZ 256 static struct option long_options[] = { {"contents", 1, 0, 'c'}, {"dbd", 0, 0, 'd'}, {"force", 0, 0, 'f'}, {"help", 0, 0, 'h'}, {"len", 1, 0, 'l'}, {"mask", 1, 0, 'm'}, {"page", 1, 0, 'p'}, {"save", 0, 0, 's'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_wr_mode [--contents=H,H...] [--dbd] [--force] [--help]\n" " [--len=10|6] [--mask=M,M...] " "[--page=PG[,SPG]] [--save]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --contents=H,H... | -c H,H... comma separated string " "of hex numbers\n" " that is mode page contents " "to write\n" " --contents=- | -c - read stdin for mode page contents" " to write\n" " --dbd | -d disable block descriptors (DBD bit" " in cdb)\n" " --force | -f force the contents to be written\n" " --help | -h print out usage message\n" " --len=10|6 | -l 10|6 use 10 byte (def) or 6 byte " "variants of\n" " SCSI MODE SENSE/SELECT commands\n" " --mask=M,M... | -m M,M... comma separated " "string of hex\n" " numbers that mask contents" " to write\n" " --page=PG | -p PG page_code to be written (in hex)\n" " --page=PG,SPG | -p PG,SPG page and subpage code to " "be\n" " written (in hex)\n" " --save | -s set 'save page' (SP) bit; default " "don't so\n" " only 'current' values changed\n" " --verbose | -v increase verbosity\n" " --version | -V print version string and exit\n\n" "writes given mode page with SCSI MODE SELECT (10 or 6) " "command\n" ); } /* Read hex numbers from command line or stdin. On the command line can * either be comma or space separated list. Space separated list need to be * quoted. For stdin (indicated by *inp=='-') there should be either * one entry per line, a comma separated list or space separated list. * Returns 0 if ok, or 1 if error. */ static int build_mode_page(const char * inp, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int in_len, k, j, m; unsigned int h; const char * lcp; char * cp; char * c2p; if ((NULL == inp) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *mp_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ char line[512]; char carry_over[4]; int off = 0; int split_line; carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), stdin)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { fprintf(stderr, "build_mode_page: carry_over error " "['%s'] around line %d\n", carry_over, j + 1); return 1; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { fprintf(stderr, "build_mode_page: syntax error at " "line %d, pos %d\n", j + 1, m + k + 1); return 1; } for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "build_mode_page: hex number " "larger than 0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { fprintf(stderr, "build_mode_page: array length " "exceeded\n"); return 1; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } fprintf(stderr, "build_mode_page: error in " "line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); return 1; } } off += (k + 1); } *mp_arr_len = off; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { fprintf(stderr, "build_mode_page: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "build_mode_page: hex number larger " "than 0xff at pos %d\n", (int)(lcp - inp + 1)); return 1; } mp_arr[k] = h; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { fprintf(stderr, "build_mode_page: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *mp_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_mode_page: array length exceeded\n"); return 1; } } return 0; } /* Read hex numbers from command line (comma separated list). * Can also be (single) space separated list but needs to be quoted on the * command line. Returns 0 if ok, or 1 if error. */ static int build_mask(const char * inp, unsigned char * mask_arr, int * mask_arr_len, int max_arr_len) { int in_len, k; unsigned int h; const char * lcp; char * cp; char * c2p; if ((NULL == inp) || (NULL == mask_arr) || (NULL == mask_arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) *mask_arr_len = 0; if ('-' == inp[0]) { /* read from stdin */ fprintf(stderr, "'--mask' does not accept input from stdin\n"); return 1; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { fprintf(stderr, "build_mode_page: error at pos %d\n", k + 1); return 1; } for (k = 0; k < max_arr_len; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { fprintf(stderr, "build_mode_page: hex number larger " "than 0xff at pos %d\n", (int)(lcp - inp + 1)); return 1; } mask_arr[k] = h; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { fprintf(stderr, "build_mode_page: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *mask_arr_len = k + 1; if (k == max_arr_len) { fprintf(stderr, "build_mode_page: array length exceeded\n"); return 1; } } return 0; } int main(int argc, char * argv[]) { int sg_fd, res, c, num, alloc_len, off, pdt; int k, md_len, hdr_len, bd_len, mask_in_len; unsigned u, uu; int dbd = 0; int got_contents = 0; int force = 0; int got_mask = 0; int mode_6 = 0; int pg_code = -1; int sub_pg_code = 0; int save = 0; int verbose = 0; int read_in_len = 0; const char * device_name = NULL; unsigned char read_in[MX_ALLOC_LEN]; unsigned char mask_in[MX_ALLOC_LEN]; unsigned char ref_md[MX_ALLOC_LEN]; char ebuff[EBUFF_SZ]; char b[80]; struct sg_simple_inquiry_resp inq_data; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:dfhl:m:p:svV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': memset(read_in, 0, sizeof(read_in)); if (0 != build_mode_page(optarg, read_in, &read_in_len, sizeof(read_in))) { fprintf(stderr, "bad argument to '--contents'\n"); return SG_LIB_SYNTAX_ERROR; } got_contents = 1; break; case 'd': dbd = 1; break; case 'f': force = 1; break; case 'h': case '?': usage(); return 0; case 'l': num = sscanf(optarg, "%d", &res); if ((1 == num) && ((6 == res) || (10 == res))) mode_6 = (6 == res) ? 1 : 0; else { fprintf(stderr, "length (of cdb) must be 6 or 10\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'm': memset(mask_in, 0xff, sizeof(mask_in)); if (0 != build_mask(optarg, mask_in, &mask_in_len, sizeof(mask_in))) { fprintf(stderr, "bad argument to '--mask'\n"); return SG_LIB_SYNTAX_ERROR; } got_mask = 1; break; case 'p': if (NULL == strchr(optarg, ',')) { num = sscanf(optarg, "%x", &u); if ((1 != num) || (u > 62)) { fprintf(stderr, "Bad page code value after '--page' " "switch\n"); return SG_LIB_SYNTAX_ERROR; } pg_code = u; } else if (2 == sscanf(optarg, "%x,%x", &u, &uu)) { if (uu > 254) { fprintf(stderr, "Bad sub page code value after '--page'" " switch\n"); return SG_LIB_SYNTAX_ERROR; } pg_code = u; sub_pg_code = uu; } else { fprintf(stderr, "Bad page code, subpage code sequence after " "'--page' switch\n"); return SG_LIB_SYNTAX_ERROR; } break; case 's': save = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (pg_code < 0) { fprintf(stderr, "need page code (see '--page=')\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (got_mask && force) { fprintf(stderr, "cannot use both '--force' and '--mask'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == sg_simple_inquiry(sg_fd, &inq_data, 0, verbose)) pdt = inq_data.peripheral_type; else pdt = 0x1f; /* do MODE SENSE to fetch current values */ memset(ref_md, 0, MX_ALLOC_LEN); alloc_len = mode_6 ? SHORT_ALLOC_LEN : MX_ALLOC_LEN; if (mode_6) res = sg_ll_mode_sense6(sg_fd, dbd, 0 /*current */, pg_code, sub_pg_code, ref_md, alloc_len, 1, verbose); else res = sg_ll_mode_sense10(sg_fd, 0 /* llbaa */, dbd, 0 /* current */, pg_code, sub_pg_code, ref_md, alloc_len, 1, verbose); ret = res; if (res) { if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "MODE SENSE (%d) not supported, try '--len=%d'\n", (mode_6 ? 6 : 10), (mode_6 ? 10 : 6)); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "MODE SENSE (%d): %s\n", (mode_6 ? 6 : 10), b); } goto err_out; } off = sg_mode_page_offset(ref_md, alloc_len, mode_6, ebuff, EBUFF_SZ); if (off < 0) { fprintf(stderr, "MODE SENSE (%d): %s\n", (mode_6 ? 6 : 10), ebuff); goto err_out; } if (mode_6) { hdr_len = 4; md_len = ref_md[0] + 1; bd_len = ref_md[3]; } else { hdr_len = 8; md_len = (ref_md[0] << 8) + ref_md[1] + 2; bd_len = (ref_md[6] << 8) + ref_md[7]; } if (got_contents) { if (read_in_len < 2) { fprintf(stderr, "contents length=%d too short\n", read_in_len); goto err_out; } ref_md[0] = 0; /* mode data length reserved for mode select */ if (! mode_6) ref_md[1] = 0; /* mode data length reserved for mode select */ if (0 == pdt) /* for disks mask out DPOFUA bit */ ref_md[mode_6 ? 2 : 3] &= 0xef; if (md_len > alloc_len) { fprintf(stderr, "mode data length=%d exceeds allocation " "length=%d\n", md_len, alloc_len); goto err_out; } if (got_mask) { for (k = 0; k < (md_len - off); ++k) { if ((0x0 == mask_in[k]) || (k > read_in_len)) read_in[k] = ref_md[off + k]; else if (mask_in[k] < 0xff) { c = (ref_md[off + k] & (0xff & ~mask_in[k])); read_in[k] = (c | (read_in[k] & mask_in[k])); } } read_in_len = md_len - off; } if (! force) { if ((! (ref_md[off] & 0x80)) && save) { fprintf(stderr, "PS bit in existing mode page indicates that " "it is not saveable\n but '--save' option given\n"); goto err_out; } read_in[0] &= 0x7f; /* mask out PS bit, reserved in mode select */ if ((md_len - off) != read_in_len) { fprintf(stderr, "contents length=%d but reference mode page " "length=%d\n", read_in_len, md_len - off); goto err_out; } if (pg_code != (read_in[0] & 0x3f)) { fprintf(stderr, "contents page_code=0x%x but reference " "page_code=0x%x\n", (read_in[0] & 0x3f), pg_code); goto err_out; } if ((read_in[0] & 0x40) != (ref_md[off] & 0x40)) { fprintf(stderr, "contents flags subpage but reference page" "does not (or vice versa)\n"); goto err_out; } if ((read_in[0] & 0x40) && (read_in[1] != sub_pg_code)) { fprintf(stderr, "contents subpage_code=0x%x but reference " "sub_page_code=0x%x\n", read_in[1], sub_pg_code); goto err_out; } } else md_len = off + read_in_len; /* force length */ memcpy(ref_md + off, read_in, read_in_len); if (mode_6) res = sg_ll_mode_select6(sg_fd, 1 /* PF */, save, ref_md, md_len, 1, verbose); else res = sg_ll_mode_select10(sg_fd, 1 /* PF */, save, ref_md, md_len, 1, verbose); ret = res; if (res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "MODE SELECT (%d): %s\n", (mode_6 ? 6 : 10), b); goto err_out; } } else { printf(">>> No contents given, so show current mode page data:\n"); printf(" header:\n"); dStrHex((const char *)ref_md, hdr_len, -1); if (bd_len) { printf(" block descriptor(s):\n"); dStrHex((const char *)(ref_md + hdr_len), bd_len, -1); } else printf(" << no block descriptors >>\n"); printf(" mode page:\n"); dStrHex((const char *)(ref_md + off), md_len - off, -1); } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_inq.c0000664000175000017500000042613712430315266014602 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2000-2014 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. This program outputs information provided by a SCSI INQUIRY command. It is mainly based on the SCSI SPC-4 document at http://www.t10.org . Acknowledgment: - Martin Schwenke added the raw switch and other improvements [20020814] - Lars Marowsky-Bree contributed Unit Path Report VPD page decoding for EMC CLARiiON devices [20041016] */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SG_LIB_LINUX #include #include #include #include #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" static const char * version_str = "1.43 20141107"; /* SPC-4 rev 37 */ /* INQUIRY notes: * It is recommended that the initial allocation length given to a * standard INQUIRY is 36 (bytes), especially if this is the first * SCSI command sent to a logical unit. This is compliant with SCSI-2 * and another major operating system. There are devices out there * that use one of the SCSI commands sets and lock up if they receive * an allocation length other than 36. This technique is sometimes * referred to as a "36 byte INQUIRY". * * A "standard" INQUIRY is one that has the EVPD and the CmdDt bits * clear. * * When doing device discovery on a SCSI transport (e.g. bus scanning) * the first SCSI command sent to a device should be a standard (36 * byte) INQUIRY. * * The allocation length field in the INQUIRY command was changed * from 1 to 2 bytes in SPC-3, revision 9, 17 September 2002. * Be careful using allocation lengths greater than 252 bytes, especially * if the lower byte is 0x0 (e.g. a 512 byte allocation length may * not be a good arbitrary choice (as 512 == 0x200) ). * * From SPC-3 revision 16 the CmdDt bit in an INQUIRY is obsolete. There * is now a REPORT SUPPORTED OPERATION CODES command that yields similar * information [MAINTENANCE IN, service action = 0xc]; see sg_opcodes. */ /* Following VPD pages are in ascending page number order */ #define VPD_SUPPORTED_VPDS 0x0 #define VPD_UNIT_SERIAL_NUM 0x80 #define VPD_DEVICE_ID 0x83 #define VPD_SOFTW_INF_ID 0x84 #define VPD_MAN_NET_ADDR 0x85 #define VPD_EXT_INQ 0x86 #define VPD_MODE_PG_POLICY 0x87 #define VPD_SCSI_PORTS 0x88 #define VPD_ATA_INFO 0x89 #define VPD_POWER_CONDITION 0x8a #define VPD_DEVICE_CONSTITUENTS 0x8b #define VPD_CFA_PROFILE_INFO 0x8c #define VPD_POWER_CONSUMPTION 0x8d #define VPD_3PARTY_COPY 0x8f #define VPD_PROTO_LU 0x90 #define VPD_PROTO_PORT 0x91 #define VPD_BLOCK_LIMITS 0xb0 #define VPD_BLOCK_DEV_CHARS 0xb1 #define VPD_MAN_ASS_SN 0xb1 #define VPD_LB_PROVISIONING 0xb2 #define VPD_REFERRALS 0xb3 #define VPD_UPR_EMC 0xc0 #define VPD_RDAC_VERS 0xc2 #define VPD_RDAC_VAC 0xc9 /* values for selection one or more associations (2**vpd_assoc), except _AS_IS */ #define VPD_DI_SEL_LU 1 #define VPD_DI_SEL_TPORT 2 #define VPD_DI_SEL_TARGET 4 #define VPD_DI_SEL_AS_IS 32 #define DEF_ALLOC_LEN 252 #define SAFE_STD_INQ_RESP_LEN 36 #define MX_ALLOC_LEN (0xc000 + 0x80) #define VPD_ATA_INFO_LEN 572 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define INQUIRY_CMD 0x12 #define INQUIRY_CMDLEN 6 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ static unsigned char rsp_buff[MX_ALLOC_LEN + 1]; static char xtra_buff[MX_ALLOC_LEN + 1]; static char usn_buff[MX_ALLOC_LEN + 1]; static const char * find_version_descriptor_str(int value); static void decode_dev_ids(const char * leadin, unsigned char * buff, int len, int do_hex); static void decode_transport_id(const char * leadin, unsigned char * ucp, int len); #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) static int try_ata_identify(int ata_fd, int do_hex, int do_raw, int do_verbose); #endif /* This structure is a duplicate of one of the same name in sg_vpd_vendor.c . Take care that both have the same fields (and types). */ struct svpd_values_name_t { int value; int subvalue; int pdt; /* peripheral device type id, -1 is the default */ /* (all or not applicable) value */ int vendor; /* vendor flag */ const char * acron; const char * name; }; static struct svpd_values_name_t vpd_pg[] = { {VPD_ATA_INFO, 0, -1, 0, "ai", "ATA information (SAT)"}, {VPD_BLOCK_DEV_CHARS, 0, 0, 0, "bdc", "Block device characteristics (SBC)"}, {VPD_BLOCK_LIMITS, 0, 0, 0, "bl", "Block limits (SBC)"}, {VPD_DEVICE_ID, 0, -1, 0, "di", "Device identification"}, #if 0 {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, 0, "di_asis", "Like 'di' " "but designators ordered as found"}, {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, 0, "di_lu", "Device identification, " "lu only"}, {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, 0, "di_port", "Device " "identification, target port only"}, {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, 0, "di_target", "Device " "identification, target device only"}, #endif {VPD_EXT_INQ, 0, -1, 0, "ei", "Extended inquiry data"}, {VPD_LB_PROVISIONING, 0, 0, 0, "lbpv", "Logical block provisioning " "(SBC)"}, {VPD_MAN_NET_ADDR, 0, -1, 0, "mna", "Management network addresses"}, {VPD_MODE_PG_POLICY, 0, -1, 0, "mpp", "Mode page policy"}, {VPD_POWER_CONDITION, 0, -1, 0, "po", "Power condition"}, {VPD_POWER_CONSUMPTION, 0, -1, 0, "psm", "Power consumption"}, {VPD_PROTO_LU, 0, 0x0, 0, "pslu", "Protocol-specific logical unit " "information"}, {VPD_PROTO_PORT, 0, 0x0, 0, "pspo", "Protocol-specific port information"}, {VPD_REFERRALS, 0, 0, 0, "ref", "Referrals (SBC)"}, {VPD_SOFTW_INF_ID, 0, -1, 0, "sii", "Software interface identification"}, {VPD_UNIT_SERIAL_NUM, 0, -1, 0, "sn", "Unit serial number"}, {VPD_SCSI_PORTS, 0, -1, 0, "sp", "SCSI ports"}, {VPD_SUPPORTED_VPDS, 0, -1, 0, "sv", "Supported VPD pages"}, {VPD_3PARTY_COPY, 0, -1, 0, "tpc", "Third party copy"}, /* Following are vendor specific */ {VPD_RDAC_VAC, 0, -1, 1, "rdac_vac", "RDAC volume access control (RDAC)"}, {VPD_RDAC_VERS, 0, -1, 1, "rdac_vers", "RDAC software version (RDAC)"}, {VPD_UPR_EMC, 0, -1, 1, "upr", "Unit path report (EMC)"}, {0, 0, 0, 0, NULL, NULL}, }; static struct option long_options[] = { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) {"ata", no_argument, 0, 'a'}, #endif {"block", required_argument, 0, 'B'}, {"cmddt", no_argument, 0, 'c'}, {"descriptors", no_argument, 0, 'd'}, {"export", no_argument, 0, 'u'}, {"extended", no_argument, 0, 'x'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"id", no_argument, 0, 'i'}, {"inhex", required_argument, 0, 'I'}, {"len", required_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, #ifdef SG_SCSI_STRINGS {"new", no_argument, 0, 'N'}, {"old", no_argument, 0, 'O'}, #endif {"page", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"vendor", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"vpd", no_argument, 0, 'e'}, {0, 0, 0, 0}, }; struct opts_t { int do_ata; int do_block; int do_cmddt; int do_descriptors; int do_export; int do_help; int do_hex; int do_raw; int do_vendor; int do_verbose; int do_version; int do_decode; int do_vpd; int resp_len; int page_num; int page_pdt; int num_pages; int num_opcodes; int p_given; const char * page_arg; const char * device_name; const char * inhex_fn; #ifdef SG_SCSI_STRINGS int opt_new; #endif }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) pr2serr("Usage: sg_inq [--ata] [--block=0|1] [--cmddt] [--descriptors] " "[--export]\n" " [--extended] [--help] [--hex] [--id] [--inhex=FN] " "[--len=LEN]\n" " [--maxlen=LEN] [--page=PG] [--raw] [--vendor] " "[--verbose]\n" " [--version] [--vpd] DEVICE\n" " where:\n" " --ata|-a treat DEVICE as (directly attached) ATA " "device\n"); #else pr2serr("Usage: sg_inq [--block=0|1] [--cmddt] [--descriptors] " "[--export]\n" " [--extended] [--help] [--hex] [--id] [--inhex=FN] " "[--len=LEN]\n" " [--maxlen=LEN] [--page=PG] [--raw] [--verbose] " "[--version]\n" " [--vpd] DEVICE\n" " where:\n"); #endif pr2serr(" --block=0|1 0-> open(non-blocking); 1-> " "open(blocking)\n" " -B 0|1 (def: depends on OS; Linux pt: 0)\n" " --cmddt|-c command support data mode (set opcode " "with '--page=PG')\n" " use twice for list of supported " "commands; obsolete\n" " --descriptors|-d fetch and decode version descriptors\n" " --export|-u SCSI_IDENT__= output " "format.\n" " Defaults to device id page (0x83) if --page " "not given,\n" " only supported for VPD pages 0x80 and 0x83\n" " --extended|-E|-x decode extended INQUIRY data VPD page " "(0x86)\n" " --help|-h print usage message then exit\n" " --hex|-H output response in hex\n" " --id|-i decode device identification VPD page " "(0x83)\n" " --inhex=FN|-I FN read ASCII hex from file FN instead of " "DEVICE;\n" " if used with --raw then read binary " "from FN\n" " --len=LEN|-l LEN requested response length (def: 0 " "-> fetch 36\n" " bytes first, then fetch again as " "indicated)\n" " --maxlen=LEN|-m LEN same as '--len='\n" " --page=PG|-p PG Vital Product Data (VPD) page number " "or\n" " abbreviation (opcode number if " "'--cmddt' given)\n" " --raw|-r output response in binary (to stdout)\n" " --vendor|-s show vendor specific fields in std " "inquiry\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --vpd|-e vital product data (set page with " "'--page=PG')\n\n" "Performs a SCSI INQUIRY command on DEVICE or decodes INQUIRY " "response\nheld in file FN. If no options given then does a " "'standard' INQUIRY.\nCan list VPD pages with '--vpd' or " "'--page=PG' option. sg_vpd and\nsdparm decode more VPD pages " "than this utility.\n"); } #ifdef SG_SCSI_STRINGS static void usage_old() { #ifdef SG_LIB_LINUX pr2serr("Usage: sg_inq [-a] [-A] [-b] [-B=0|1] [-c] [-cl] [-d] [-e] " "[-h]\n" " [-H] [-i] [I=FN] [-l=LEN] [-m] [-M] " "[-o=OPCODE_PG]\n" " [-p=VPD_PG] [-P] [-r] [-s] [-u] [-U] [-v] [-V] " "[-x]\n" " [-36] [-?] DEVICE\n" " where:\n" " -a decode ATA information VPD page (0x89)\n" " -A treat as (directly attached) ATA device\n"); #else pr2serr("Usage: sg_inq [-a] [-b] [-B 0|1] [-c] [-cl] [-d] [-e] [-h] " "[-H]\n" " [-i] [-l=LEN] [-m] [-M] [-o=OPCODE_PG] " "[-p=VPD_PG]\n" " [-P] [-r] [-s] [-u] [-v] [-V] [-x] [-36] " "[-?]\n" " DEVICE\n" " where:\n" " -a decode ATA information VPD page (0x89)\n"); #endif /* SG_LIB_LINUX */ pr2serr(" -b decode Block limits VPD page (0xb0) (SBC)\n" " -B=0|1 0-> open(non-blocking); 1->open(blocking)\n" " -c set CmdDt mode (use -o for opcode) [obsolete]\n" " -cl list supported commands using CmdDt mode [obsolete]\n" " -d decode: version descriptors or VPD page\n" " -e set VPD mode (use -p for page code)\n" " -h output in hex (ASCII to the right)\n" " -H output in hex (ASCII to the right) [same as '-h']\n" " -i decode device identification VPD page (0x83)\n" " -I=FN use ASCII hex in file FN instead of DEVICE\n" " -l=LEN requested response length (def: 0 " "-> fetch 36\n" " bytes first, then fetch again as " "indicated)\n" " -m decode management network addresses VPD page " "(0x85)\n" " -M decode mode page policy VPD page (0x87)\n" " -o=OPCODE_PG opcode or page code in hex (def: 0)\n" " -p=VPD_PG vpd page code in hex (def: 0)\n" " -P decode Unit Path Report VPD page (0xc0) (EMC)\n" " -r output response in binary ('-rr': output for hdparm)\n" " -s decode SCSI Ports VPD page (0x88)\n" " -u SCSI_IDENT__= output format\n" " -v verbose (output cdb and, if non-zero, resid)\n" " -V output version string\n" " -x decode extended INQUIRY data VPD page (0x86)\n" " -36 perform standard INQUIRY with a 36 byte response\n" " -? output this usage message\n\n" "If no options given then does a standard SCSI INQUIRY\n"); } static void usage_for(const struct opts_t * op) { if (op->opt_new) usage(); else usage_old(); } #else /* SG_SCSI_STRINGS */ static void usage_for(const struct opts_t * op) { op = op; usage(); } #endif /* SG_SCSI_STRINGS */ /* Processes command line options according to new option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int cl_new_process(struct opts_t * op, int argc, char * argv[]) { int c, n; while (1) { int option_index = 0; #ifdef SG_LIB_LINUX #ifdef SG_SCSI_STRINGS c = getopt_long(argc, argv, "aB:cdeEhHiI:l:m:NOp:rsuvVx", long_options, &option_index); #else c = getopt_long(argc, argv, "B:cdeEhHiI:l:m:p:rsuvVx", long_options, &option_index); #endif /* SG_SCSI_STRINGS */ #else /* SG_LIB_LINUX */ #ifdef SG_SCSI_STRINGS c = getopt_long(argc, argv, "B:cdeEhHiI:l:m:NOp:rsuvVx", long_options, &option_index); #else c = getopt_long(argc, argv, "B:cdeEhHiI:l:m:p:rsuvVx", long_options, &option_index); #endif /* SG_SCSI_STRINGS */ #endif /* SG_LIB_LINUX */ if (c == -1) break; switch (c) { #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) case 'a': ++op->do_ata; break; #endif case 'B': if ('-' == optarg[0]) n = -1; else { n = sg_get_num(optarg); if ((n < 0) || (n > 1)) { pr2serr("bad argument to '--block=' want 0 or 1\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } } op->do_block = n; break; case 'c': ++op->do_cmddt; break; case 'd': ++op->do_descriptors; break; case 'e': ++op->do_vpd; break; case 'E': case 'x': ++op->do_decode; ++op->do_vpd; op->page_num = VPD_EXT_INQ; break; case 'h': ++op->do_help; break; case '?': if (! op->do_help) ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': ++op->do_decode; ++op->do_vpd; op->page_num = VPD_DEVICE_ID; break; case 'I': op->inhex_fn = optarg; break; case 'l': case 'm': n = sg_get_num(optarg); if ((n < 0) || (n > 65532)) { pr2serr("bad argument to '--len='\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } op->resp_len = n; break; #ifdef SG_SCSI_STRINGS case 'N': break; /* ignore */ case 'O': op->opt_new = 0; return 0; #endif case 'p': op->page_arg = optarg; ++op->p_given; break; case 'r': ++op->do_raw; break; case 's': ++op->do_vendor; break; case 'u': ++op->do_export; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; default: pr2serr("unrecognised option code %c [0x%x]\n", c, c); if (op->do_help) break; usage_for(op); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage_for(op); return SG_LIB_SYNTAX_ERROR; } } return 0; } #ifdef SG_SCSI_STRINGS /* Processes command line options according to old option format. Returns * 0 is ok, else SG_LIB_SYNTAX_ERROR is returned. */ static int cl_old_process(struct opts_t * op, int argc, char * argv[]) { int k, jmp_out, plen, num, n; 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 '3': if ('6' == *(cp + 1)) { op->resp_len = 36; --plen; ++cp; } else jmp_out = 1; break; case 'a': op->page_num = VPD_ATA_INFO; ++op->do_vpd; ++op->num_pages; break; #ifdef SG_LIB_LINUX case 'A': ++op->do_ata; break; #endif case 'b': op->page_num = VPD_BLOCK_LIMITS; ++op->do_vpd; ++op->num_pages; break; case 'c': ++op->do_cmddt; if ('l' == *(cp + 1)) { ++op->do_cmddt; --plen; ++cp; } break; case 'd': ++op->do_descriptors; ++op->do_decode; break; case 'e': ++op->do_vpd; break; case 'h': case 'H': ++op->do_hex; break; case 'i': op->page_num = VPD_DEVICE_ID; ++op->do_vpd; ++op->num_pages; break; case 'm': op->page_num = VPD_MAN_NET_ADDR; ++op->do_vpd; ++op->num_pages; break; case 'M': op->page_num = VPD_MODE_PG_POLICY; ++op->do_vpd; ++op->num_pages; break; case 'N': op->opt_new = 1; return 0; case 'O': break; case 'P': op->page_num = VPD_UPR_EMC; ++op->do_vpd; ++op->num_pages; break; case 'r': ++op->do_raw; break; case 's': op->page_num = VPD_SCSI_PORTS; ++op->do_vpd; ++op->num_pages; break; case 'u': ++op->do_export; break; case 'v': ++op->do_verbose; break; case 'V': ++op->do_version; break; case 'x': op->page_num = VPD_EXT_INQ; ++op->do_vpd; ++op->num_pages; break; case '?': if (! op->do_help) ++op->do_help; break; default: jmp_out = 1; break; } if (jmp_out) break; } if (plen <= 0) continue; else if (0 == strncmp("B=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 0) || (n > 1)) { pr2serr("'B=' option expects 0 or 1\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } op->do_block = n; } else if (0 == strncmp("I=", cp, 2)) op->inhex_fn = cp + 2; else if (0 == strncmp("l=", cp, 2)) { num = sscanf(cp + 2, "%d", &n); if ((1 != num) || (n < 1)) { pr2serr("Inappropriate value after 'l=' option\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } else if (n > MX_ALLOC_LEN) { pr2serr("value after 'l=' option too large\n"); return SG_LIB_SYNTAX_ERROR; } op->resp_len = n; } else if (0 == strncmp("o=", cp, 2)) { op->page_arg = cp + 2; ++op->num_opcodes; } else if (0 == strncmp("p=", cp, 2)) { op->page_arg = cp + 2; ++op->p_given; } else if (0 == strncmp("-old", cp, 4)) ; else if (jmp_out) { pr2serr("Unrecognized option: %s\n", cp); usage_for(op); return SG_LIB_SYNTAX_ERROR; } } else if (0 == op->device_name) op->device_name = cp; else { pr2serr("too many arguments, got: %s, not expecting: %s\n", op->device_name, cp); usage_for(op); return SG_LIB_SYNTAX_ERROR; } } return 0; } /* Process command line options. First check using new option format unless * the SG3_UTILS_OLD_OPTS environment variable is defined which causes the * old option format to be checked first. Both new and old format can be * countermanded by a '-O' and '-N' options respectively. As soon as either * of these options is detected (when processing the other format), processing * stops and is restarted using the other format. Clear? */ static int cl_process(struct opts_t * op, int argc, char * argv[]) { int res; char * cp; cp = getenv("SG3_UTILS_OLD_OPTS"); if (cp) { op->opt_new = 0; res = cl_old_process(op, argc, argv); if ((0 == res) && op->opt_new) res = cl_new_process(op, argc, argv); } else { op->opt_new = 1; res = cl_new_process(op, argc, argv); if ((0 == res) && (0 == op->opt_new)) res = cl_old_process(op, argc, argv); } return res; } #else /* SG_SCSI_STRINGS */ static int cl_process(struct opts_t * op, int argc, char * argv[]) { return cl_new_process(op, argc, argv); } #endif /* SG_SCSI_STRINGS */ /* Read ASCII hex bytes or binary from fname (a file named '-' taken as * stdin). If reading ASCII hex then there should be either one entry per * line or a comma, space or tab separated list of bytes. If no_space is * set then a string of ACSII hex digits is expected, 2 per byte. Everything * from and including a '#' on a line is ignored. Returns 0 if ok, or 1 if * error. */ static int f2hex_arr(const char * fname, int as_binary, int no_space, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int fn_len, in_len, k, j, m, split_line, fd, has_stdin; unsigned int h; const char * lcp; FILE * fp; char line[512]; char carry_over[4]; int off = 0; if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; fn_len = strlen(fname); if (0 == fn_len) return 1; has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */ if (as_binary) { if (has_stdin) { fd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { fd = open(fname, O_RDONLY); if (fd < 0) { pr2serr("unable to open binary file %s: %s\n", fname, safe_strerror(errno)); return 1; } else if (sg_set_binary_mode(fd) < 0) perror("sg_set_binary_mode"); } k = read(fd, mp_arr, max_arr_len); if (k <= 0) { if (0 == k) pr2serr("read 0 bytes from binary file %s\n", fname); else pr2serr("read from binary file %s: %s\n", fname, safe_strerror(errno)); if (! has_stdin) close(fd); return 1; } *mp_arr_len = k; if (! has_stdin) close(fd); return 0; } else { /* So read the file as ASCII hex */ if (has_stdin) fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { pr2serr("Unable to open %s for reading\n", fname); return 1; } } } carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { pr2serr("f2hex_arr: carry_over error ['%s'] around line " "%d\n", carry_over, j + 1); goto bad; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("f2hex_arr: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto bad; } if (no_space) { for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1)); ++k, lcp += 2) { if (1 != sscanf(lcp, "%2x", &h)) { pr2serr("f2hex_arr: bad hex number in line %d, " "pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; off += k; } else { for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("f2hex_arr: hex number larger than " "0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("f2hex_arr: error in line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } } off += (k + 1); } } *mp_arr_len = off; if (stdin != fp) fclose(fp); return 0; bad: if (stdin != fp) fclose(fp); return 1; } /* Local version of sg_ll_inquiry() [found in libsgutils] that additionally * passes back resid. Same return values as sg_ll_inquiry() (0 is good). */ static int pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len, int * residp, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; unsigned char * up; struct sg_pt_base * ptvp; if (evpd) inqCmdBlk[1] |= 1; inqCmdBlk[2] = (unsigned char)pg_op; /* 16 bit allocation length (was 8) is a recent SPC-3 addition */ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); inqCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { pr2serr(" inquiry cdb: "); for (k = 0; k < INQUIRY_CMDLEN; ++k) pr2serr("%02x ", inqCmdBlk[k]); pr2serr("\n"); } if (resp && (mx_resp_len > 0)) { up = (unsigned char *)resp; up[0] = 0x7f; /* defensive prefill */ if (mx_resp_len > 4) up[4] = 0; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("inquiry: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else if (ret < 4) { if (verbose) pr2serr("inquiry: got too few bytes (%d)\n", ret); ret = SG_LIB_CAT_MALFORMED; } else ret = 0; if (resid > 0) { if (resid > mx_resp_len) { pr2serr("INQUIRY resid (%d) should never exceed requested " "len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } static const struct svpd_values_name_t * sdp_find_vpd_by_acron(const char * ap) { const struct svpd_values_name_t * vnp; for (vnp = vpd_pg; vnp->acron; ++vnp) { if (0 == strcmp(vnp->acron, ap)) return vnp; } return NULL; } static void enumerate_vpds() { const struct svpd_values_name_t * vnp; for (vnp = vpd_pg; vnp->acron; ++vnp) { if (vnp->name) printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value, vnp->name); } } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Strip initial and trailing whitespaces; convert one or repeated * whitespaces to a single "_"; convert non-printable characters to "." * and if there are no valid (i.e. printable) characters return 0. * Process 'str' in place (i.e. it's input and output) and return the * length of the output, excluding the trailing '\0'. */ static int encode_whitespaces(unsigned char *str, int inlen) { int k, res; int j = 0; int valid = 0; int outlen = inlen; /* Skip initial whitespaces */ while (isblank(str[j])) j++; k = j; /* Strip trailing whitespaces */ while ((outlen > k) && (isblank(str[outlen - 1]) || ('\0' == str[outlen - 1]))) { str[outlen - 1] = '\0'; outlen--; } for (res = 0; k < outlen; ++k) { if (isblank(str[k])) { if ((res > 0) && ('_' != str[res - 1])) { str[res++] = '_'; valid++; } } else if (! isprint(str[k])) str[res++] = '.'; else { str[res++] = str[k]; valid++; } } if (! valid) res = 0; if (res < inlen) str[res] = '\0'; return res; } static int encode_string(char *out, const unsigned char *in, int inlen) { int i, j = 0; for (i = 0; (i < inlen); ++i) { if (isblank(in[i]) || !isprint(in[i])) { sprintf(&out[j], "\\x%02x", in[i]); j += 4; } else { out[j] = in[i]; j++; } } out[j] = '\0'; return j; } struct vpd_name { int number; int peri_type; const char * name; }; /* In numerical order */ static struct vpd_name vpd_name_arr[] = { {VPD_SUPPORTED_VPDS, 0, "Supported VPD pages"}, /* 0x0 */ {VPD_UNIT_SERIAL_NUM, 0, "Unit serial number"}, /* 0x80 */ {0x81, 0, "Implemented operating definitions (obsolete)"}, {0x82, 0, "ASCII implemented operating definition (obsolete)"}, {VPD_DEVICE_ID, 0, "Device identification"}, {VPD_SOFTW_INF_ID, 0, "Software interface identification"}, {VPD_MAN_NET_ADDR, 0, "Management network addresses"}, {VPD_EXT_INQ, 0, "Extended INQUIRY data"}, {VPD_MODE_PG_POLICY, 0, "Mode page policy"}, {VPD_SCSI_PORTS, 0, "SCSI ports"}, {VPD_ATA_INFO, 0, "ATA information"}, {VPD_POWER_CONDITION, 0, "Power condition"}, {VPD_DEVICE_CONSTITUENTS, 0, "Device constituents"}, {VPD_CFA_PROFILE_INFO, 0, "CFA profile information"}, /* 0x8c */ {VPD_POWER_CONSUMPTION, 0, "Power consumption"}, /* 0x8d */ {VPD_3PARTY_COPY, 0, "Third party copy"}, /* 0x8f */ /* 0xb0 to 0xbf are per peripheral device type */ {VPD_BLOCK_LIMITS, 0, "Block limits (sbc2)"}, /* 0xb0 */ {VPD_BLOCK_DEV_CHARS, 0, "Block device characteristics (sbc3)"}, {VPD_LB_PROVISIONING, 0, "Logical block provisioning (sbc3)"}, {VPD_REFERRALS, 0, "Referrals (sbc3)"}, {0xb0, PDT_TAPE, "Sequential access device capabilities (ssc3)"}, {0xb2, PDT_TAPE, "TapeAlert supported flags (ssc3)"}, {0xb0, PDT_OSD, "OSD information (osd)"}, {0xb1, PDT_OSD, "Security token (osd)"}, /* 0xc0 to 0xff are vendor specific */ {0xc0, 0, "vendor: Firmware numbers (seagate); Unit path report (EMC)"}, {0xc1, 0, "vendor: Date code (seagate)"}, {0xc2, 0, "vendor: Jumper settings (seagate); Software version (RDAC)"}, {0xc3, 0, "vendor: Device behavior (seagate)"}, {0xc9, 0, "Volume Access Control (RDAC)"}, }; static const char * get_vpd_page_str(int vpd_page_num, int scsi_ptype) { int k; int vpd_name_arr_sz = (int)(sizeof(vpd_name_arr) / sizeof(vpd_name_arr[0])); if ((vpd_page_num >= 0xb0) && (vpd_page_num < 0xc0)) { /* peripheral device type relevant for 0xb0..0xbf range */ for (k = 0; k < vpd_name_arr_sz; ++k) { if ((vpd_name_arr[k].number == vpd_page_num) && (vpd_name_arr[k].peri_type == scsi_ptype)) break; } if (k < vpd_name_arr_sz) return vpd_name_arr[k].name; for (k = 0; k < vpd_name_arr_sz; ++k) { if ((vpd_name_arr[k].number == vpd_page_num) && (vpd_name_arr[k].peri_type == 0)) break; } if (k < vpd_name_arr_sz) return vpd_name_arr[k].name; else return NULL; } else { /* rest of 0x0..0xff range doesn't depend on peripheral type */ for (k = 0; k < vpd_name_arr_sz; ++k) { if (vpd_name_arr[k].number == vpd_page_num) break; } if (k < vpd_name_arr_sz) return vpd_name_arr[k].name; else return NULL; } } static void decode_supported_vpd(unsigned char * buff, int len, int do_hex) { int vpd, k, rlen, pdt; const char * cp; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } if (len < 4) { pr2serr("Supported VPD pages VPD page length too short=%d\n", len); return; } pdt = 0x1f & buff[0]; rlen = buff[3] + 4; if (rlen > len) pr2serr("Supported VPD pages VPD page truncated, indicates %d, got " "%d\n", rlen, len); else len = rlen; printf(" Supported VPD pages:\n"); for (k = 0; k < len - 4; ++k) { vpd = buff[4 + k]; cp = get_vpd_page_str(vpd, pdt); if (cp) printf(" 0x%x\t%s\n", vpd, cp); else printf(" 0x%x\n", vpd); } } /* ASCII Information VPD pages (page numbers: 0x1 to 0x7f) */ static void decode_ascii_inf(unsigned char * buff, int len, int do_hex) { int al, k, bump; unsigned char * ucp; unsigned char * p; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } if (len < 4) { pr2serr("ASCII information VPD page length too short=%d\n", len); return; } if (4 == len) return; al = buff[4]; if ((al + 5) > len) al = len - 5; for (k = 0, ucp = buff + 5; k < al; k += bump, ucp += bump) { p = (unsigned char *)memchr(ucp, 0, al - k); if (! p) { printf(" %.*s\n", al - k, (const char *)ucp); break; } printf(" %s\n", (const char *)ucp); bump = (p - ucp) + 1; } ucp = buff + 5 + al; if (ucp < (buff + len)) { printf("Vendor specific information in hex:\n"); dStrHex((const char *)ucp, len - (al + 5), 0); } } static void decode_id_vpd(unsigned char * buff, int len, int do_hex) { if (len < 4) { pr2serr("Device identification VPD page length too " "short=%d\n", len); return; } decode_dev_ids("Device identification", buff + 4, len - 4, do_hex); } static const char * assoc_arr[] = { "addressed logical unit", "target port", /* that received request; unless SCSI ports VPD */ "target device that contains addressed lu", "reserved [0x3]", }; static const char * network_service_type_arr[] = { "unspecified", "storage configuration service", "diagnostics", "status", "logging", "code download", "copy service", "administrative configuration service", "[0x8]", "[0x9]", "[0xa]", "[0xb]", "[0xc]", "[0xd]", "[0xe]", "[0xf]", "[0x10]", "[0x11]", "[0x12]", "[0x13]", "[0x14]", "[0x15]", "[0x16]", "[0x17]", "[0x18]", "[0x19]", "[0x1a]", "[0x1b]", "[0x1c]", "[0x1d]", "[0x1e]", "[0x1f]", }; /* VPD_MAN_NET_ADDR */ static void decode_net_man_vpd(unsigned char * buff, int len, int do_hex) { int k, bump, na_len; unsigned char * ucp; if (len < 4) { pr2serr("Management network addresses VPD page length too short=%d\n", len); return; } if (do_hex > 2) { dStrHex((const char *)buff, len, -1); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { printf(" %s, Service type: %s\n", assoc_arr[(ucp[0] >> 5) & 0x3], network_service_type_arr[ucp[0] & 0x1f]); na_len = (ucp[2] << 8) + ucp[3]; bump = 4 + na_len; if ((k + bump) > len) { pr2serr("Management network addresses VPD page, short " "descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (na_len > 0) { if (do_hex) { printf(" Network address:\n"); dStrHex((const char *)(ucp + 4), na_len, 0); } else printf(" %s\n", ucp + 4); } } } static const char * mode_page_policy_arr[] = { "shared", "per target port", "per initiator port", "per I_T nexus", }; /* VPD_MODE_PG_POLICY */ static void decode_mode_policy_vpd(unsigned char * buff, int len, int do_hex) { int k, bump; unsigned char * ucp; if (len < 4) { pr2serr("Mode page policy VPD page length too short=%d\n", len); return; } if (do_hex > 2) { dStrHex((const char *)buff, len, -1); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { bump = 4; if ((k + bump) > len) { pr2serr("Mode page policy VPD page, short " "descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (do_hex) dStrHex((const char *)ucp, 4, (1 == do_hex) ? 1 : -1); else { printf(" Policy page code: 0x%x", (ucp[0] & 0x3f)); if (ucp[1]) printf(", subpage code: 0x%x\n", ucp[1]); else printf("\n"); printf(" MLUS=%d, Policy: %s\n", !!(ucp[2] & 0x80), mode_page_policy_arr[ucp[2] & 0x3]); } } } /* VPD_SCSI_PORTS */ static void decode_scsi_ports_vpd(unsigned char * buff, int len, int do_hex) { int k, bump, rel_port, ip_tid_len, tpd_len; unsigned char * ucp; if (len < 4) { pr2serr("SCSI Ports VPD page length too short=%d\n", len); return; } if (do_hex > 2) { dStrHex((const char *)buff, len, -1); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { rel_port = (ucp[2] << 8) + ucp[3]; printf("Relative port=%d\n", rel_port); ip_tid_len = (ucp[6] << 8) + ucp[7]; bump = 8 + ip_tid_len; if ((k + bump) > len) { pr2serr("SCSI Ports VPD page, short descriptor " "length=%d, left=%d\n", bump, (len - k)); return; } if (ip_tid_len > 0) { if (do_hex) { printf(" Initiator port transport id:\n"); dStrHex((const char *)(ucp + 8), ip_tid_len, (1 == do_hex) ? 1 : -1); } else decode_transport_id(" ", ucp + 8, ip_tid_len); } tpd_len = (ucp[bump + 2] << 8) + ucp[bump + 3]; if ((k + bump + tpd_len + 4) > len) { pr2serr("SCSI Ports VPD page, short descriptor(tgt) " "length=%d, left=%d\n", bump, (len - k)); return; } if (tpd_len > 0) { printf(" Target port descriptor(s):\n"); if (do_hex) dStrHex((const char *)(ucp + bump + 4), tpd_len, (1 == do_hex) ? 1 : -1); else decode_dev_ids("SCSI Ports", ucp + bump + 4, tpd_len, do_hex); } bump += tpd_len + 4; } } static const char * code_set_arr[] = { "Reserved [0x0]", "Binary", "ASCII", "UTF-8", "[0x4]", "[0x5]", "[0x6]", "[0x7]", "[0x8]", "[0x9]", "[0xa]", "[0xb]", "[0xc]", "[0xd]", "[0xe]", "[0xf]", }; static const char * desig_type_arr[] = { "vendor specific [0x0]", /* SCSI_IDENT_DEVICE_VENDOR */ "T10 vendor identification", /* SCSI_IDENT_DEVICE_T10 */ "EUI-64 based", /* SCSI_IDENT_DEVICE_EUI64 */ "NAA", /* SCSI_IDENT_DEVICE_NAA */ "Relative target port", /* SCSI_IDENT_PORT_RELATIVE */ "Target port group", /* SCSI_IDENT_PORT_TP_GROUP */ "Logical unit group", /* SCSI_IDENT_PORT_LU_GROUP */ "MD5 logical unit identifier", /* SCSI_IDENT_DEVICE_MD5 */ "SCSI name string", /* SCSI_IDENT_DEVICE_SCSINAME */ "Protocol specific port identifier", /* spc4r36 */ "[0xa]", "[0xb]", "[0xc]", "[0xd]", "[0xe]", "[0xf]", }; /* These are target port, device server (i.e. target) and LU identifiers */ static void decode_dev_ids(const char * leadin, unsigned char * buff, int len, int do_hex) { int u, j, m, id_len, p_id, c_set, piv, assoc, desig_type, i_len; int off, ci_off, c_id, d_id, naa, vsi, k; uint64_t vsei; uint64_t id_ext; const unsigned char * ucp; const unsigned char * ip; char b[64]; if (buff[2] != 0) { /* * Reference the 3rd byte of the first Identification descriptor * of a page 83 reply to determine whether the reply is compliant * with SCSI-2 or SPC-2/3 specifications. A zero value in the * 3rd byte indicates an SPC-2/3 conformant reply ( the field is * reserved ). This byte will be non-zero for a SCSI-2 * conformant page 83 reply from these EMC Symmetrix models since * the 7th byte of the reply corresponds to the 4th and 5th * nibbles of the 6-byte OUI for EMC, that is, 0x006048. */ i_len = len; ip = ucp = buff; c_set = 1; assoc = 0; piv = 0; p_id = 0xf; desig_type = 3; j = 1; off = 16; printf(" Pre-SPC descriptor, descriptor length: %d\n", i_len); goto decode; } for (j = 1, off = -1; (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0; ++j) { ucp = buff + off; i_len = ucp[3]; id_len = i_len + 4; printf(" Designation descriptor number %d, " "descriptor length: %d\n", j, id_len); if ((off + id_len) > len) { pr2serr("%s VPD page error: designator length longer " "than\n remaining response length=%d\n", leadin, (len - off)); return; } ip = ucp + 4; p_id = ((ucp[0] >> 4) & 0xf); /* protocol identifier */ c_set = (ucp[0] & 0xf); /* code set */ piv = ((ucp[1] & 0x80) ? 1 : 0); /* protocol identifier valid */ assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); decode: if (piv && ((1 == assoc) || (2 == assoc))) printf(" transport: %s\n", sg_get_trans_proto_str(p_id, sizeof(b), b)); printf(" designator_type: %s, code_set: %s\n", desig_type_arr[desig_type], code_set_arr[c_set]); printf(" associated with the %s\n", assoc_arr[assoc]); if (do_hex) { printf(" designator header(hex): %.2x %.2x %.2x %.2x\n", ucp[0], ucp[1], ucp[2], ucp[3]); printf(" designator:\n"); dStrHex((const char *)ip, i_len, 0); continue; } switch (desig_type) { case 0: /* vendor specific */ k = 0; if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ for (k = 0; (k < i_len) && isprint(ip[k]); ++k) ; if (k >= i_len) k = 1; } if (k) printf(" vendor specific: %.*s\n", i_len, ip); else { printf(" vendor specific:\n"); dStrHex((const char *)ip, i_len, -1); } break; case 1: /* T10 vendor identification */ printf(" vendor id: %.8s\n", ip); if (i_len > 8) { if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ printf(" vendor specific: %.*s\n", i_len - 8, ip + 8); } else { printf(" vendor specific: 0x"); for (m = 8; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } } break; case 2: /* EUI-64 based */ printf(" EUI-64 based %d byte identifier\n", i_len); if (1 != c_set) { pr2serr(" << expected binary code_set (1)>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } ci_off = 0; if (16 == i_len) { ci_off = 8; id_ext = 0; for (m = 0; m < 8; ++m) { if (m > 0) id_ext <<= 8; id_ext |= ip[m]; } printf(" Identifier extension: 0x%" PRIx64 "\n", id_ext); } else if ((8 != i_len) && (12 != i_len)) { pr2serr(" << can only decode 8, 12 and 16 " "byte ids>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } c_id = ((ip[ci_off] << 16) | (ip[ci_off + 1] << 8) | ip[ci_off + 2]); printf(" IEEE Company_id: 0x%x\n", c_id); vsei = 0; for (m = 0; m < 5; ++m) { if (m > 0) vsei <<= 8; vsei |= ip[ci_off + 3 + m]; } printf(" Vendor Specific Extension Identifier: 0x%" PRIx64 "\n", vsei); if (12 == i_len) { d_id = ((ip[8] << 24) | (ip[9] << 16) | (ip[10] << 8) | ip[11]); printf(" Directory ID: 0x%x\n", d_id); } printf(" [0x"); for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); break; case 3: /* NAA */ naa = (ip[0] >> 4) & 0xff; if (1 != c_set) { pr2serr(" << expected binary code_set (1), got %d for " "NAA=%d>>\n", c_set, naa); dStrHexErr((const char *)ip, i_len, -1); break; } switch (naa) { case 2: /* NAA 2: IEEE Extended */ if (8 != i_len) { pr2serr(" << unexpected NAA 2 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, -1); break; } d_id = (((ip[0] & 0xf) << 8) | ip[1]); c_id = ((ip[2] << 16) | (ip[3] << 8) | ip[4]); vsi = ((ip[5] << 16) | (ip[6] << 8) | ip[7]); printf(" NAA 2, vendor specific identifier A: 0x%x\n", d_id); printf(" IEEE Company_id: 0x%x\n", c_id); printf(" vendor specific identifier B: 0x%x\n", vsi); printf(" [0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); break; case 3: /* NAA 3: Locally assigned */ if (8 != i_len) { pr2serr(" << unexpected NAA 3 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, -1); break; } printf(" NAA 3, Locally assigned:\n"); printf(" [0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); break; case 5: /* NAA 5: IEEE Registered */ if (8 != i_len) { pr2serr(" << unexpected NAA 5 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, -1); break; } c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); printf(" [0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); break; case 6: /* NAA 6: IEEE Registered extended */ if (16 != i_len) { pr2serr(" << unexpected NAA 6 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); vsei = 0; for (m = 0; m < 8; ++m) { if (m > 0) vsei <<= 8; vsei |= ip[8 + m]; } printf(" Vendor Specific Identifier Extension: " "0x%" PRIx64 "\n", vsei); printf(" [0x"); for (m = 0; m < 16; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); break; default: pr2serr(" << bad NAA nibble , expect 2, 3, 5 or 6, " "got %d>>\n", naa); dStrHexErr((const char *)ip, i_len, -1); break; } break; case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } d_id = ((ip[2] << 8) | ip[3]); printf(" Relative target port: 0x%x\n", d_id); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } d_id = ((ip[2] << 8) | ip[3]); printf(" Target port group: 0x%x\n", d_id); break; case 6: /* Logical unit group */ if ((1 != c_set) || (0 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, logical " "unit association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } d_id = ((ip[2] << 8) | ip[3]); printf(" Logical unit group: 0x%x\n", d_id); break; case 7: /* MD5 logical unit identifier */ if ((1 != c_set) || (0 != assoc)) { pr2serr(" << expected binary code_set, logical " "unit association>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } printf(" MD5 logical unit identifier:\n"); dStrHex((const char *)ip, i_len, -1); break; case 8: /* SCSI name string */ if (3 != c_set) { pr2serr(" << expected UTF-8 code_set>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } printf(" SCSI name string:\n"); /* does %s print out UTF-8 ok?? * Seems to depend on the locale. Looks ok here with my * locale setting: en_AU.UTF-8 */ printf(" %s\n", (const char *)ip); break; case 9: /* Protocol specific port identifier */ /* added in spc4r36, PIV must be set, proto_id indicates */ /* whether UAS (USB) or SOP (PCIe) or ... */ if (! piv) printf(" >>>> Protocol specific port identifier " "expects protocol\n" " identifier to be valid and it is not\n"); if (TPROTO_UAS == p_id) { printf(" USB device address: 0x%x\n", 0x7f & ip[0]); printf(" USB interface number: 0x%x\n", ip[2]); } else if (TPROTO_SOP == p_id) { printf(" PCIe routing ID, bus number: 0x%x\n", ip[0]); printf(" function number: 0x%x\n", ip[1]); printf(" [or device number: 0x%x, function number: " "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); } else printf(" >>>> unexpected protocol indentifier: %s\n" " with Protocol specific port " "identifier\n", sg_get_trans_proto_str(p_id, sizeof(b), b)); break; default: /* reserved */ pr2serr(" reserved designator=0x%x\n", desig_type); dStrHexErr((const char *)ip, i_len, -1); break; } } if (-2 == u) pr2serr("%s VPD page error: around offset=%d\n", leadin, off); } static void export_dev_ids(unsigned char * buff, int len, int verbose) { int u, j, m, id_len, c_set, assoc, desig_type, i_len; int off, d_id, naa, k, p_id; unsigned char * ucp; unsigned char * ip; const char * assoc_str; if (buff[2] != 0) { /* * Cf decode_dev_ids() for details */ i_len = len; ip = buff; c_set = 1; assoc = 0; p_id = 0xf; desig_type = 3; j = 1; off = 16; goto decode; } for (j = 1, off = -1; (u = sg_vpd_dev_id_iter(buff, len, &off, -1, -1, -1)) == 0; ++j) { ucp = buff + off; i_len = ucp[3]; id_len = i_len + 4; if ((off + id_len) > len) { if (verbose) pr2serr("Device Identification VPD page error: designator " "length longer than\n remaining response " "length=%d\n", (len - off)); return; } ip = ucp + 4; p_id = ((ucp[0] >> 4) & 0xf); /* protocol identifier */ c_set = (ucp[0] & 0xf); assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); decode: switch (assoc) { case 0: assoc_str = "LUN"; break; case 1: assoc_str = "PORT"; break; case 2: assoc_str = "TARGET"; break; default: if (verbose) pr2serr(" Invalid association %d\n", assoc); return; } switch (desig_type) { case 0: /* vendor specific */ if (i_len > 128) break; printf("SCSI_IDENT_%s_VENDOR=", assoc_str); if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ k = encode_whitespaces(ip, i_len); printf("%.*s\n", k, ip); } else { for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } break; case 1: /* T10 vendor identification */ printf("SCSI_IDENT_%s_T10=", assoc_str); if ((2 == c_set) || (3 == c_set)) { k = encode_whitespaces(ip, i_len); printf("%.*s\n", k, ip); if (!memcmp(ip, "ATA_", 4)) { printf("SCSI_IDENT_%s_ATA=%.*s\n", assoc_str, k - 4, ip + 4); } } else { for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } break; case 2: /* EUI-64 based */ if (1 != c_set) { if (verbose) { pr2serr(" << expected binary code_set (1)>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_EUI64=", assoc_str); for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; case 3: /* NAA */ if (1 != c_set) { if (verbose) { pr2serr(" << expected binary code_set (1)>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } naa = (ip[0] >> 4) & 0xff; if ((naa < 2) || (naa > 6) || (4 == naa)) { if (verbose) { pr2serr(" << unexpected naa [0x%x]>>\n", naa); dStrHexErr((const char *)ip, i_len, 0); } break; } if (6 != naa) { if (8 != i_len) { if (verbose) { pr2serr(" << unexpected NAA 2 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_NAA=", assoc_str); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } else { /* NAA IEEE Registered extended */ if (16 != i_len) { if (verbose) { pr2serr(" << unexpected NAA 6 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_NAA=", assoc_str); for (m = 0; m < 16; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } break; case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { if (verbose) { pr2serr(" << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } d_id = ((ip[2] << 8) | ip[3]); printf("SCSI_IDENT_%s_RELATIVE=%d\n", assoc_str, d_id); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { if (verbose) { pr2serr(" << expected binary code_set, target " "port association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } d_id = ((ip[2] << 8) | ip[3]); printf("SCSI_IDENT_%s_TARGET_PORT_GROUP=0x%x\n", assoc_str, d_id); break; case 6: /* Logical unit group */ if ((1 != c_set) || (0 != assoc) || (4 != i_len)) { if (verbose) { pr2serr(" << expected binary code_set, logical " "unit association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } d_id = ((ip[2] << 8) | ip[3]); printf("SCSI_IDENT_%s_LOGICAL_UNIT_GROUP=0x%x\n", assoc_str, d_id); break; case 7: /* MD5 logical unit identifier */ if ((1 != c_set) || (0 != assoc)) { if (verbose) { pr2serr(" << expected binary code_set, logical " "unit association>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_MD5=", assoc_str); dStrHex((const char *)ip, i_len, -1); break; case 8: /* SCSI name string */ if (3 != c_set) { if (verbose) { pr2serr(" << expected UTF-8 code_set>>\n"); dStrHexErr((const char *)ip, i_len, -1); } break; } if (strncmp((const char *)ip, "eui.", 4) || strncmp((const char *)ip, "naa.", 4) || strncmp((const char *)ip, "iqn.", 4)) { if (verbose) { pr2serr(" << expected name string prefix>>\n"); dStrHexErr((const char *)ip, i_len, -1); } break; } printf("SCSI_IDENT_%s_NAME=%.*s\n", assoc_str, i_len, (const char *)ip); break; case 9: /* Protocol specific port identifier */ if (TPROTO_UAS == p_id) { if ((4 != i_len) || (1 != assoc)) { if (verbose) { pr2serr(" << UAS (USB) expected target " "port association>>\n"); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_UAS_DEVICE_ADDRESS=0x%x\n", assoc_str, ip[0] & 0x7f); printf("SCSI_IDENT_%s_UAS_INTERFACE_NUMBER=0x%x\n", assoc_str, ip[2]); } else if (TPROTO_SOP == p_id) { if ((4 != i_len) && (8 != i_len)) { /* spc4r36h confused */ if (verbose) { pr2serr(" << SOP (PCIe) descriptor " "length=%d >>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); } break; } printf("SCSI_IDENT_%s_SOP_ROUTING_ID=0x%x\n", assoc_str, ((ip[0] << 8) | ip[1])); } else { pr2serr(" << Protocol specific port identifier " "protocol_id=0x%x>>\n", p_id); } break; default: /* reserved */ if (verbose) { pr2serr(" reserved designator=0x%x\n", desig_type); dStrHexErr((const char *)ip, i_len, -1); } break; } } if (-2 == u && verbose) pr2serr("Device identification VPD page error: " "around offset=%d\n", off); } /* Transport IDs are initiator port identifiers, typically other than the initiator port issuing a SCSI command. */ static void decode_transport_id(const char * leadin, unsigned char * ucp, int len) { int format_code, proto_id, num, j, k; uint64_t ull; int bump; for (k = 0, bump = 24; k < len; k += bump, ucp += bump) { if ((len < 24) || (0 != (len % 4))) printf("%sTransport Id short or not multiple of 4 " "[length=%d]:\n", leadin, len); else printf("%sTransport Id of initiator:\n", leadin); format_code = ((ucp[0] >> 6) & 0x3); proto_id = (ucp[0] & 0xf); switch (proto_id) { case TPROTO_FCP: printf("%s FCP-2 World Wide Name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); bump = 24; break; case TPROTO_SPI: printf("%s Parallel SCSI initiator SCSI address: 0x%x\n", leadin, ((ucp[2] << 8) | ucp[3])); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); printf("%s relative port number (of corresponding target): " "0x%x\n", leadin, ((ucp[6] << 8) | ucp[7])); bump = 24; break; case TPROTO_SSA: /* SSA */ printf("%s SSA (transport id not defined):\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); bump = 24; break; case TPROTO_1394: printf("%s IEEE 1394 EUI-64 name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); bump = 24; break; case TPROTO_SRP: printf("%s RDMA initiator port identifier:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 16, -1); bump = 24; break; case TPROTO_ISCSI: printf("%s iSCSI ", leadin); num = ((ucp[2] << 8) | ucp[3]); if (0 == format_code) printf("name: %.*s\n", num, &ucp[4]); else if (1 == format_code) printf("world wide unique port id: %.*s\n", num, &ucp[4]); else { printf(" [Unexpected format code: %d]\n", format_code); dStrHex((const char *)ucp, num + 4, -1); } bump = (((num + 4) < 24) ? 24 : num + 4); break; case TPROTO_SAS: ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[4 + j]; } printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); bump = 24; break; case TPROTO_ADT: printf("%s ADT:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); bump = 24; break; case TPROTO_ATA: printf("%s ATAPI:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); bump = 24; break; case TPROTO_UAS: printf("%s UAS:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); bump = 24; break; case TPROTO_SOP: printf("%s SOP ", leadin); num = ((ucp[2] << 8) | ucp[3]); if (0 == format_code) printf("Routing ID: 0x%x\n", num); else { printf(" [Unexpected format code: %d]\n", format_code); dStrHex((const char *)ucp, 24, -1); } bump = 24; break; case TPROTO_NONE: pr2serr("%s No specified protocol\n", leadin); /* dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0); */ bump = 24; break; default: pr2serr("%s unknown protocol id=0x%x " "format_code=%d\n", leadin, proto_id, format_code); dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; } } } /* VPD_EXT_INQ Extended Inquiry */ static void decode_x_inq_vpd(unsigned char * buff, int len, int do_hex) { if (len < 7) { pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } printf(" ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d " "REF_CHK=%d\n", ((buff[4] >> 6) & 0x3), ((buff[4] >> 3) & 0x7), !!(buff[4] & 0x4), !!(buff[4] & 0x2), !!(buff[4] & 0x1)); printf(" UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d " "SIMPSUP=%d\n", !!(buff[5] & 0x20), !!(buff[5] & 0x10), !!(buff[5] & 0x8), !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1)); printf(" WU_SUP=%d CRD_SUP=%d NV_SUP=%d V_SUP=%d\n", !!(buff[6] & 0x8), !!(buff[6] & 0x4), !!(buff[6] & 0x2), !!(buff[6] & 0x1)); printf(" P_I_I_SUP=%d LUICLR=%d R_SUP=%d CBCS=%d\n", !!(buff[7] & 0x10), !!(buff[7] & 0x1), !!(buff[8] & 0x10), !!(buff[8] & 0x1)); printf(" Multi I_T nexus microcode download=%d\n", buff[9] & 0xf); printf(" Extended self-test completion minutes=%d\n", (buff[10] << 8) + buff[11]); /* spc4r27 */ printf(" POA_SUP=%d HRA_SUP=%d VSA_SUP=%d\n", /* spc4r32 */ !!(buff[12] & 0x80), !!(buff[12] & 0x40), !!(buff[12] & 0x20)); printf(" Maximum supported sense data length=%d\n", buff[13]); /* spc4r34 */ } /* VPD_SOFTW_INF_ID */ static void decode_softw_inf_id(unsigned char * buff, int len, int do_hex) { if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } len -= 4; buff += 4; for ( ; len > 5; len -= 6, buff += 6) printf(" IEEE Company_id: 0x%06x, vendor specific extension " "id: 0x%06x\n", (buff[0] << 16) | (buff[1] << 8) | buff[2], (buff[3] << 16) | (buff[4] << 8) | buff[5]); } /* VPD_ATA_INFO */ static void decode_ata_info_vpd(unsigned char * buff, int len, int do_hex) { char b[80]; int is_be, num; if (len < 36) { pr2serr("ATA information VPD page length too short=%d\n", len); return; } if (do_hex && (2 != do_hex)) { dStrHex((const char *)buff, len, (3 == do_hex) ? 0 : -1); return; } memcpy(b, buff + 8, 8); b[8] = '\0'; printf(" SAT Vendor identification: %s\n", b); memcpy(b, buff + 16, 16); b[16] = '\0'; printf(" SAT Product identification: %s\n", b); memcpy(b, buff + 32, 4); b[4] = '\0'; printf(" SAT Product revision level: %s\n", b); if (len < 56) return; printf(" Signature (Device to host FIS):\n"); dStrHex((const char *)buff + 36, 20, 1); if (len < 60) return; is_be = sg_is_big_endian(); if ((0xec == buff[56]) || (0xa1 == buff[56])) { printf(" ATA command IDENTIFY %sDEVICE response summary:\n", ((0xa1 == buff[56]) ? "PACKET " : "")); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20, is_be, b); b[num] = '\0'; printf(" model: %s\n", b); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10, is_be, b); b[num] = '\0'; printf(" serial number: %s\n", b); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4, is_be, b); b[num] = '\0'; printf(" firmware revision: %s\n", b); printf(" response in hex:\n"); } else printf(" ATA command 0x%x got following response:\n", (unsigned int)buff[56]); if (len < 572) return; if (2 == do_hex) dStrHex((const char *)(buff + 60), 512, 0); else dWordHex((const unsigned short *)(buff + 60), 256, 0, sg_is_big_endian()); } /* VPD_POWER_CONDITION */ static void decode_power_condition(unsigned char * buff, int len, int do_hex) { if (len < 18) { pr2serr("Power condition VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } printf(" Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d Idle_a=%d\n", !!(buff[4] & 0x2), !!(buff[4] & 0x1), !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1)); printf(" Stopped condition recovery time (ms) %d\n", (buff[6] << 8) + buff[7]); printf(" Standby_z condition recovery time (ms) %d\n", (buff[8] << 8) + buff[9]); printf(" Standby_y condition recovery time (ms) %d\n", (buff[10] << 8) + buff[11]); printf(" Idle_a condition recovery time (ms) %d\n", (buff[12] << 8) + buff[13]); printf(" Idle_b condition recovery time (ms) %d\n", (buff[14] << 8) + buff[15]); printf(" Idle_c condition recovery time (ms) %d\n", (buff[16] << 8) + buff[17]); } /* VPD_BLOCK_LIMITS sbc */ /* Sequential access device characteristics, ssc+smc */ /* OSD information, osd */ static void decode_b0_vpd(unsigned char * buff, int len, int do_hex) { int pdt, m; unsigned int u; uint64_t mwsl; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } pdt = 0x1f & buff[0]; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: if (len < 16) { pr2serr("Block limits VPD page length too short=%d\n", len); return; } printf(" Maximum compare and write length: %u blocks\n", buff[5]); u = (buff[6] << 8) | buff[7]; printf(" Optimal transfer length granularity: %u blocks\n", u); u = (buff[8] << 24) | (buff[9] << 16) | (buff[10] << 8) | buff[11]; printf(" Maximum transfer length: %u blocks\n", u); u = (buff[12] << 24) | (buff[13] << 16) | (buff[14] << 8) | buff[15]; printf(" Optimal transfer length: %u blocks\n", u); if (len > 19) { /* added in sbc3r09 */ u = (buff[16] << 24) | (buff[17] << 16) | (buff[18] << 8) | buff[19]; printf(" Maximum prefetch, xdread, xdwrite transfer length: " "%u blocks\n", u); } if (len > 27) { /* added in sbc3r18 */ u = ((unsigned int)buff[20] << 24) | (buff[21] << 16) | (buff[22] << 8) | buff[23]; printf(" Maximum unmap LBA count: %u\n", u); u = ((unsigned int)buff[24] << 24) | (buff[25] << 16) | (buff[26] << 8) | buff[27]; printf(" Maximum unmap block descriptor count: %u\n", u); } if (len > 35) { /* added in sbc3r19 */ u = ((unsigned int)buff[28] << 24) | (buff[29] << 16) | (buff[30] << 8) | buff[31]; printf(" Optimal unmap granularity: %u\n", u); printf(" Unmap granularity alignment valid: %u\n", !!(buff[32] & 0x80)); u = ((unsigned int)(buff[32] & 0x7f) << 24) | (buff[33] << 16) | (buff[34] << 8) | buff[35]; printf(" Unmap granularity alignment: %u\n", u); } if (len > 43) { /* added in sbc3r26 */ mwsl = 0; for (m = 0; m < 8; ++m) { if (m > 0) mwsl <<= 8; mwsl |= buff[36 + m]; } printf(" Maximum write same length: 0x%" PRIx64 " blocks\n", mwsl); } if (len > 44) { /* added in sbc4r02 */ u = ((unsigned int)buff[44] << 24) | (buff[45] << 16) | (buff[46] << 8) | buff[47]; printf(" Maximum atomic transfer length: %u\n", u); u = ((unsigned int)buff[48] << 24) | (buff[49] << 16) | (buff[50] << 8) | buff[51]; printf(" Atomic alignment: %u\n", u); u = ((unsigned int)buff[52] << 24) | (buff[53] << 16) | (buff[54] << 8) | buff[55]; printf(" Atomic transfer length granularity: %u\n", u); } break; case PDT_TAPE: case PDT_MCHANGER: printf(" WORM=%d\n", !!(buff[4] & 0x1)); break; case PDT_OSD: default: printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHex((const char *)buff, len, 0); break; } } /* VPD_BLOCK_DEV_CHARS sbc */ /* VPD_MAN_ASS_SN ssc */ static void decode_b1_vpd(unsigned char * buff, int len, int do_hex) { int pdt; unsigned int u; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } pdt = 0x1f & buff[0]; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: if (len < 64) { pr2serr("Block device characteristics VPD page length too " "short=%d\n", len); return; } u = (buff[4] << 8) | buff[5]; if (0 == u) printf(" Medium rotation rate is not reported\n"); else if (1 == u) printf(" Non-rotating medium (e.g. solid state)\n"); else if ((u < 0x401) || (0xffff == u)) printf(" Reserved [0x%x]\n", u); else printf(" Nominal rotation rate: %d rpm\n", u); printf(" Product type=%d\n", buff[6]); printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3); printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3); u = buff[7] & 0xf; printf(" Nominal form factor "); switch(u) { case 0: printf("is not reported\n"); break; case 1: printf("5.25 inches\n"); break; case 2: printf("3.5 inches\n"); break; case 3: printf("2.5 inches\n"); break; case 4: printf("1.8 inches\n"); break; case 5: printf("less then 1.8 inches\n"); break; default: printf("reserved [%u]\n", u); break; } printf(" HAW_ZBC=%d\n", buff[8] & 0x10); /* sbc4r01 */ printf(" FUAB=%d\n", buff[8] & 0x2); printf(" VBULS=%d\n", buff[8] & 0x1); break; case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: printf(" Manufacturer-assigned serial number: %.*s\n", len - 4, buff + 4); break; default: printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHex((const char *)buff, len, 0); break; } } /* VPD_REFERRALS sbc */ static void decode_b3_vpd(unsigned char * buff, int len, int do_hex) { int pdt; unsigned int s, m; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } pdt = 0x1f & buff[0]; switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: if (len < 0x10) { pr2serr("Referrals VPD page length too short=%d\n", len); return; } s = (buff[8] << 24) | (buff[9] << 16) | (buff[10] << 8) | buff[11]; m = (buff[12] << 24) | (buff[13] << 16) | (buff[14] << 8) | buff[15]; if (0 == s) printf(" Single user data segment\n"); else if (0 == m) printf(" Segment size specified by user data segment " "descriptor\n"); else printf(" Segment size: %u, segment multiplier: %u\n", s, m); break; default: printf(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHex((const char *)buff, len, 0); break; } } static const char * lun_state_arr[] = { "LUN not bound or LUN_Z report", "LUN bound, but not owned by this SP", "LUN bound and owned by this SP", }; static const char * ip_mgmt_arr[] = { "No IP access", "Reserved (undefined)", "via IPv4", "via IPv6", }; static const char * sp_arr[] = { "SP A", "SP B", }; static const char * lun_op_arr[] = { "Normal operations", "I/O Operations being rejected, SP reboot or NDU in progress", }; static const char * failover_mode_arr[] = { "Legacy mode 0", "Unknown mode (1)", "Unknown mode (2)", "Unknown mode (3)", "Active/Passive (PNR) mode 1", "Unknown mode (5)", "Active/Active (ALUA) mode 4", "Unknown mode (7)", "Legacy mode 2", "Unknown mode (9)", "Unknown mode (10)", "Unknown mode (11)", "Unknown mode (12)", "Unknown mode (13)", "AIX Active/Passive (PAR) mode 3", "Unknown mode (15)", }; static void decode_upr_vpd_c0_emc(unsigned char * buff, int len, int do_hex) { int k, ip_mgmt, vpp80, lun_z; if (len < 3) { pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (buff[9] != 0x00) { pr2serr("Unsupported page revision %d, decoding not possible.\n", buff[9]); return; } printf(" LUN WWN: "); for (k = 0; k < 16; ++k) printf("%02x", buff[10 + k]); printf("\n"); printf(" Array Serial Number: "); dStrRaw((const char *)&buff[50], buff[49]); printf("\n"); printf(" LUN State: "); if (buff[4] > 0x02) printf("Unknown (%x)\n", buff[4]); else printf("%s\n", lun_state_arr[buff[4]]); printf(" This path connects to: "); if (buff[8] > 0x01) printf("Unknown SP (%x)", buff[8]); else printf("%s", sp_arr[buff[8]]); printf(", Port Number: %u\n", buff[7]); printf(" Default Owner: "); if (buff[5] > 0x01) printf("Unknown (%x)\n", buff[5]); else printf("%s\n", sp_arr[buff[5]]); printf(" NO_ATF: %s, Access Logix: %s\n", buff[6] & 0x80 ? "set" : "not set", buff[6] & 0x40 ? "supported" : "not supported"); ip_mgmt = (buff[6] >> 4) & 0x3; printf(" SP IP Management Mode: %s\n", ip_mgmt_arr[ip_mgmt]); if (ip_mgmt == 2) printf(" SP IPv4 address: %u.%u.%u.%u\n", buff[44], buff[45], buff[46], buff[47]); else { printf(" SP IPv6 address: "); for (k = 0; k < 16; ++k) printf("%02x", buff[32 + k]); printf("\n"); } vpp80 = buff[30] & 0x08; lun_z = buff[30] & 0x04; printf(" System Type: %x, Failover mode: %s\n", buff[27], failover_mode_arr[buff[28] & 0x0f]); printf(" Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", vpp80 ? "array serial#" : "LUN serial#", lun_z ? "Set to 1" : "Unknown"); printf(" Lun operations: %s\n", buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]); return; } static void decode_rdac_vpd_c2(unsigned char * buff, int len, int do_hex) { if (len < 3) { pr2serr("Software Version VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { pr2serr("Invalid page identifier %c%c%c%c, decoding " "not possible.\n" , buff[4], buff[5], buff[6], buff[7]); return; } printf(" Software Version: %d.%d.%d\n", buff[8], buff[9], buff[10]); printf(" Software Date: %02x/%02x/%02x\n", buff[11], buff[12], buff[13]); printf(" Features:"); if (buff[14] & 0x01) printf(" Dual Active,"); if (buff[14] & 0x02) printf(" Series 3,"); if (buff[14] & 0x04) printf(" Multiple Sub-enclosures,"); if (buff[14] & 0x08) printf(" DCE/DRM,"); if (buff[14] & 0x10) printf(" AVT,"); printf("\n"); printf(" Max. #of LUNS: %d\n", buff[15]); return; } static void decode_rdac_vpd_c9(unsigned char * buff, int len, int do_hex) { if (len < 3) { pr2serr("Volume Access Control VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') { pr2serr("Invalid page identifier %c%c%c%c, decoding " "not possible.\n" , buff[4], buff[5], buff[6], buff[7]); return; } if (buff[7] != '1') { pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]); } printf(" AVT:"); if (buff[8] & 0x80) { printf(" Enabled"); if (buff[8] & 0x40) printf(" (Allow reads on sector 0)"); printf("\n"); } else { printf(" Disabled\n"); } printf(" Volume Access via: "); if (buff[8] & 0x01) printf("primary controller\n"); else printf("alternate controller\n"); printf(" Path priority: %d ", buff[9] & 0xf); switch(buff[9] & 0xf) { case 0x1: printf("(preferred path)\n"); break; case 0x2: printf("(secondary path)\n"); break; default: printf("(unknown)\n"); break; } return; } extern const char * sg_ansi_version_arr[]; static const char * get_ansi_version_str(int version, char * buff, int buff_len) { version &= 0xf; buff[buff_len - 1] = '\0'; strncpy(buff, sg_ansi_version_arr[version], buff_len - 1); return buff; } static int std_inq_response(const struct opts_t * op, int act_len) { int len, pqual, peri_type, ansi_version, k, j; const char * cp; int vdesc_arr[8]; char buff[48]; const unsigned char * rp; rp = rsp_buff; memset(vdesc_arr, 0, sizeof(vdesc_arr)); len = rp[4] + 5; if (op->do_raw) { dStrRaw((const char *)rp, act_len); return 0; } else if (op->do_hex) { /* with -H, print with address, -HH without */ dStrHex((const char *)rp, act_len, ((1 == op->do_hex) ? 0 : -1)); return 0; } pqual = (rp[0] & 0xe0) >> 5; if (! op->do_raw && ! op->do_export) { if (0 == pqual) printf("standard INQUIRY:\n"); else if (1 == pqual) printf("standard INQUIRY: [qualifier indicates no connected " "LU]\n"); else if (3 == pqual) printf("standard INQUIRY: [qualifier indicates not capable " "of supporting LU]\n"); else printf("standard INQUIRY: [reserved or vendor specific " "qualifier [%d]]\n", pqual); } len = rp[4] + 5; /* N.B. rp[2] full byte is 'version' in SPC-2,3,4 but in SPC * [spc-r11a (1997)] bits 6,7: ISO/IEC version; bits 3-5: ECMA * version; bits 0-2: SCSI version */ ansi_version = rp[2] & 0x7; /* Only take SCSI version */ peri_type = rp[0] & 0x1f; if (op->do_export) { printf("SCSI_TPGS=%d\n", (rp[5] & 0x30) >> 4); cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf("SCSI_TYPE=%s\n", cp); } else { printf(" PQual=%d Device_type=%d RMB=%d LU_CONG=%d " "version=0x%02x ", pqual, peri_type, !!(rp[1] & 0x80), !!(rp[1] & 0x40), (unsigned int)rp[2]); printf(" [%s]\n", get_ansi_version_str(ansi_version, buff, sizeof(buff))); printf(" [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d " " Resp_data_format=%d\n SCCS=%d ", !!(rp[3] & 0x80), !!(rp[3] & 0x40), !!(rp[3] & 0x20), !!(rp[3] & 0x10), rp[3] & 0x0f, !!(rp[5] & 0x80)); printf("ACC=%d TPGS=%d 3PC=%d Protect=%d ", !!(rp[5] & 0x40), ((rp[5] & 0x30) >> 4), !!(rp[5] & 0x08), !!(rp[5] & 0x01)); printf(" [BQue=%d]\n EncServ=%d ", !!(rp[6] & 0x80), !!(rp[6] & 0x40)); if (rp[6] & 0x10) printf("MultiP=1 (VS=%d) ", !!(rp[6] & 0x20)); else printf("MultiP=0 "); printf("[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n [RelAdr=%d] ", !!(rp[6] & 0x08), !!(rp[6] & 0x04), !!(rp[6] & 0x01), !!(rp[7] & 0x80)); printf("WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ", !!(rp[7] & 0x20), !!(rp[7] & 0x10), !!(rp[7] & 0x08), !!(rp[7] & 0x04)); printf("CmdQue=%d\n", !!(rp[7] & 0x02)); if (act_len > 56) printf(" [SPI: Clocking=0x%x QAS=%d IUS=%d]\n", (rp[56] & 0x0c) >> 2, !!(rp[56] & 0x2), !!(rp[56] & 0x1)); if (act_len >= len) printf(" length=%d (0x%x)", len, len); else printf(" length=%d (0x%x), but only fetched %d bytes", len, len, act_len); if ((ansi_version >= 2) && (len < SAFE_STD_INQ_RESP_LEN)) printf("\n [for SCSI>=2, len>=36 is expected]"); cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); } if (act_len <= 8) { if (! op->do_export) printf(" Inquiry response length=%d, no vendor, product or " "revision data\n", act_len); } else { int i; memcpy(xtra_buff, &rp[8], 8); xtra_buff[8] = '\0'; /* Fixup any tab characters */ for (i = 0; i < 8; ++i) if (xtra_buff[i] == 0x09) xtra_buff[i] = ' '; if (op->do_export) { len = encode_whitespaces((unsigned char *)xtra_buff, 8); printf("SCSI_VENDOR=%s\n", xtra_buff); encode_string(xtra_buff, &rp[8], 8); printf("SCSI_VENDOR_ENC=%s\n", xtra_buff); } else printf(" Vendor identification: %s\n", xtra_buff); if (act_len <= 16) { if (! op->do_export) printf(" Product identification: \n"); } else { memcpy(xtra_buff, &rp[16], 16); xtra_buff[16] = '\0'; if (op->do_export) { len = encode_whitespaces((unsigned char *)xtra_buff, 16); printf("SCSI_MODEL=%s\n", xtra_buff); encode_string(xtra_buff, &rp[16], 16); printf("SCSI_MODEL_ENC=%s\n", xtra_buff); } else printf(" Product identification: %s\n", xtra_buff); } if (act_len <= 32) { if (!op->do_export) printf(" Product revision level: \n"); } else { memcpy(xtra_buff, &rp[32], 4); xtra_buff[4] = '\0'; if (op->do_export) { len = encode_whitespaces((unsigned char *)xtra_buff, 4); printf("SCSI_REVISION=%s\n", xtra_buff); } else printf(" Product revision level: %s\n", xtra_buff); } if (op->do_vendor && (act_len > 36) && ('\0' != rp[36]) && (' ' != rp[36])) { memcpy(xtra_buff, &rp[36], act_len < 56 ? act_len - 36 : 20); if (op->do_export) { len = encode_whitespaces((unsigned char *)xtra_buff, 20); printf("VENDOR_SPECIFIC=%s\n", xtra_buff); } else printf(" Vendor specific: %s\n", xtra_buff); } if (op->do_descriptors) { for (j = 0, k = 58; ((j < 8) && ((k + 1) < act_len)); k +=2, ++j) vdesc_arr[j] = ((rp[k] << 8) + rp[k + 1]); } if ((op->do_vendor > 1) && (act_len > 96)) { memcpy(xtra_buff, &rp[96], act_len - 96); if (op->do_export) { len = encode_whitespaces((unsigned char *)xtra_buff, act_len - 96); printf("VENDOR_SPECIFIC=%s\n", xtra_buff); } else printf(" Vendor specific: %s\n", xtra_buff); } } if (! op->do_export) { if ((0 == op->resp_len) && usn_buff[0]) printf(" Unit serial number: %s\n", usn_buff); if (op->do_descriptors) { if (0 == vdesc_arr[0]) printf("\n No version descriptors available\n"); else { printf("\n Version descriptors:\n"); for (k = 0; k < 8; ++k) { if (0 == vdesc_arr[k]) break; cp = find_version_descriptor_str(vdesc_arr[k]); if (cp) printf(" %s\n", cp); else printf(" [unrecognised version descriptor " "code: 0x%x]\n", vdesc_arr[k]); } } } } return 0; } /* When sg_fd >= 0 fetch VPD page from device; mxlen is command line * --maxlen=LEN option (def: 0) or -1 for a VPD page with a short length * (1 byte). When sg_fd < 0 then mxlen bytes have been read from * --inhex=FN file. Returns 0 for success. */ static int vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page, int mxlen, int vb, int * rlenp) { int res, resid, rlen, len, n; if (sg_fd < 0) { len = ((rp[2] << 8) + rp[3]) + 4; if (vb && (len > mxlen)) pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN " "file (%d)\n", len , mxlen); if (rlenp) *rlenp = (len < mxlen) ? len : mxlen; return 0; } if (mxlen > MX_ALLOC_LEN) { pr2serr("--maxlen=LEN too long: %d > %d\n", mxlen, MX_ALLOC_LEN); return SG_LIB_SYNTAX_ERROR; } n = (mxlen > 0) ? mxlen : DEF_ALLOC_LEN; res = pt_inquiry(sg_fd, 1, page, rp, n, &resid, 1, vb); if (res) return res; rlen = n - resid; if (rlen < 4) { pr2serr("VPD response too short (len=%d)\n", rlen); return SG_LIB_CAT_MALFORMED; } if (page != rp[1]) { pr2serr("invalid VPD response; probably a STANDARD INQUIRY " "response\n"); return SG_LIB_CAT_MALFORMED; } if (mxlen < 0) len = rp[3] + 4; else len = ((rp[2] << 8) + rp[3]) + 4; if (len <= rlen) { if (rlenp) *rlenp = len; return 0; } else if (mxlen) { if (rlenp) *rlenp = rlen; return 0; } if (len > MX_ALLOC_LEN) { pr2serr("response length too long: %d > %d\n", len, MX_ALLOC_LEN); return SG_LIB_CAT_MALFORMED; } else { res = pt_inquiry(sg_fd, 1, page, rp, len, &resid, 1, vb); if (res) return res; rlen = len - resid; /* assume it is well behaved: hence page and len still same */ if (rlenp) *rlenp = rlen; return 0; } } /* Returns 0 if Unit Serial Number VPD page contents found, else see * sg_ll_inquiry() return values */ static int fetch_unit_serial_num(int sg_fd, char * obuff, int obuff_len, int verbose) { int len, k, res; unsigned char b[DEF_ALLOC_LEN]; res = 0; memset(b, 0xff, 4); /* guard against empty response */ res = vpd_fetch_page_from_dev(sg_fd, b, VPD_UNIT_SERIAL_NUM, -1, verbose, &len); if ((0 == res) && (len > 3)) { len -= 4; len = (len < (obuff_len - 1)) ? len : (obuff_len - 1); if (len > 0) { /* replace non-printable ASCII characters with space */ for (k = 0; k < len; ++k) obuff[k] = isprint(b[4 + k]) ? b[4 + k] : ' '; obuff[len] = '\0'; return 0; } else { if (verbose > 2) pr2serr("fetch_unit_serial_num: bad sn VPD page\n"); return SG_LIB_CAT_MALFORMED; } } else { if (verbose > 2) pr2serr("fetch_unit_serial_num: no supported VPDs page\n"); return SG_LIB_CAT_MALFORMED; } return res; } /* Process a standard INQUIRY response. Returns 0 if successful */ static int std_inq_process(int sg_fd, const struct opts_t * op, int inhex_len) { int res, len, rlen, act_len; char buff[48]; int verb, resid; if (sg_fd < 0) return std_inq_response(op, inhex_len); rlen = (op->resp_len > 0) ? op->resp_len : SAFE_STD_INQ_RESP_LEN; verb = op->do_verbose; res = pt_inquiry(sg_fd, 0, 0, rsp_buff, rlen, &resid, 0, verb); if (0 == res) { len = rsp_buff[4] + 5; if ((len > SAFE_STD_INQ_RESP_LEN) && (len < 256) && (0 == op->resp_len)) { rlen = len; memset(rsp_buff, 0, rlen); if (pt_inquiry(sg_fd, 0, 0, rsp_buff, rlen, &resid, 1, verb)) { pr2serr("second INQUIRY (%d byte) failed\n", len); return SG_LIB_CAT_OTHER; } if (len != (rsp_buff[4] + 5)) { pr2serr("strange, consecutive INQUIRYs yield different " "'additional lengths'\n"); res = SG_LIB_CAT_MALFORMED; len = rsp_buff[4] + 5; } } if (op->resp_len > 0) act_len = rlen; else act_len = (rlen < len) ? rlen : len; /* don't use more than HBA's resid says was transferred from LU */ if (act_len > (rlen - resid)) act_len = rlen - resid; if (act_len < SAFE_STD_INQ_RESP_LEN) rsp_buff[act_len] = '\0'; if ((! op->do_export) && (0 == op->resp_len)) { if (fetch_unit_serial_num(sg_fd, usn_buff, sizeof(usn_buff), op->do_verbose)) usn_buff[0] = '\0'; } return std_inq_response(op, act_len); } else if (res < 0) { /* could be an ATA device */ #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) /* Try an ATA Identify Device command */ res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, op->do_verbose); if (0 != res) { pr2serr("Both SCSI INQUIRY and fetching ATA information " "failed on %s\n", op->device_name); return SG_LIB_CAT_OTHER; } #else pr2serr("SCSI INQUIRY failed on %s, res=%d\n", op->device_name, res); return res; #endif } else { char b[80]; pr2serr(" inquiry: failed requesting %d byte response: ", rlen); if (resid && verb) snprintf(buff, sizeof(buff), " [resid=%d]", resid); else buff[0] = '\0'; sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("%s%s\n", b, buff); return res; } return 0; } #ifdef SG_SCSI_STRINGS /* Returns 0 if successful */ static int cmddt_process(int sg_fd, const struct opts_t * op) { int k, j, num, len, peri_type, reserved_cmddt, support_num, res; char op_name[128]; memset(rsp_buff, 0, DEF_ALLOC_LEN); if (op->do_cmddt > 1) { printf("Supported command list:\n"); for (k = 0; k < 256; ++k) { res = sg_ll_inquiry(sg_fd, 1, 0, k, rsp_buff, DEF_ALLOC_LEN, 1, op->do_verbose); if (0 == res) { peri_type = rsp_buff[0] & 0x1f; support_num = rsp_buff[1] & 7; reserved_cmddt = rsp_buff[4]; if ((3 == support_num) || (5 == support_num)) { num = rsp_buff[5]; for (j = 0; j < num; ++j) printf(" %.2x", (int)rsp_buff[6 + j]); if (5 == support_num) printf(" [vendor specific manner (5)]"); sg_get_opcode_name((unsigned char)k, peri_type, sizeof(op_name) - 1, op_name); op_name[sizeof(op_name) - 1] = '\0'; printf(" %s\n", op_name); } else if ((4 == support_num) || (6 == support_num)) printf(" opcode=0x%.2x vendor specific (%d)\n", k, support_num); else if ((0 == support_num) && (reserved_cmddt > 0)) { printf(" opcode=0x%.2x ignored cmddt bit, " "given standard INQUIRY response, stop\n", k); break; } } else if (SG_LIB_CAT_ILLEGAL_REQ == res) break; else { pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", k); break; } } } else { res = sg_ll_inquiry(sg_fd, 1, 0, op->page_num, rsp_buff, DEF_ALLOC_LEN, 1, op->do_verbose); if (0 == res) { peri_type = rsp_buff[0] & 0x1f; if (! op->do_raw) { printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->page_num); sg_get_opcode_name((unsigned char)op->page_num, peri_type, sizeof(op_name) - 1, op_name); op_name[sizeof(op_name) - 1] = '\0'; printf("%s]\n", op_name); } len = rsp_buff[5] + 6; reserved_cmddt = rsp_buff[4]; if (op->do_hex) dStrHex((const char *)rsp_buff, len, (1 == op->do_hex) ? 0 : -1); else if (op->do_raw) dStrRaw((const char *)rsp_buff, len); else { const char * desc_p; int prnt_cmd = 0; support_num = rsp_buff[1] & 7; num = rsp_buff[5]; switch (support_num) { case 0: if (0 == reserved_cmddt) desc_p = "no data available"; else desc_p = "ignored cmddt bit, standard INQUIRY " "response"; break; case 1: desc_p = "not supported"; break; case 2: desc_p = "reserved (2)"; break; case 3: desc_p = "supported as per standard"; prnt_cmd = 1; break; case 4: desc_p = "vendor specific (4)"; break; case 5: desc_p = "supported in vendor specific way"; prnt_cmd = 1; break; case 6: desc_p = "vendor specific (6)"; break; case 7: desc_p = "reserved (7)"; break; default: desc_p = "impossible value > 7"; break; } if (prnt_cmd) { printf(" Support field: %s [", desc_p); for (j = 0; j < num; ++j) printf(" %.2x", (int)rsp_buff[6 + j]); printf(" ]\n"); } else printf(" Support field: %s\n", desc_p); } } else if (SG_LIB_CAT_ILLEGAL_REQ != res) { if (! op->do_raw) { printf("CmdDt INQUIRY, opcode=0x%.2x: [", op->page_num); sg_get_opcode_name((unsigned char)op->page_num, 0, sizeof(op_name) - 1, op_name); op_name[sizeof(op_name) - 1] = '\0'; printf("%s]\n", op_name); } pr2serr("CmdDt INQUIRY on opcode=0x%.2x: failed\n", op->page_num); } } return res; } #else /* SG_SCSI_STRINGS */ /* Returns 0. */ static int cmddt_process(int sg_fd, const struct opts_t * op) { sg_fd = sg_fd; op = op; pr2serr("'--cmddt' not implemented, use sg_opcodes\n"); return 0; } #endif /* SG_SCSI_STRINGS */ /* Returns 0 if successful */ static int vpd_mainly_hex(int sg_fd, const struct opts_t * op, int inhex_len) { int res, len; char b[128]; const char * cp; unsigned char * rp; rp = rsp_buff; if ((! op->do_raw) && (op->do_hex < 2)) printf("VPD INQUIRY, page code=0x%.2x:\n", op->page_num); if (sg_fd < 0) { len = ((rp[2] << 8) + rp[3]) + 4; if (op->do_verbose && (len > inhex_len)) pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN " "file (%d)\n", len , inhex_len); res = 0; } else { memset(rp, 0, DEF_ALLOC_LEN); res = vpd_fetch_page_from_dev(sg_fd, rp, op->page_num, op->resp_len, op->do_verbose, &len); } if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { if (0 == op->page_num) decode_supported_vpd(rp, len, op->do_hex); else { if (op->do_verbose) { cp = sg_get_pdt_str(rp[0] & 0x1f, sizeof(b), b); printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, cp); } dStrHex((const char *)rp, len, ((1 == op->do_hex) ? 0 : -1)); } } } else { if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr(" inquiry: field in cdb illegal (page not " "supported)\n"); else { sg_get_category_sense_str(res, sizeof(b), b, op->do_verbose); pr2serr(" inquiry: %s\n", b); } } return res; } /* Returns 0 if successful */ static int vpd_decode(int sg_fd, const struct opts_t * op, int inhex_len) { int len, pdt, pn, vb, mxlen; int res = 0; unsigned char * rp; pn = op->page_num; rp = rsp_buff; vb = op->do_verbose; if (sg_fd >= 0) mxlen = op->resp_len; else mxlen = inhex_len; switch (pn) { case VPD_SUPPORTED_VPDS: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Supported VPD pages page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1); else decode_supported_vpd(rp, len, 0x1f & rp[0]); break; case VPD_UNIT_SERIAL_NUM: if (! op->do_raw && ! op->do_export && (op->do_hex < 2)) printf("VPD INQUIRY: Unit serial number page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1); else { char obuff[DEF_ALLOC_LEN]; memset(obuff, 0, sizeof(obuff)); len -= 4; if (len >= (int)sizeof(obuff)) len = sizeof(obuff) - 1; memcpy(obuff, rp + 4, len); if (op->do_export) { len = encode_whitespaces((unsigned char *)obuff, len); printf("SCSI_IDENT_SERIAL=%s\n", obuff); } else { printf(" Unit serial number: %s\n", obuff); } } break; case VPD_DEVICE_ID: if (! op->do_raw && ! op->do_export && (op->do_hex < 3)) printf("VPD INQUIRY: Device Identification page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex > 2) dStrHex((const char *)rp, len, -1); else if (op->do_export) export_dev_ids(rp + 4, len - 4, op->do_verbose); else decode_id_vpd(rp, len, op->do_hex); break; case VPD_SOFTW_INF_ID: if (! op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Software interface identification page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_softw_inf_id(rp, len, op->do_hex); break; case VPD_MAN_NET_ADDR: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Management network addresses page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_net_man_vpd(rp, len, op->do_hex); break; case VPD_MODE_PG_POLICY: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Mode page policy\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_mode_policy_vpd(rp, len, op->do_hex); break; case VPD_EXT_INQ: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: extended INQUIRY data page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_x_inq_vpd(rp, len, op->do_hex); break; case VPD_ATA_INFO: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: ATA information page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; /* format output for 'hdparm --Istdin' with '-rr' or '-HHH' */ if ((2 == op->do_raw) || (3 == op->do_hex)) dWordHex((const unsigned short *)(rp + 60), 256, -2, sg_is_big_endian()); else if (op->do_raw) dStrRaw((const char *)rp, len); else decode_ata_info_vpd(rp, len, op->do_hex); break; case VPD_POWER_CONDITION: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Power condition page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_power_condition(rp, len, op->do_hex); break; case 0xb0: /* VPD pages in B0h to BFh range depend on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: printf("VPD INQUIRY: Block limits page (SBC)\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("VPD INQUIRY: Sequential access device " "capabilities (SSC)\n"); break; case PDT_OSD: printf("VPD INQUIRY: OSD information (OSD)\n"); break; default: printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb0, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else decode_b0_vpd(rp, len, op->do_hex); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb0\n"); break; case 0xb1: /* VPD pages in B0h to BFh range depend on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: printf("VPD INQUIRY: Block device characteristcis page " "(SBC)\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("Manufactured assigned serial number VPD page " "(SSC):\n"); break; case PDT_OSD: printf("Security token VPD page (OSD):\n"); break; case PDT_ADC: printf("Manufactured assigned serial number VPD page " "(ADC):\n"); break; default: printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb1, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else decode_b1_vpd(rp, len, op->do_hex); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb1\n"); break; case 0xb2: /* VPD pages in B0h to BFh range depend on pdt */ if (!op->do_raw && (op->do_hex < 2)) pr2serr(" Only hex output supported. sg_vpd decodes the B2h " "page.\n"); return vpd_mainly_hex(sg_fd, op, inhex_len); case 0xb3: /* VPD pages in B0h to BFh range depend on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (! op->do_raw && (op->do_hex < 2)) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: printf("VPD INQUIRY: Referrals VPD page (SBC)\n"); break; default: printf("VPD INQUIRY: page=0x%x, pdt=0x%x\n", 0xb3, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else decode_b3_vpd(rp, len, op->do_hex); } else if (! op->do_raw) pr2serr("VPD INQUIRY: page=0xb3\n"); break; case VPD_UPR_EMC: /* 0xc0 */ if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Unit Path Report Page (EMC)\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_upr_vpd_c0_emc(rp, len, op->do_hex); break; case VPD_RDAC_VERS: /* 0xc2 */ if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Software Version (RDAC)\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_rdac_vpd_c2(rp, len, op->do_hex); break; case VPD_RDAC_VAC: /* 0xc9 */ if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: Volume Access Control (RDAC)\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, -1, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_rdac_vpd_c9(rp, len, op->do_hex); break; case VPD_SCSI_PORTS: if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: SCSI Ports page\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (res) break; if (op->do_raw) dStrRaw((const char *)rp, len); else decode_scsi_ports_vpd(rp, len, op->do_hex); break; default: if ((pn > 0) && (pn < 0x80)) { if (!op->do_raw && (op->do_hex < 2)) printf("VPD INQUIRY: ASCII information page, FRU code=0x%x\n", pn); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, mxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else decode_ascii_inf(rp, len, op->do_hex); } } else { if (op->do_hex < 2) pr2serr(" Only hex output supported. sg_vpd and sdparm " "decode more VPD pages.\n"); return vpd_mainly_hex(sg_fd, op, inhex_len); } } if (res) { char b[80]; if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr(" inquiry: field in cdb illegal (page not " "supported)\n"); else { sg_get_category_sense_str(res, sizeof(b), b, vb); pr2serr(" inquiry: %s\n", b); } } return res; } int main(int argc, char * argv[]) { int sg_fd, res, n; int ret = 0; int inhex_len = 0; const struct svpd_values_name_t * vnp; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->page_num = -1; op->page_pdt = -1; op->do_block = -1; /* use default for OS */ res = cl_process(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_help) { usage_for(op); if (op->do_help > 1) { pr2serr("\n>>> Available VPD page abbreviations:\n"); enumerate_vpds(); } return 0; } if (op->do_version) { pr2serr("Version string: %s\n", version_str); return 0; } if (op->page_arg) { if (op->page_num >= 0) { pr2serr("Given '-p' option and another option that " "implies a page\n"); return SG_LIB_SYNTAX_ERROR; } if (isalpha(op->page_arg[0])) { vnp = sdp_find_vpd_by_acron(op->page_arg); if (NULL == vnp) { #ifdef SG_SCSI_STRINGS if (op->opt_new) pr2serr("abbreviation %s given to '--page=' " "not recognized\n", op->page_arg); else pr2serr("abbreviation %s given to '-p=' " "not recognized\n", op->page_arg); #else pr2serr("abbreviation %s given to '--page=' " "not recognized\n", op->page_arg); #endif pr2serr(">>> Available abbreviations:\n"); enumerate_vpds(); return SG_LIB_SYNTAX_ERROR; } if ((1 != op->do_hex) && (0 == op->do_raw)) ++op->do_decode; op->page_num = vnp->value; op->page_pdt = vnp->pdt; } else if ('-' == op->page_arg[0]) { op->page_num = -2; /* request standard INQUIRY response */ } else { #ifdef SG_SCSI_STRINGS if (op->opt_new) { n = sg_get_num(op->page_arg); if ((n < 0) || (n > 255)) { pr2serr("Bad argument to '--page=', " "expecting 0 to 255 inclusive\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if ((1 != op->do_hex) && (0 == op->do_raw)) ++op->do_decode; } else { int num; unsigned int u; num = sscanf(op->page_arg, "%x", &u); if ((1 != num) || (u > 255)) { pr2serr("Inappropriate value after '-o=' " "or '-p=' option\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } n = u; } #else n = sg_get_num(op->page_arg); if ((n < 0) || (n > 255)) { pr2serr("Bad argument to '--page=', " "expecting 0 to 255 inclusive\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if ((1 != op->do_hex) && (0 == op->do_raw)) ++op->do_decode; #endif /* SG_SCSI_STRINGS */ op->page_num = n; } } if (op->inhex_fn) { if (op->device_name) { pr2serr("Cannot have both a DEVICE and --inhex= option\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_cmddt) { pr2serr("Don't support --cmddt with --inhex= option\n"); return SG_LIB_SYNTAX_ERROR; } if (f2hex_arr(op->inhex_fn, op->do_raw, 0, rsp_buff, &inhex_len, sizeof(rsp_buff))) return SG_LIB_FILE_ERROR; op->do_raw = 0; /* don't want raw on output with --inhex= */ if (-1 == op->page_num) { /* may be able to deduce VPD page */ if (op->page_pdt < 0) op->page_pdt = 0x1f & rsp_buff[0]; if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) { if (op->do_verbose) pr2serr("Guessing from --inhex= this is a standard " "INQUIRY\n"); } else if (rsp_buff[2] <= 2) { if (op->do_verbose) pr2serr("Guessing from --inhex this is VPD page 0x%x\n", rsp_buff[1]); op->page_num = rsp_buff[1]; ++op->do_vpd; if ((1 != op->do_hex) && (0 == op->do_raw)) ++op->do_decode; } else { if (op->do_verbose) pr2serr("page number unclear from --inhex, hope it's a " "standard INQUIRY\n"); } } } else if (0 == op->device_name) { pr2serr("No DEVICE argument given\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (-2 == op->page_num) /* from --page=- to force standard INQUIRY */ op->page_num = -1; /* now past guessing, set to normal indication */ if (op->do_export) { if (op->page_num != -1) { if (op->page_num != VPD_DEVICE_ID && op->page_num != VPD_UNIT_SERIAL_NUM) { pr2serr("Option '--export' only supported " "for VPD pages 0x80 and 0x83\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } ++op->do_decode; ++op->do_vpd; } } if ((0 == op->do_cmddt) && (op->page_num >= 0) && op->p_given) ++op->do_vpd; if (op->do_raw && op->do_hex) { pr2serr("Can't do hex and raw at the same time\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_vpd && op->do_cmddt) { #ifdef SG_SCSI_STRINGS if (op->opt_new) pr2serr("Can't use '--cmddt' with VPD pages\n"); else pr2serr("Can't have both '-e' and '-c' (or '-cl')\n"); #else pr2serr("Can't use '--cmddt' with VPD pages\n"); #endif usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (((op->do_vpd || op->do_cmddt)) && (op->page_num < 0)) op->page_num = 0; if (op->num_pages > 1) { pr2serr("Can only fetch one page (VPD or Cmd) at a time\n"); usage_for(op); return SG_LIB_SYNTAX_ERROR; } if (op->do_descriptors) { if ((op->resp_len > 0) && (op->resp_len < 60)) { pr2serr("version descriptors need INQUIRY response " "length >= 60 bytes\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_vpd || op->do_cmddt) { pr2serr("version descriptors require standard INQUIRY\n"); return SG_LIB_SYNTAX_ERROR; } } if (op->num_pages && op->do_ata) { pr2serr("Can't use '-A' with an explicit decode VPD page option\n"); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if (op->inhex_fn) { if (op->do_vpd) { if (op->do_decode) return vpd_decode(-1, op, inhex_len); else return vpd_mainly_hex(-1, op, inhex_len); } else return std_inq_process(-1, op, inhex_len); } #if defined(O_NONBLOCK) && defined(O_RDONLY) if (op->do_block >= 0) { n = O_RDONLY | (op->do_block ? 0 : O_NONBLOCK); if ((sg_fd = sg_cmds_open_flags(op->device_name, n, op->do_verbose)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } } else { if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->do_verbose)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } } #else if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->do_verbose)) < 0) { pr2serr("sg_inq: error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } #endif memset(rsp_buff, 0, sizeof(rsp_buff)); #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) if (op->do_ata) { res = try_ata_identify(sg_fd, op->do_hex, op->do_raw, op->do_verbose); if (0 != res) { pr2serr("fetching ATA information failed on %s\n", op->device_name); ret = SG_LIB_CAT_OTHER; } else ret = 0; goto err_out; } #endif if ((! op->do_cmddt) && (! op->do_vpd)) { /* So it's a standard INQUIRY, try ATA IDENTIFY if that fails */ ret = std_inq_process(sg_fd, op, -1); if (ret) goto err_out; } else if (op->do_cmddt) { if (op->page_num < 0) op->page_num = 0; ret = cmddt_process(sg_fd, op); if (ret) goto err_out; } else if (op->do_vpd) { if (op->do_decode) { ret = vpd_decode(sg_fd, op, -1); if (ret) goto err_out; } else { ret = vpd_mainly_hex(sg_fd, op, -1); if (ret) goto err_out; } } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } #if defined(SG_LIB_LINUX) && defined(SG_SCSI_STRINGS) /* Following code permits ATA IDENTIFY commands to be performed on ATA non "Packet Interface" devices (e.g. ATA disks). GPL-ed code borrowed from smartmontools (smartmontools.sf.net). Copyright (C) 2002-4 Bruce Allen */ #ifndef ATA_IDENTIFY_DEVICE #define ATA_IDENTIFY_DEVICE 0xec #define ATA_IDENTIFY_PACKET_DEVICE 0xa1 #endif #ifndef HDIO_DRIVE_CMD #define HDIO_DRIVE_CMD 0x031f #endif /* Needed parts of the ATA DRIVE IDENTIFY Structure. Those labeled * word* are NOT used. */ struct ata_identify_device { unsigned short words000_009[10]; unsigned char serial_no[20]; unsigned short words020_022[3]; unsigned char fw_rev[8]; unsigned char model[40]; unsigned short words047_079[33]; unsigned short major_rev_num; unsigned short minor_rev_num; unsigned short command_set_1; unsigned short command_set_2; unsigned short command_set_extension; unsigned short cfs_enable_1; unsigned short word086; unsigned short csf_default; unsigned short words088_255[168]; }; #define ATA_IDENTIFY_BUFF_SZ sizeof(struct ata_identify_device) #define HDIO_DRIVE_CMD_OFFSET 4 static int ata_command_interface(int device, char *data, int * atapi_flag, int verbose) { unsigned char buff[ATA_IDENTIFY_BUFF_SZ + HDIO_DRIVE_CMD_OFFSET]; unsigned short get_ident[256]; if (atapi_flag) *atapi_flag = 0; memset(buff, 0, sizeof(buff)); if (ioctl(device, HDIO_GET_IDENTITY, &get_ident) < 0) { if (ENOTTY == errno) { if (verbose > 1) pr2serr("HDIO_GET_IDENTITY failed with ENOTTY, " "try HDIO_DRIVE_CMD ioctl ...\n"); buff[0] = ATA_IDENTIFY_DEVICE; buff[3] = 1; if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) { if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) " "ioctl failed:\n\t%s [%d]\n", safe_strerror(errno), errno); return errno; } memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ); return 0; } else { if (verbose) pr2serr("HDIO_GET_IDENTITY ioctl failed:\n" "\t%s [%d]\n", safe_strerror(errno), errno); return errno; } } else if (verbose > 1) pr2serr("HDIO_GET_IDENTITY succeeded\n"); if (0x2 == ((get_ident[0] >> 14) &0x3)) { /* ATAPI device */ if (verbose > 1) pr2serr("assume ATAPI device from HDIO_GET_IDENTITY response\n"); memset(buff, 0, sizeof(buff)); buff[0] = ATA_IDENTIFY_PACKET_DEVICE; buff[3] = 1; if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) { if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_PACKET_DEVICE) " "ioctl failed:\n\t%s [%d]\n", safe_strerror(errno), errno); buff[0] = ATA_IDENTIFY_DEVICE; buff[3] = 1; if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) { if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) " "ioctl failed:\n\t%s [%d]\n", safe_strerror(errno), errno); return errno; } } else if (atapi_flag) { *atapi_flag = 1; if (verbose > 1) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n"); } } else { /* assume non-packet device */ buff[0] = ATA_IDENTIFY_DEVICE; buff[3] = 1; if (ioctl(device, HDIO_DRIVE_CMD, buff) < 0) { if (verbose) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) ioctl failed:" "\n\t%s [%d]\n", safe_strerror(errno), errno); return errno; } else if (verbose > 1) pr2serr("HDIO_DRIVE_CMD(ATA_IDENTIFY_DEVICE) succeeded\n"); } /* if the command returns data, copy it back */ memcpy(data, buff + HDIO_DRIVE_CMD_OFFSET, ATA_IDENTIFY_BUFF_SZ); return 0; } /* Returns 0 if successful, else errno of error */ static int try_ata_identify(int ata_fd, int do_hex, int do_raw, int verbose) { struct ata_identify_device ata_ident; char model[64]; char serial[64]; char firm[64]; int res, atapi; memset(&ata_ident, 0, sizeof(ata_ident)); res = ata_command_interface(ata_fd, (char *)&ata_ident, &atapi, verbose); if (res) return res; if ((2 == do_raw) || (3 == do_hex)) dWordHex((const unsigned short *)&ata_ident, 256, -2, sg_is_big_endian()); else if (do_raw) dStrRaw((const char *)&ata_ident, 512); else { if (do_hex) { if (atapi) printf("ATA IDENTIFY PACKET DEVICE response "); else printf("ATA IDENTIFY DEVICE response "); if (do_hex > 1) { printf("(512 bytes):\n"); dStrHex((const char *)&ata_ident, 512, 0); } else { printf("(256 words):\n"); dWordHex((const unsigned short *)&ata_ident, 256, 0, sg_is_big_endian()); } } else { printf("%s device: model, serial number and firmware revision:\n", (atapi ? "ATAPI" : "ATA")); res = sg_ata_get_chars((const unsigned short *)ata_ident.model, 0, 20, sg_is_big_endian(), model); model[res] = '\0'; res = sg_ata_get_chars((const unsigned short *)ata_ident.serial_no, 0, 10, sg_is_big_endian(), serial); serial[res] = '\0'; res = sg_ata_get_chars((const unsigned short *)ata_ident.fw_rev, 0, 4, sg_is_big_endian(), firm); firm[res] = '\0'; printf(" %s %s %s\n", model, serial, firm); if (verbose) { if (atapi) printf("ATA IDENTIFY PACKET DEVICE response " "(256 words):\n"); else printf("ATA IDENTIFY DEVICE response (256 words):\n"); dWordHex((const unsigned short *)&ata_ident, 256, 0, sg_is_big_endian()); } } } return 0; } #endif /* If this structure is changed then the structure of the same name in * sg_inq_data,c should also be changed */ struct sg_version_descriptor { int value; const char * name; }; extern struct sg_version_descriptor sg_version_descriptor_arr[]; static const char * find_version_descriptor_str(int value) { int k; const struct sg_version_descriptor * vdp; for (k = 0; ((vdp = sg_version_descriptor_arr + k) && vdp->name); ++k) { if (value == vdp->value) return vdp->name; if (value < vdp->value) break; } return NULL; } sg3_utils-1.40/src/sg_ses.c0000664000175000017500000047032412424673250014605 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_pt.h" /* needed for scsi_pt_win32_direct() */ /* * This program issues SCSI SEND DIAGNOSTIC and RECEIVE DIAGNOSTIC RESULTS * commands tailored for SES (enclosure) devices. */ static const char * version_str = "1.99 20141028"; /* ses3r07 */ #define MX_ALLOC_LEN ((64 * 1024) - 4) /* max allowable for big enclosures */ #define MX_ELEM_HDR 1024 #define MX_DATA_IN 2048 #define MX_JOIN_ROWS 260 #define NUM_ACTIVE_ET_AESP_ARR 32 #define TEMPERAT_OFF 20 /* 8 bits represents -19 C to +235 C */ /* value of 0 (would imply -20 C) reserved */ /* Send Diagnostic and Receive Diagnostic Results page codes */ #define DPC_SUPPORTED 0x0 #define DPC_CONFIGURATION 0x1 #define DPC_ENC_CONTROL 0x2 #define DPC_ENC_STATUS 0x2 #define DPC_HELP_TEXT 0x3 #define DPC_STRING 0x4 #define DPC_THRESHOLD 0x5 #define DPC_ARRAY_CONTROL 0x6 /* obsolete */ #define DPC_ARRAY_STATUS 0x6 /* obsolete */ #define DPC_ELEM_DESC 0x7 #define DPC_SHORT_ENC_STATUS 0x8 #define DPC_ENC_BUSY 0x9 #define DPC_ADD_ELEM_STATUS 0xa #define DPC_SUBENC_HELP_TEXT 0xb #define DPC_SUBENC_STRING 0xc #define DPC_SUPPORTED_SES 0xd #define DPC_DOWNLOAD_MICROCODE 0xe #define DPC_SUBENC_NICKNAME 0xf /* Element Type codes */ #define UNSPECIFIED_ETC 0x0 #define DEVICE_ETC 0x1 #define POWER_SUPPLY_ETC 0x2 #define COOLING_ETC 0x3 #define TEMPERATURE_ETC 0x4 #define DOOR_ETC 0x5 /* prior to ses3r05 was DOOR_LOCK_ETC */ #define AUD_ALARM_ETC 0x6 #define ENC_ELECTRONICS_ETC 0x7 #define SCC_CELECTR_ETC 0x8 #define NV_CACHE_ETC 0x9 #define INV_OP_REASON_ETC 0xa #define UI_POWER_SUPPLY_ETC 0xb #define DISPLAY_ETC 0xc #define KEY_PAD_ETC 0xd #define ENCLOSURE_ETC 0xe #define SCSI_PORT_TRAN_ETC 0xf #define LANGUAGE_ETC 0x10 #define COMM_PORT_ETC 0x11 #define VOLT_SENSOR_ETC 0x12 #define CURR_SENSOR_ETC 0x13 #define SCSI_TPORT_ETC 0x14 #define SCSI_IPORT_ETC 0x15 #define SIMPLE_SUBENC_ETC 0x16 #define ARRAY_DEV_ETC 0x17 #define SAS_EXPANDER_ETC 0x18 #define SAS_CONNECTOR_ETC 0x19 #define LAST_ETC SAS_CONNECTOR_ETC /* adjust as necessary */ #define NUM_ETC (LAST_ETC + 1) struct element_type_t { int elem_type_code; const char * abbrev; const char * desc; }; struct opts_t { int byte1; int byte1_given; int do_control; int do_data; int dev_slot_num; int enumerate; int eiioe_auto; int eiioe_force; int do_filter; int do_help; int do_hex; int ind_given; int ind_th; /* type header index */ int ind_indiv; /* individual element index; -1 for overall */ int ind_et_inst; /* ETs can have multiple type header instances */ int inner_hex; int do_join; int do_list; int mask_ign; /* element read-mask-modify-write actions */ int maxlen; int seid; int seid_given; int page_code; int page_code_given; int do_raw; int o_readonly; int do_status; int verbose; int do_version; int warn; int num_cgs; int arr_len; unsigned char sas_addr[8]; unsigned char data_arr[MX_DATA_IN + 16]; const char * clear_str; const char * desc_name; const char * get_str; const char * set_str; const char * dev_name; const char * index_str; const char * nickname_str; const struct element_type_t * ind_etp; }; struct diag_page_code { int page_code; const char * desc; }; struct diag_page_abbrev { const char * abbrev; int page_code; }; /* The Configuration diagnostic page contains one or more of these. The * elements of the Enclosure Control/Status and Threshold In/ Out page follow * this format. The additional element status page is closely related to * this format (with some element types and all overall elements excluded). */ struct type_desc_hdr_t { unsigned char etype; /* element type code (0: unspecified) */ unsigned char num_elements; /* number of possible elements, excluding * overall element */ unsigned char se_id; /* subenclosure id (0 for primary enclosure) */ unsigned char txt_len; /* type descriptor text length; (unused) */ }; /* A SQL-like join of the Enclosure Status, Threshold In and Additional * Element Status pages based of the format indicated in the Configuration * page. */ struct join_row_t { int el_ind_th; /* type header index (origin 0) */ int el_ind_indiv; /* individual element index, -1 for overall * instance, otherwise origin 0 */ unsigned char etype; /* element type */ unsigned char se_id; /* subenclosure id (0 for primary enclosure) */ int ei_asc; /* element index used by Additional Element * Status page, -1 for not applicable */ int ei_asc2; /* some vendors get ei_asc wrong, this is * their broken version */ /* following point into Element Descriptor, Enclosure Status, Threshold * In and Additional element status diagnostic pages. enc_statp only * NULL past last, other pointers can be NULL . */ unsigned char * elem_descp; unsigned char * enc_statp; /* NULL indicates past last */ unsigned char * thresh_inp; unsigned char * add_elem_statp; int dev_slot_num; /* if not available, set to -1 */ unsigned char sas_addr[8]; /* if not available, set to 0 */ }; /* Representation of [=] or * :[:][=]. */ struct tuple_acronym_val { const char * acron; const char * val_str; int start_byte; /* -1 indicates no start_byte */ int start_bit; int num_bits; int64_t val; }; /* Mapping from to :: for a * given element type. */ struct acronym2tuple { const char * acron; /* element name or acronym, NULL for past end */ int etype; /* -1 for all element types */ int start_byte; /* origin 0, normally 0 to 3 */ int start_bit; /* 7 (MSB or rightmost in SES drafts) to 0 (LSB) */ int num_bits; /* usually 1 */ const char * info; /* optional, set to NULL if not used */ }; /* Structure for holding (sub-)enclosure information found in the * Configuration diagnostic page. */ struct enclosure_info { int have_info; int rel_esp_id; /* relative enclosure services process id (origin 1) */ int num_esp; /* number of enclosure services processes */ unsigned char enc_log_id[8]; /* 8 byte NAA */ unsigned char enc_vendor_id[8]; /* may differ from INQUIRY response */ unsigned char product_id[16]; /* may differ from INQUIRY response */ unsigned char product_rev_level[4]; /* may differ from INQUIRY response */ }; static struct type_desc_hdr_t type_desc_hdr_arr[MX_ELEM_HDR]; static struct join_row_t join_arr[MX_JOIN_ROWS]; static struct join_row_t * join_arr_lastp = join_arr + MX_JOIN_ROWS - 1; #ifdef SG_LIB_FREEBSD #include /* contains PAGE_SIZE */ static unsigned char enc_stat_rsp[MX_ALLOC_LEN] __attribute__ ((aligned (PAGE_SIZE))); static unsigned char elem_desc_rsp[MX_ALLOC_LEN] __attribute__ ((aligned (PAGE_SIZE))); static unsigned char add_elem_rsp[MX_ALLOC_LEN] __attribute__ ((aligned (PAGE_SIZE))); static unsigned char threshold_rsp[MX_ALLOC_LEN] __attribute__ ((aligned (PAGE_SIZE))); #else static unsigned char enc_stat_rsp[MX_ALLOC_LEN]; static unsigned char elem_desc_rsp[MX_ALLOC_LEN]; static unsigned char add_elem_rsp[MX_ALLOC_LEN]; static unsigned char threshold_rsp[MX_ALLOC_LEN]; #endif static int enc_stat_rsp_len; static int elem_desc_rsp_len; static int add_elem_rsp_len; static int threshold_rsp_len; /* Diagnostic page names, control and/or status (in and/or out) */ static struct diag_page_code dpc_arr[] = { {DPC_SUPPORTED, "Supported Diagnostic Pages"}, /* 0 */ {DPC_CONFIGURATION, "Configuration (SES)"}, {DPC_ENC_STATUS, "Enclosure Status/Control (SES)"}, {DPC_HELP_TEXT, "Help Text (SES)"}, {DPC_STRING, "String In/Out (SES)"}, {DPC_THRESHOLD, "Threshold In/Out (SES)"}, {DPC_ARRAY_STATUS, "Array Status/Control (SES, obsolete)"}, {DPC_ELEM_DESC, "Element Descriptor (SES)"}, {DPC_SHORT_ENC_STATUS, "Short Enclosure Status (SES)"}, /* 8 */ {DPC_ENC_BUSY, "Enclosure Busy (SES-2)"}, {DPC_ADD_ELEM_STATUS, "Additional Element Status (SES-2)"}, {DPC_SUBENC_HELP_TEXT, "Subenclosure Help Text (SES-2)"}, {DPC_SUBENC_STRING, "Subenclosure String In/Out (SES-2)"}, {DPC_SUPPORTED_SES, "Supported SES Diagnostic Pages (SES-2)"}, {DPC_DOWNLOAD_MICROCODE, "Download Microcode (SES-2)"}, {DPC_SUBENC_NICKNAME, "Subenclosure Nickname (SES-2)"}, {0x3f, "Protocol Specific (SAS transport)"}, {0x40, "Translate Address (SBC)"}, {0x41, "Device Status (SBC)"}, {0x42, "Rebuild Assist (SBC)"}, /* sbc3r31 */ {-1, NULL}, }; /* Diagnostic page names, for status (or in) pages */ static struct diag_page_code in_dpc_arr[] = { {DPC_SUPPORTED, "Supported Diagnostic Pages"}, /* 0 */ {DPC_CONFIGURATION, "Configuration (SES)"}, {DPC_ENC_STATUS, "Enclosure Status (SES)"}, {DPC_HELP_TEXT, "Help Text (SES)"}, {DPC_STRING, "String In (SES)"}, {DPC_THRESHOLD, "Threshold In (SES)"}, {DPC_ARRAY_STATUS, "Array Status (SES, obsolete)"}, {DPC_ELEM_DESC, "Element Descriptor (SES)"}, {DPC_SHORT_ENC_STATUS, "Short Enclosure Status (SES)"}, /* 8 */ {DPC_ENC_BUSY, "Enclosure Busy (SES-2)"}, {DPC_ADD_ELEM_STATUS, "Additional Element Status (SES-2)"}, {DPC_SUBENC_HELP_TEXT, "Subenclosure Help Text (SES-2)"}, {DPC_SUBENC_STRING, "Subenclosure String In (SES-2)"}, {DPC_SUPPORTED_SES, "Supported SES Diagnostic Pages (SES-2)"}, {DPC_DOWNLOAD_MICROCODE, "Download Microcode (SES-2)"}, {DPC_SUBENC_NICKNAME, "Subenclosure Nickname (SES-2)"}, {0x3f, "Protocol Specific (SAS transport)"}, {0x40, "Translate Address (SBC)"}, {0x41, "Device Status (SBC)"}, {0x42, "Rebuild Assist Input (SBC)"}, {-1, NULL}, }; /* Diagnostic page names, for control (or out) pages */ static struct diag_page_code out_dpc_arr[] = { {DPC_SUPPORTED, "?? [Supported Diagnostic Pages]"}, /* 0 */ {DPC_CONFIGURATION, "?? [Configuration (SES)]"}, {DPC_ENC_CONTROL, "Enclosure Control (SES)"}, {DPC_HELP_TEXT, "Help Text (SES)"}, {DPC_STRING, "String Out (SES)"}, {DPC_THRESHOLD, "Threshold Out (SES)"}, {DPC_ARRAY_CONTROL, "Array Control (SES, obsolete)"}, {DPC_ELEM_DESC, "?? [Element Descriptor (SES)]"}, {DPC_SHORT_ENC_STATUS, "?? [Short Enclosure Status (SES)]"}, /* 8 */ {DPC_ENC_BUSY, "?? [Enclosure Busy (SES-2)]"}, {DPC_ADD_ELEM_STATUS, "?? [Additional Element Status (SES-2)]"}, {DPC_SUBENC_HELP_TEXT, "?? [Subenclosure Help Text (SES-2)]"}, {DPC_SUBENC_STRING, "Subenclosure String Out (SES-2)"}, {DPC_SUPPORTED_SES, "?? [Supported SES Diagnostic Pages (SES-2)]"}, {DPC_DOWNLOAD_MICROCODE, "Download Microcode (SES-2)"}, {DPC_SUBENC_NICKNAME, "Subenclosure Nickname (SES-2)"}, {0x3f, "Protocol Specific (SAS transport)"}, {0x40, "Translate Address (SBC)"}, {0x41, "Device Status (SBC)"}, {0x42, "Rebuild Assist Output (SBC)"}, {-1, NULL}, }; static struct diag_page_abbrev dp_abbrev[] = { {"ac", DPC_ARRAY_CONTROL}, {"aes", DPC_ADD_ELEM_STATUS}, {"as", DPC_ARRAY_STATUS}, {"cf", DPC_CONFIGURATION}, {"dm", DPC_DOWNLOAD_MICROCODE}, {"eb", DPC_ENC_BUSY}, {"ec", DPC_ENC_CONTROL}, {"ed", DPC_ELEM_DESC}, {"es", DPC_ENC_STATUS}, {"ht", DPC_HELP_TEXT}, {"sdp", DPC_SUPPORTED}, {"ses", DPC_SHORT_ENC_STATUS}, {"sht", DPC_SUBENC_HELP_TEXT}, {"snic", DPC_SUBENC_NICKNAME}, {"ssp", DPC_SUPPORTED_SES}, {"sstr", DPC_SUBENC_STRING}, {"str", DPC_STRING}, {"th", DPC_THRESHOLD}, {NULL, -1}, }; /* Names of element types used by the Enclosure Control/Status diagnostic * page. */ static struct element_type_t element_type_arr[] = { {UNSPECIFIED_ETC, "un", "Unspecified"}, {DEVICE_ETC, "dev", "Device slot"}, {POWER_SUPPLY_ETC, "ps", "Power supply"}, {COOLING_ETC, "coo", "Cooling"}, {TEMPERATURE_ETC, "ts", "Temperature sensor"}, {DOOR_ETC, "do", "Door"}, /* prior to ses3r05 was 'dl' (for Door Lock) but the "Lock" has been dropped */ {AUD_ALARM_ETC, "aa", "Audible alarm"}, {ENC_ELECTRONICS_ETC, "esc", "Enclosure services controller electronics"}, {SCC_CELECTR_ETC, "sce", "SCC controller electronics"}, {NV_CACHE_ETC, "nc", "Nonvolatile cache"}, {INV_OP_REASON_ETC, "ior", "Invalid operation reason"}, {UI_POWER_SUPPLY_ETC, "ups", "Uninterruptible power supply"}, {DISPLAY_ETC, "dis", "Display"}, {KEY_PAD_ETC, "kpe", "Key pad entry"}, {ENCLOSURE_ETC, "enc", "Enclosure"}, {SCSI_PORT_TRAN_ETC, "sp", "SCSI port/transceiver"}, {LANGUAGE_ETC, "lan", "Language"}, {COMM_PORT_ETC, "cp", "Communication port"}, {VOLT_SENSOR_ETC, "vs", "Voltage sensor"}, {CURR_SENSOR_ETC, "cs", "Current sensor"}, {SCSI_TPORT_ETC, "stp", "SCSI target port"}, {SCSI_IPORT_ETC, "sip", "SCSI initiator port"}, {SIMPLE_SUBENC_ETC, "ss", "Simple subenclosure"}, {ARRAY_DEV_ETC, "arr", "Array device slot"}, {SAS_EXPANDER_ETC, "sse", "SAS expander"}, {SAS_CONNECTOR_ETC, "ssc", "SAS connector"}, {-1, NULL, NULL}, }; static struct element_type_t element_type_by_code = {0, NULL, "element type code form"}; /* Many control element names below have "RQST" in front in drafts. These are for the Enclosure Control/Status diagnostic page */ static struct acronym2tuple ecs_a2t_arr[] = { {"active", DEVICE_ETC, 2, 7, 1, NULL}, /* for control only */ {"active", ARRAY_DEV_ETC, 2, 7, 1, NULL}, /* for control only */ {"conscheck", ARRAY_DEV_ETC, 1, 4, 1, "consistency check"}, {"disable", -1, 0, 5, 1, NULL}, /* -1 is for all element types */ {"devoff", DEVICE_ETC, 3, 4, 1, NULL}, /* device off */ {"devoff", ARRAY_DEV_ETC, 3, 4, 1, NULL}, {"dnr", DEVICE_ETC, 2, 6, 1, "do not remove"}, {"dnr", ARRAY_DEV_ETC, 2, 6, 1, "do not remove"}, {"fail", SAS_CONNECTOR_ETC, 3, 6, 1, NULL}, {"fault", DEVICE_ETC, 3, 5, 1, NULL}, {"fault", ARRAY_DEV_ETC, 3, 5, 1, NULL}, {"hotspare", ARRAY_DEV_ETC, 1, 5, 1, NULL}, {"ident", DEVICE_ETC, 2, 1, 1, "flash LED"}, {"ident", ARRAY_DEV_ETC, 2, 1, 1, "flash LED"}, {"ident", POWER_SUPPLY_ETC, 1, 7, 1, "flash LED"}, {"ident", COOLING_ETC, 1, 7, 1, "flash LED"}, {"ident", ENCLOSURE_ETC, 1, 7, 1, "flash LED"}, {"ident", AUD_ALARM_ETC, 1, 7, 1, NULL}, {"ident", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"}, {"incritarray", ARRAY_DEV_ETC, 1, 3, 1, NULL}, {"infailedarray", ARRAY_DEV_ETC, 1, 2, 1, NULL}, {"info", AUD_ALARM_ETC, 3, 3, 1, "emits warning tone when set"}, {"insert", DEVICE_ETC, 2, 3, 1, NULL}, {"insert", ARRAY_DEV_ETC, 2, 3, 1, NULL}, {"locate", DEVICE_ETC, 2, 1, 1, "flash LED"}, {"locate", ARRAY_DEV_ETC, 2, 1, 1, "flash LED"}, {"locate", POWER_SUPPLY_ETC, 1, 7, 1, "flash LED"}, {"locate", COOLING_ETC, 1, 7, 1, "flash LED"}, {"locate", ENCLOSURE_ETC, 1, 7, 1, "flash LED"}, {"locate", SAS_CONNECTOR_ETC, 1, 7, 1, "flash LED"}, {"missing", DEVICE_ETC, 2, 4, 1, NULL}, {"missing", ARRAY_DEV_ETC, 2, 4, 1, NULL}, {"ok", ARRAY_DEV_ETC, 1, 7, 1, NULL}, {"on", POWER_SUPPLY_ETC, 3, 5, 1, "0: turn (remain) off; 1: turn on"}, {"overcurrent", POWER_SUPPLY_ETC, 2, 1, 1, "DC overcurrent"}, {"overcurrent", SAS_CONNECTOR_ETC, 3, 5, 1, NULL}, /* added ses3r07 */ {"locate", DEVICE_ETC, 2, 1, 1, NULL}, {"locate", ARRAY_DEV_ETC, 2, 1, 1, NULL}, {"pow_cycle", ENCLOSURE_ETC, 2, 7, 2, "0: no; 1: start in pow_c_delay minutes; 2: cancel"}, {"pow_c_delay", ENCLOSURE_ETC, 2, 5, 6, "delay in minutes before starting power cycle"}, {"prdfail", -1, 0, 6, 1, "predict failure"}, {"rebuildremap", ARRAY_DEV_ETC, 1, 1, 1, NULL}, {"remove", DEVICE_ETC, 2, 2, 1, NULL}, {"remove", ARRAY_DEV_ETC, 2, 2, 1, NULL}, {"rrabort", ARRAY_DEV_ETC, 1, 0, 1, "rebuild/remap abort"}, {"rsvddevice", ARRAY_DEV_ETC, 1, 6, 1, "reserved device"}, {"speed_act", COOLING_ETC, 1, 2, 11, "actual speed (rpm / 10)"}, {"speed_code", COOLING_ETC, 3, 2, 3, "0: leave; 1: lowest... 7: highest"}, {"swap", -1, 0, 4, 1, NULL}, /* Reset swap */ {NULL, 0, 0, 0, 0, NULL}, }; /* These are for the Threshold in/out diagnostic page */ static struct acronym2tuple th_a2t_arr[] = { {"high_crit", -1, 0, 7, 8, NULL}, {"high_warn", -1, 1, 7, 8, NULL}, {"low_crit", -1, 2, 7, 8, NULL}, {"low_warn", -1, 3, 7, 8, NULL}, {NULL, 0, 0, 0, 0, NULL}, }; /* These are for the Additional element status diagnostic page for SAS with * the EIP bit set. First phy only. Index from start of AES descriptor */ static struct acronym2tuple ae_sas_a2t_arr[] = { {"at_sas_addr", -1, 12, 7, 64, NULL}, /* best viewed with --hex --get= */ /* typically this is the expander's SAS address */ {"dev_type", -1, 8, 6, 3, "1: SAS/SATA dev, 2: expander"}, {"dsn", -1, 7, 7, 8, "device slot number (255: none)"}, {"num_phys", -1, 4, 7, 8, "number of phys"}, {"phy_id", -1, 28, 7, 8, NULL}, {"sas_addr", -1, 20, 7, 64, NULL}, /* should be disk or tape ... */ {"sata_dev", -1, 11, 0, 1, NULL}, {"sata_port_sel", -1, 11, 7, 1, NULL}, {"smp_init", -1, 10, 1, 1, NULL}, {"smp_targ", -1, 11, 1, 1, NULL}, {"ssp_init", -1, 10, 3, 1, NULL}, {"ssp_targ", -1, 11, 3, 1, NULL}, {"stp_init", -1, 10, 2, 1, NULL}, {"stp_targ", -1, 11, 2, 1, NULL}, {NULL, 0, 0, 0, 0, NULL}, }; /* Boolean array of element types of interest to the Additional Element * Status page. Indexed by element type (0 <= et <= 32). */ static int active_et_aesp_arr[NUM_ACTIVE_ET_AESP_ARR] = { 0, 1 /* dev */, 0, 0, 0, 0, 0, 1 /* esce */, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /* starg */, 1 /* sinit */, 0, 1 /* arr */, 1 /* sas exp */, 0, 0, 0, 0, 0, 0, 0, }; /* Command line long option names with corresponding short letter. */ static struct option long_options[] = { {"byte1", required_argument, 0, 'b'}, {"clear", required_argument, 0, 'C'}, {"control", no_argument, 0, 'c'}, {"data", required_argument, 0, 'd'}, {"descriptor", required_argument, 0, 'D'}, {"dev-slot-num", required_argument, 0, 'x'}, {"dsn", required_argument, 0, 'x'}, {"eiioe", required_argument, 0, 'E'}, {"enumerate", no_argument, 0, 'e'}, {"filter", no_argument, 0, 'f'}, {"get", required_argument, 0, 'G'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"index", required_argument, 0, 'I'}, {"inner-hex", no_argument, 0, 'i'}, {"join", no_argument, 0, 'j'}, {"list", no_argument, 0, 'l'}, {"nickid", required_argument, 0, 'N'}, {"nickname", required_argument, 0, 'n'}, {"mask", required_argument, 0, 'M'}, {"maxlen", required_argument, 0, 'm'}, {"page", required_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"readonly", no_argument, 0, 'R'}, {"sas-addr", required_argument, 0, 'A'}, {"set", required_argument, 0, 'S'}, {"status", no_argument, 0, 's'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; /* For overzealous SES device servers that don't like some status elements * sent back as control elements. This table is as per ses3r06. */ static uint8_t ses3_element_cmask_arr[NUM_ETC][4] = { /* Element type code (ETC) names; comment */ {0x40, 0xff, 0xff, 0xff}, /* [0] unspecified */ {0x40, 0, 0x4e, 0x3c}, /* DEVICE */ {0x40, 0x80, 0, 0x60}, /* POWER_SUPPLY */ {0x40, 0x80, 0, 0x60}, /* COOLING; requested speed as is unless */ {0x40, 0xc0, 0, 0}, /* TEMPERATURE */ {0x40, 0xc0, 0, 0x1}, /* DOOR */ {0x40, 0xc0, 0, 0x5f}, /* AUD_ALARM */ {0x40, 0xc0, 0x1, 0}, /* ENC_ELECTRONICS */ {0x40, 0xc0, 0, 0}, /* SCC_CELECTR */ {0x40, 0xc0, 0, 0}, /* NV_CACHE */ {0x40, 0, 0, 0}, /* [10] INV_OP_REASON */ {0x40, 0, 0, 0xc0}, /* UI_POWER_SUPPLY */ {0x40, 0xc0, 0xff, 0xff}, /* DISPLAY */ {0x40, 0xc3, 0, 0}, /* KEY_PAD */ {0x40, 0x80, 0, 0xff}, /* ENCLOSURE */ {0x40, 0xc0, 0, 0x10}, /* SCSI_PORT_TRAN */ {0x40, 0x80, 0xff, 0xff}, /* LANGUAGE */ {0x40, 0xc0, 0, 0x1}, /* COMM_PORT */ {0x40, 0xc0, 0, 0}, /* VOLT_SENSOR */ {0x40, 0xc0, 0, 0}, /* CURR_SENSOR */ {0x40, 0xc0, 0, 0x1}, /* [20] SCSI_TPORT */ {0x40, 0xc0, 0, 0x1}, /* SCSI_IPORT */ {0x40, 0xc0, 0, 0}, /* SIMPLE_SUBENC */ {0x40, 0xff, 0x4e, 0x3c}, /* ARRAY */ {0x40, 0xc0, 0, 0}, /* SAS_EXPANDER */ {0x40, 0x80, 0, 0x40}, /* SAS_CONNECTOR */ }; static int read_hex(const char * inp, unsigned char * arr, int * arr_len, int verb); static int strcase_eq(const char * s1p, const char * s2p); static void enumerate_diag_pages(void); static int saddr_non_zero(const unsigned char * ucp); #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage(int help_num) { if (1 == help_num) { pr2serr("Usage: " "sg_ses [--byte1=B1] [--clear=STR] [--control] [--data=H,H...]\n" " [--descriptor=DN] [--dev-slot-num=SN] " "[--eiioe=A_F]\n" " [--enumerate] [--filter] [--get=STR] [--help] " "[--hex]\n" " [--index=IIA | =TIA,II] [--inner-hex] " "[--join] [--list]\n" " [--mask] [--maxlen=LEN] [--nickname=SEN] " "[--nickid=SEID]\n" " [--page=PG] [--raw] [--sas-addr=SA] [--set=STR] " "[--status]\n" " [--verbose] [--version] [--warn] DEVICE\n" " where the main options are:\n" " --clear=STR|-C STR clear field by acronym or position\n" " --descriptor=DN|-D DN descriptor name (for indexing)\n" " --dev-slot-num=SN|--dsn=SN|-x SN device slot number " "(for indexing)\n" " --eiioe=A_F|-E A_F where A_F is either 'auto' or 'force'." "'force'\n" " acts as if EIIOE is set, 'auto' tries " "to guess\n" " --enumerate|-e enumerate page names + element types " "(ignore\n" " DEVICE). Use twice for clear,get,set " "acronyms\n" " --filter|-f filter out enclosure status flags that " "are clear\n" " use twice for status=okay entries " "only\n" " --get=STR|-G STR get value of field by acronym or " "position\n" " --help|-h print out usage message, use twice for " "additional\n" " --index=IIA|-I IIA individual index ('-1' for overall) " "or element\n" " type abbreviation (e.g. 'arr')\n" " --index=TIA,II|-I TIA,II comma separated pair: TIA is " "type header\n" " index or element type " "abbreviation;\n" " II is individual index ('-1' " "for overall)\n" ); pr2serr( " --join|-j group Enclosure Status, Element " "Descriptor\n" " and Additional Element Status pages. " "Use twice\n" " to add Threshold In page\n" " --page=PG|-p PG diagnostic page code (abbreviation " "or number)\n" " (def: 'ssp' [0x0] (supported diagnostic " "pages))\n" " --sas-addr=SA|-A SA SAS address in hex (for indexing)\n" " --set=STR|-S STR set value of field by acronym or " "position\n\n" "Fetches status or sends control data to a SCSI enclosure. Use " "'-hh' for\nmore help, including the options not shown here.\n"); } else { /* for '-hh' or '--help --help' */ pr2serr( " where the remaining sg_ses options are:\n" " --byte1=B1|-b B1 byte 1 (2nd byte) of control page set " "to B1\n" " --control|-c send control information (def: fetch " "status)\n" " --data=H,H...|-d H,H... string of ASCII hex bytes for " "control pages\n" " --data=- | -d - fetch string of ASCII hex bytes from " "stdin\n" " --data=@FN | -d @FN fetch string of ASCII hex bytes from " "file: FN\n" " --hex|-H print page response (or field) in hex\n" " --inner-hex|-i print innermost level of a" " status page in hex\n" " --list|-l same as '--enumerate' option\n" " --mask|-M ignore status element mask in modify " "actions\n" " (e.g.--set= and --clear=) (def: apply " "mask)\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " --nickname=SEN|-n SEN SEN is new subenclosure nickname\n" " --nickid=SEID|-N SEID SEID is subenclosure identifier " "(def: 0)\n" " used to specify which nickname to " "change\n" " --raw|-r print status page in ASCII hex suitable " "for '-d';\n" " when used twice outputs page in binary " "to stdout\n" " --readonly|-R open DEVICE read-only (def: " "read-write)\n" " --status|-s fetch status information (default " "action)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n" " --warn|-w warn about join (and other) issues\n\n" "If no options are given then DEVICE's supported diagnostic " "pages are\nlisted. STR can be ':" "[:][=]'\nor '[=val]'. Element type " "abbreviations may be followed by a\nnumber (e.g. 'ps1' is " "the second power supply element type). Use\n'sg_ses -e' and " "'sg_ses -ee' for more information.\n\n" ); pr2serr( "Low level indexing can be done with one of the two '--index=' " "options.\nAlternatively, medium level indexing can be done " "with either the\n'--descriptor=', 'dev-slot-num=' or " "'--sas-addr=' options. Support for\nthe medium level options " "in the SES device is itself optional. The\nmedium level " "options implicitly set '--join'.\n" ); } } /* Return 0 for okay, else an error */ static int parse_index(struct opts_t *op) { int n; const char * cp; char * mallcp; char * c2p; const struct element_type_t * etp; char b[64]; op->ind_given = 1; if ((cp = strchr(op->index_str, ','))) { if (0 == strcmp("-1", cp + 1)) n = -1; else { n = sg_get_num(cp + 1); if ((n < 0) || (n > 255)) { pr2serr("bad argument to '--index', after comma expect " "number from -1 to 255\n"); return SG_LIB_SYNTAX_ERROR; } } op->ind_indiv = n; n = cp - op->index_str; if (n >= (int)sizeof(b)) { pr2serr("bad argument to '--index', string prior to comma too " "long\n"); return SG_LIB_SYNTAX_ERROR; } } else { n = strlen(op->index_str); if (n >= (int)sizeof(b)) { pr2serr("bad argument to '--index', string too long\n"); return SG_LIB_SYNTAX_ERROR; } } strncpy(b, op->index_str, n); b[n] = '\0'; if (0 == strcmp("-1", b)) { if (cp) { pr2serr("bad argument to '--index', unexpected '-1' type header " "index\n"); return SG_LIB_SYNTAX_ERROR; } op->ind_th = 0; op->ind_indiv = -1; } else if (isdigit(b[0])) { n = sg_get_num(b); if ((n < 0) || (n > 255)) { pr2serr("bad numeric argument to '--index', expect number from 0 " "to 255\n"); return SG_LIB_SYNTAX_ERROR; } if (cp) op->ind_th = n; else { op->ind_th = 0; op->ind_indiv = n; } } else if ('_' == b[0]) { if ((c2p = strchr(b + 1, '_'))) *c2p = '\0'; n = sg_get_num(b + 1); if ((n < 0) || (n > 255)) { pr2serr("bad element type code for '--index', expect value from " "0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } element_type_by_code.elem_type_code = n; mallcp = (char *)malloc(8); /* willfully forget about freeing this */ mallcp[0] = '_'; snprintf(mallcp + 1, 6, "%d", n); element_type_by_code.abbrev = mallcp; if (c2p) { n = sg_get_num(c2p + 1); if ((n < 0) || (n > 255)) { pr2serr("bad element type code for '--index', expect " " from 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->ind_et_inst = n; } op->ind_etp = &element_type_by_code; if (NULL == cp) op->ind_indiv = -1; } else { /* element type abbreviation perhaps followed by */ int blen = strlen(b); for (etp = element_type_arr; etp->desc; ++etp) { n = strlen(etp->abbrev); if ((n == blen) && (0 == strncmp(b, etp->abbrev, n))) break; } if (NULL == etp->desc) { pr2serr("bad element type abbreviation [%s] for '--index'\n" "use '--enumerate' to see possibles\n", b); return SG_LIB_SYNTAX_ERROR; } if ((int)strlen(b) > n) { n = sg_get_num(b + n); if ((n < 0) || (n > 255)) { pr2serr("bad element type abbreviation for '--index', " "expect from 0 to 255\n"); return SG_LIB_SYNTAX_ERROR; } op->ind_et_inst = n; } op->ind_etp = etp; if (NULL == cp) op->ind_indiv = -1; } if (op->verbose > 1) { if (op->ind_etp) pr2serr(" element type abbreviation: %s, etp_num=%d, " "individual index=%d\n", op->ind_etp->abbrev, op->ind_et_inst, op->ind_indiv); else pr2serr(" type header index=%d, individual index=%d\n", op->ind_th, op->ind_indiv); } return 0; } /* process command line options and argument. Returns 0 if ok. */ static int cl_process(struct opts_t *op, int argc, char *argv[]) { int c, j, ret, ff; const char * data_arg = NULL; uint64_t saddr; const char * cp; op->dev_slot_num = -1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "A:b:cC:d:D:eE:fG:hHiI:jln:N:m:Mp:rRsS:v" "Vwx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'A': /* SAS address, assumed to be hex */ cp = optarg; if ((strlen(optarg) > 2) && ('X' == toupper(optarg[1]))) cp = optarg + 2; if (1 != sscanf(cp, "%" SCNx64 "", &saddr)) { pr2serr("bad argument to '--sas-addr'\n"); return SG_LIB_SYNTAX_ERROR; } for (j = 7, ff = 1; j >= 0; --j) { if (ff & (0xff != (saddr & 0xff))) ff = 0; op->sas_addr[j] = (saddr & 0xff); saddr >>= 8; } if (ff) { pr2serr("decode error from argument to '--sas-addr'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'b': op->byte1 = sg_get_num(optarg); if ((op->byte1 < 0) || (op->byte1 > 255)) { pr2serr("bad argument to '--byte1' (0 to 255 inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } ++op->byte1_given; break; case 'c': ++op->do_control; break; case 'C': op->clear_str = optarg; ++op->num_cgs; break; case 'd': data_arg = optarg; op->do_data = 1; break; case 'D': op->desc_name = optarg; break; case 'e': ++op->enumerate; break; case 'E': if (0 == strcmp("auto", optarg)) ++op->eiioe_auto; else if (0 == strcmp("force", optarg)) ++op->eiioe_force; else { pr2serr("--eiioe option expects 'auto' or 'force' as an " "argument\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'f': ++op->do_filter; break; case 'G': op->get_str = optarg; ++op->num_cgs; break; case 'h': case '?': ++op->do_help; break; case 'H': ++op->do_hex; break; case 'i': ++op->inner_hex; break; case 'I': op->index_str = optarg; break; case 'j': ++op->do_join; break; case 'l': ++op->do_list; break; case 'n': op->nickname_str = optarg; break; case 'N': op->seid = sg_get_num(optarg); if ((op->seid < 0) || (op->seid > 255)) { pr2serr("bad argument to '--nick_id' (0 to 255 inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } ++op->seid_given; break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > 65535)) { pr2serr("bad argument to '--maxlen' (0 to 65535 " "inclusive expected)\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'M': ++op->mask_ign; break; case 'p': if (isdigit(optarg[0])) { op->page_code = sg_get_num(optarg); if ((op->page_code < 0) || (op->page_code > 255)) { pr2serr("bad argument to '--page' (0 to 255 " "inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } } else { const struct diag_page_abbrev * ap; for (ap = dp_abbrev; ap->abbrev; ++ap) { if (strcase_eq(ap->abbrev, optarg)) { op->page_code = ap->page_code; break; } } if (NULL == ap->abbrev) { pr2serr("'--page' abbreviation %s not found\nHere are " "the choices:\n", optarg); enumerate_diag_pages(); return SG_LIB_SYNTAX_ERROR; } } ++op->page_code_given; break; case 'r': ++op->do_raw; break; case 'R': ++op->o_readonly; break; case 's': ++op->do_status; break; case 'S': op->set_str = optarg; ++op->num_cgs; break; case 'v': ++op->verbose; break; case 'V': ++op->do_version; return 0; case 'w': ++op->warn; break; case 'x': op->dev_slot_num = sg_get_num(optarg); if ((op->dev_slot_num < 0) || (op->dev_slot_num > 255)) { pr2serr("bad argument to '--dev-slot-num' (0 to 255 " "inclusive)\n"); return SG_LIB_SYNTAX_ERROR; } break; default: pr2serr("unrecognised option code 0x%x ??\n", c); goto err_help; } } if (op->do_help) return 0; if (optind < argc) { if (NULL == op->dev_name) { op->dev_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); goto err_help; } } if (data_arg) { memset(op->data_arr, 0, sizeof(op->data_arr)); if (read_hex(data_arg, op->data_arr + 4, &op->arr_len, op->verbose)) { pr2serr("bad argument to '--data'\n"); return SG_LIB_SYNTAX_ERROR; } } if (op->maxlen <= 0) op->maxlen = MX_ALLOC_LEN; if (op->do_join && (op->do_control)) { pr2serr("cannot have '--join' and '--control'\n"); goto err_help; } if (op->num_cgs > 1) { pr2serr("can only be one of '--clear', '--get' and '--set'\n"); goto err_help; } if (op->index_str) { ret = parse_index(op); if (ret) { pr2serr(" For more information use '--help'\n"); return ret; } } if (op->desc_name || (op->dev_slot_num >= 0) || saddr_non_zero(op->sas_addr)) { if (op->ind_given) { pr2serr("cannot have --index with either --descriptor, " "--dev-slot-num or --sas-addr\n"); goto err_help; } if (((!! op->desc_name) + (op->dev_slot_num >= 0) + saddr_non_zero(op->sas_addr)) > 1) { pr2serr("can only have one of --descriptor, " "--dev-slot-num and --sas-addr\n"); return SG_LIB_SYNTAX_ERROR; } if ((0 == op->do_join) && (0 == op->do_control) && (0 == op->num_cgs) && (0 == op->page_code_given)) { ++op->do_join; /* implicit --join */ if (op->verbose) pr2serr("assume --join option is set\n"); } } if (op->ind_given) { if ((0 == op->do_join) && (0 == op->do_control) && (0 == op->num_cgs) && (0 == op->page_code_given)) { ++op->page_code_given; op->page_code = 2; /* implicit status page */ if (op->verbose) pr2serr("assume --page=2 (es) option is set\n"); } } if (op->do_list || op->enumerate) return 0; if (op->do_control && op->do_status) { pr2serr("cannot have both '--control' and '--status'\n"); goto err_help; } else if (op->do_control) { if (op->nickname_str || op->seid_given) ; else if (! op->do_data) { pr2serr("need to give '--data' in control mode\n"); goto err_help; } } else if (0 == op->do_status) op->do_status = 1; /* default to receiving status pages */ if (op->nickname_str) { if (! op->do_control) { pr2serr("since '--nickname=' implies control mode, require " "'--control' as well\n"); return SG_LIB_SYNTAX_ERROR; } if (op->page_code_given) { if (DPC_SUBENC_NICKNAME != op->page_code) { pr2serr("since '--nickname=' assume or expect " "'--page=snic'\n"); return SG_LIB_SYNTAX_ERROR; } } else op->page_code = DPC_SUBENC_NICKNAME; } else if (op->seid_given) { pr2serr("'--nickid=' must be used together with '--nickname='\n"); return SG_LIB_SYNTAX_ERROR; } if ((op->verbose > 4) && saddr_non_zero(op->sas_addr)) { pr2serr(" SAS address (in hex): "); for (j = 0; j < 8; ++j) pr2serr("%02x", op->sas_addr[j]); pr2serr("\n"); } if (NULL == op->dev_name) { pr2serr("missing DEVICE name!\n"); goto err_help; } return 0; err_help: pr2serr(" For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } /* Returns 64 bit signed integer given in either decimal or in hex. The * hex number is either preceded by "0x" or followed by "h". Returns -1 * on error (so check for "-1" string before using this function). */ static int64_t get_llnum(const char * buf) { int res, len; int64_t num; uint64_t unum; if ((NULL == buf) || ('\0' == buf[0])) return -1; len = strlen(buf); if (('0' == buf[0]) && (('x' == buf[1]) || ('X' == buf[1]))) { res = sscanf(buf + 2, "%" SCNx64 "", &unum); num = unum; } else if ('H' == toupper(buf[len - 1])) { res = sscanf(buf, "%" SCNx64 "", &unum); num = unum; } else res = sscanf(buf, "%" SCNd64 "", &num); return (1 == res) ? num : -1; } /* Parse clear/get/set string. Uses 'buff' for scratch area. Returns 0 * on success, else -1. */ static int parse_cgs_str(char * buff, struct tuple_acronym_val * tavp) { char * esp; char * colp; char * cp; unsigned int ui; tavp->acron = NULL; tavp->val_str = NULL; tavp->start_byte = -1; tavp->num_bits = 1; if ((esp = strchr(buff, '='))) { tavp->val_str = esp + 1; *esp = '\0'; if (0 == strcmp("-1", esp + 1)) tavp->val = -1; else { tavp->val = get_llnum(esp + 1); if (-1 == tavp->val) { pr2serr("unable to decode: %s value\n", esp + 1); pr2serr(" expected: [=]\n"); return -1; } } } if (isalpha(buff[0])) tavp->acron = buff; else { colp = strchr(buff, ':'); if ((NULL == colp) || (buff == colp)) return -1; *colp = '\0'; if (('0' == buff[0]) && ('X' == toupper(buff[1]))) { if (1 != sscanf(buff + 2, "%x", &ui)) return -1; tavp->start_byte = ui; } else if ('H' == toupper(*(colp - 1))) { if (1 != sscanf(buff, "%x", &ui)) return -1; tavp->start_byte = ui; } else { if (1 != sscanf(buff, "%d", &tavp->start_byte)) return -1; } if ((tavp->start_byte < 0) || (tavp->start_byte > 127)) { pr2serr(" needs to be between 0 and 127\n"); return -1; } cp = colp + 1; colp = strchr(cp, ':'); if (cp == colp) return -1; if (colp) *colp = '\0'; if (1 != sscanf(cp, "%d", &tavp->start_bit)) return -1; if ((tavp->start_bit < 0) || (tavp->start_bit > 7)) { pr2serr(" needs to be between 0 and 7\n"); return -1; } if (colp) { if (1 != sscanf(colp + 1, "%d", &tavp->num_bits)) return -1; } if ((tavp->num_bits < 1) || (tavp->num_bits > 64)) { pr2serr(" needs to be between 1 and 64\n"); return -1; } } return 0; } /* Fetch diagnostic page name (control or out). Returns NULL if not found. */ static const char * find_out_diag_page_desc(int page_num) { const struct diag_page_code * pcdp; for (pcdp = out_dpc_arr; pcdp->desc; ++pcdp) { if (page_num == pcdp->page_code) return pcdp->desc; else if (page_num < pcdp->page_code) return NULL; } return NULL; } /* Return of 0 -> success, SG_LIB_CAT_* positive values or -1 -> other * failures */ static int do_senddiag(int sg_fd, int pf_bit, void * outgoing_pg, int outgoing_len, int noisy, int verbose) { const char * cp; int page_num; if (outgoing_pg && (verbose > 2)) { page_num = ((const char *)outgoing_pg)[0]; cp = find_out_diag_page_desc(page_num); if (cp) pr2serr(" Send diagnostic cmd name: %s\n", cp); else pr2serr(" Send diagnostic cmd number: 0x%x\n", page_num); } return sg_ll_send_diag(sg_fd, 0 /* sf_code */, pf_bit, 0 /* sf_bit */, 0 /* devofl_bit */, 0 /* unitofl_bit */, 0 /* long_duration */, outgoing_pg, outgoing_len, noisy, verbose); } /* Fetch diagnostic page name (status and/or control). Returns NULL if not * found. */ static const char * find_diag_page_desc(int page_num) { const struct diag_page_code * pcdp; for (pcdp = dpc_arr; pcdp->desc; ++pcdp) { if (page_num == pcdp->page_code) return pcdp->desc; else if (page_num < pcdp->page_code) return NULL; } return NULL; } /* Fetch diagnostic page name (status or in). Returns NULL if not found. */ static const char * find_in_diag_page_desc(int page_num) { const struct diag_page_code * pcdp; for (pcdp = in_dpc_arr; pcdp->desc; ++pcdp) { if (page_num == pcdp->page_code) return pcdp->desc; else if (page_num < pcdp->page_code) return NULL; } return NULL; } /* Fetch element type name. Returns NULL if not found. */ static char * find_element_tname(int elem_type_code, char * b, int mlen_b) { const struct element_type_t * etp; int len; if ((NULL == b) || (mlen_b < 1)) return b; for (etp = element_type_arr; etp->desc; ++etp) { if (elem_type_code == etp->elem_type_code) { len = strlen(etp->desc); if (len < mlen_b) strcpy(b, etp->desc); else { strncpy(b, etp->desc, mlen_b - 1); b[mlen_b - 1] = '\0'; } return b; } else if (elem_type_code < etp->elem_type_code) break; } if (elem_type_code < 0x80) snprintf(b, mlen_b - 1, "[0x%x]", elem_type_code); else snprintf(b, mlen_b - 1, "vendor specific [0x%x]", elem_type_code); b[mlen_b - 1] = '\0'; return b; } /* Returns 1 if el_type (element type) is of interest to the Additional * Element Status page. Otherwise return 0. */ static int active_et_aesp(int el_type) { if ((el_type >= 0) && (el_type < NUM_ACTIVE_ET_AESP_ARR)) return active_et_aesp_arr[el_type]; else return 0; } /* Return of 0 -> success, SG_LIB_CAT_* positive values or -1 -> other * failures */ static int do_rec_diag(int sg_fd, int page_code, unsigned char * rsp_buff, int rsp_buff_size, const struct opts_t * op, int * rsp_lenp) { int rsp_len, res; const char * cp; char b[80]; memset(rsp_buff, 0, rsp_buff_size); if (rsp_lenp) *rsp_lenp = 0; cp = find_in_diag_page_desc(page_code); if (op->verbose > 1) { if (cp) pr2serr(" Receive diagnostic results cmd for %s page\n", cp); else pr2serr(" Receive diagnostic results cmd for page 0x%x\n", page_code); } res = sg_ll_receive_diag(sg_fd, 1 /* pcv */, page_code, rsp_buff, rsp_buff_size, 1, op->verbose); if (0 == res) { rsp_len = (rsp_buff[2] << 8) + rsp_buff[3] + 4; if (rsp_len > rsp_buff_size) { if (rsp_buff_size > 8) /* tried to get more than header */ pr2serr("<<< warning response buffer too small [%d but need " "%d]>>>\n", rsp_buff_size, rsp_len); rsp_len = rsp_buff_size; } if (rsp_lenp) *rsp_lenp = rsp_len; if (page_code != rsp_buff[0]) { if ((0x9 == rsp_buff[0]) && (1 & rsp_buff[1])) { pr2serr("Enclosure busy, try again later\n"); if (op->do_hex) dStrHexErr((const char *)rsp_buff, rsp_len, 0); } else if (0x8 == rsp_buff[0]) { pr2serr("Enclosure only supports Short Enclosure Status: " "0x%x\n", rsp_buff[1]); } else { pr2serr("Invalid response, wanted page code: 0x%x but got " "0x%x\n", page_code, rsp_buff[0]); dStrHexErr((const char *)rsp_buff, rsp_len, 0); } return -2; } return 0; } else if (op->verbose) { if (cp) pr2serr("Attempt to fetch %s diagnostic page failed\n", cp); else pr2serr("Attempt to fetch status diagnostic page [0x%x] failed\n", page_code); sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr(" %s\n", b); } return res; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* DPC_CONFIGURATION [0x1] * Display Configuration diagnostic page. */ static void ses_configuration_sdg(const unsigned char * resp, int resp_len) { int j, k, el, num_subs, sum_elem_types; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; const unsigned char * text_ucp; char b[64]; printf("Configuration diagnostic page:\n"); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ sum_elem_types = 0; last_ucp = resp + resp_len - 1; printf(" number of secondary subenclosures: %d\n", num_subs - 1); gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); printf(" enclosure descriptor list\n"); ucp = resp + 8; for (k = 0; k < num_subs; ++k, ucp += el) { if ((ucp + 3) > last_ucp) goto truncated; el = ucp[3] + 4; sum_elem_types += ucp[2]; printf(" Subenclosure identifier: %d%s\n", ucp[1], (ucp[1] ? "" : " [primary]")); printf(" relative ES process id: %d, number of ES processes" ": %d\n", ((ucp[0] & 0x70) >> 4), (ucp[0] & 0x7)); printf(" number of type descriptor headers: %d\n", ucp[2]); if (el < 40) { pr2serr(" enc descriptor len=%d ??\n", el); continue; } printf(" enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", ucp[4 + j]); printf("\n enclosure vendor: %.8s product: %.16s rev: %.4s\n", ucp + 12, ucp + 20, ucp + 36); if (el > 40) { printf(" vendor-specific data:\n"); /* dStrHex((const char *)(ucp + 40), el - 40, 0); */ printf(" "); for (j = 0; j < (el - 40); ++j) { if ((j > 0) && (0 == (j % 16))) printf("\n "); printf("%02x ", *(ucp + 40 + j)); } printf("\n"); } } /* printf("\n"); */ printf(" type descriptor header/text list\n"); text_ucp = ucp + (sum_elem_types * 4); for (k = 0; k < sum_elem_types; ++k, ucp += 4) { if ((ucp + 3) > last_ucp) goto truncated; printf(" Element type: %s, subenclosure id: %d\n", find_element_tname(ucp[0], b, sizeof(b)), ucp[2]); printf(" number of possible elements: %d\n", ucp[1]); if (ucp[3] > 0) { if (text_ucp > last_ucp) goto truncated; printf(" text: %.*s\n", ucp[3], text_ucp); text_ucp += ucp[3]; } } return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_CONFIGURATION * Returns total number of type descriptor headers written to 'tdhp' or -1 * if there is a problem */ static int populate_type_desc_hdr_arr(int fd, struct type_desc_hdr_t * tdhp, unsigned int * generationp, struct enclosure_info * primary_ip, struct opts_t * op) { int resp_len, k, el, num_subs, sum_type_dheaders, res, n; int ret = 0; unsigned int gen_code; unsigned char * resp; const unsigned char * ucp; const unsigned char * last_ucp; resp = (unsigned char *)calloc(op->maxlen, 1); if (NULL == resp) { pr2serr("populate: unable to allocate %d bytes on heap\n", op->maxlen); ret = -1; goto the_end; } res = do_rec_diag(fd, DPC_CONFIGURATION, resp, op->maxlen, op, &resp_len); if (res) { pr2serr("populate: couldn't read config page, res=%d\n", res); ret = -1; goto the_end; } if (resp_len < 4) { ret = -1; goto the_end; } num_subs = resp[1] + 1; sum_type_dheaders = 0; last_ucp = resp + resp_len - 1; gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; if (generationp) *generationp = gen_code; ucp = resp + 8; for (k = 0; k < num_subs; ++k, ucp += el) { if ((ucp + 3) > last_ucp) goto p_truncated; el = ucp[3] + 4; sum_type_dheaders += ucp[2]; if (el < 40) { pr2serr("populate: short enc descriptor len=%d ??\n", el); continue; } if ((0 == k) && primary_ip) { ++primary_ip->have_info; primary_ip->rel_esp_id = (ucp[0] & 0x70) >> 4; primary_ip->num_esp = (ucp[0] & 0x7); memcpy(primary_ip->enc_log_id, ucp + 4, 8); memcpy(primary_ip->enc_vendor_id, ucp + 12, 8); memcpy(primary_ip->product_id, ucp + 20, 16); memcpy(primary_ip->product_rev_level, ucp + 36, 4); } } for (k = 0; k < sum_type_dheaders; ++k, ucp += 4) { if ((ucp + 3) > last_ucp) goto p_truncated; if (k >= MX_ELEM_HDR) { pr2serr("populate: too many elements\n"); ret = -1; goto the_end; } tdhp[k].etype = ucp[0]; tdhp[k].num_elements = ucp[1]; tdhp[k].se_id = ucp[2]; tdhp[k].txt_len = ucp[3]; } if (op->ind_given && op->ind_etp) { n = op->ind_et_inst; for (k = 0; k < sum_type_dheaders; ++k) { if (op->ind_etp->elem_type_code == tdhp[k].etype) { if (0 == n) break; else --n; } } if (k < sum_type_dheaders) op->ind_th = k; else { if (op->ind_et_inst) pr2serr("populate: unable to find element type '%s%d'\n", op->ind_etp->abbrev, op->ind_et_inst); else pr2serr("populate: unable to find element type '%s'\n", op->ind_etp->abbrev); ret = -1; goto the_end; } } ret = sum_type_dheaders; goto the_end; p_truncated: pr2serr("populate: config too short\n"); ret = -1; the_end: if (resp) free(resp); return ret; } static char * find_sas_connector_type(int conn_type, char * buff, int buff_len) { switch (conn_type) { case 0x0: snprintf(buff, buff_len, "No information"); break; case 0x1: snprintf(buff, buff_len, "SAS 4x receptacle (SFF-8470) " "[max 4 phys]"); break; case 0x2: snprintf(buff, buff_len, "Mini SAS 4x receptacle (SFF-8088) " "[max 4 phys]"); break; case 0x3: snprintf(buff, buff_len, "QSFP+ receptacle (SFF-8436) " "[max 4 phys]"); break; case 0x4: snprintf(buff, buff_len, "Mini SAS 4x active receptacle (SFF-8088) " "[max 4 phys]"); break; case 0x5: snprintf(buff, buff_len, "Mini SAS HD 4x receptacle (SFF-8644) " "[max 4 phys]"); break; case 0x6: snprintf(buff, buff_len, "Mini SAS HD 8x receptacle (SFF-8644) " "[max 8 phys]"); break; case 0x7: snprintf(buff, buff_len, "Mini SAS HD 16x receptacle (SFF-8644) " "[max 16 phys]"); break; case 0xf: snprintf(buff, buff_len, "Vendor specific external connector"); break; case 0x10: snprintf(buff, buff_len, "SAS 4i plug (SFF-8484) [max 4 phys]"); break; case 0x11: snprintf(buff, buff_len, "Mini SAS 4i receptacle (SFF-8087) " "[max 4 phys]"); break; case 0x12: snprintf(buff, buff_len, "Mini SAS HD 4i receptacle (SFF-8643) " "[max 4 phys]"); break; case 0x13: snprintf(buff, buff_len, "Mini SAS HD 8i receptacle (SFF-8643) " "[max 8 phys]"); break; case 0x20: snprintf(buff, buff_len, "SAS Drive backplane receptacle (SFF-8482) " "[max 2 phys]"); break; case 0x21: snprintf(buff, buff_len, "SATA host plug [max 1 phy]"); break; case 0x22: snprintf(buff, buff_len, "SAS Drive plug (SFF-8482) [max 2 phys]"); break; case 0x23: snprintf(buff, buff_len, "SATA device plug [max 1 phy]"); break; case 0x24: snprintf(buff, buff_len, "Micro SAS receptacle [max 2 phys]"); break; case 0x25: snprintf(buff, buff_len, "Micro SATA device plug [max 1 phy]"); break; case 0x26: snprintf(buff, buff_len, "Micro SAS plug (SFF-8486) [max 2 phys]"); break; case 0x27: snprintf(buff, buff_len, "Micro SAS/SATA plug (SFF-8486) " "[max 2 phys]"); break; case 0x2f: snprintf(buff, buff_len, "SAS virtual connector [max 1 phy]"); break; case 0x3f: snprintf(buff, buff_len, "Vendor specific internal connector"); break; default: if (conn_type < 0x10) snprintf(buff, buff_len, "unknown external connector type: 0x%x", conn_type); else if (conn_type < 0x20) snprintf(buff, buff_len, "unknown internal wide connector type: " "0x%x", conn_type); else if (conn_type < 0x30) snprintf(buff, buff_len, "unknown internal connector to end " "device, type: 0x%x", conn_type); else if (conn_type < 0x3f) snprintf(buff, buff_len, "reserved for internal connector, " "type: 0x%x", conn_type); else if (conn_type < 0x70) snprintf(buff, buff_len, "reserved connector type: 0x%x", conn_type); else if (conn_type < 0x80) snprintf(buff, buff_len, "vendor specific connector type: 0x%x", conn_type); else /* conn_type is a 7 bit field, so this is impossible */ snprintf(buff, buff_len, "unexpected connector type: 0x%x", conn_type); break; } return buff; } static const char * elem_status_code_desc[] = { "Unsupported", "OK", "Critical", "Noncritical", "Unrecoverable", "Not installed", "Unknown", "Not available", "No access allowed", "reserved [9]", "reserved [10]", "reserved [11]", "reserved [12]", "reserved [13]", "reserved [14]", "reserved [15]", }; static const char * actual_speed_desc[] = { "stopped", "at lowest speed", "at second lowest speed", "at third lowest speed", "at intermediate speed", "at third highest speed", "at second highest speed", "at highest speed" }; static const char * nv_cache_unit[] = { "Bytes", "KiB", "MiB", "GiB" }; static const char * invop_type_desc[] = { "SEND DIAGNOSTIC page code error", "SEND DIAGNOSTIC page format error", "Reserved", "Vendor specific error" }; static void enc_status_helper(const char * pad, const unsigned char * statp, int etype, const struct opts_t * op) { int res, a, b; char bb[128]; int nofilter = ! op->do_filter; if (op->inner_hex) { printf("%s%02x %02x %02x %02x\n", pad, statp[0], statp[1], statp[2], statp[3]); return; } printf("%sPredicted failure=%d, Disabled=%d, Swap=%d, status: %s\n", pad, !!(statp[0] & 0x40), !!(statp[0] & 0x20), !!(statp[0] & 0x10), elem_status_code_desc[statp[0] & 0xf]); switch (etype) { /* element types */ case UNSPECIFIED_ETC: if (op->verbose) printf("%sstatus in hex: %02x %02x %02x %02x\n", pad, statp[0], statp[1], statp[2], statp[3]); break; case DEVICE_ETC: printf("%sSlot address: %d\n", pad, statp[1]); if (nofilter || (0xe0 & statp[2])) printf("%sApp client bypassed A=%d, Do not remove=%d, Enc " "bypassed A=%d\n", pad, !!(statp[2] & 0x80), !!(statp[2] & 0x40), !!(statp[2] & 0x20)); if (nofilter || (0x1c & statp[2])) printf("%sEnc bypassed B=%d, Ready to insert=%d, RMV=%d, Ident=" "%d\n", pad, !!(statp[2] & 0x10), !!(statp[2] & 0x8), !!(statp[2] & 0x4), !!(statp[2] & 0x2)); if (nofilter || ((1 & statp[2]) || (0xe0 & statp[3]))) printf("%sReport=%d, App client bypassed B=%d, Fault sensed=%d, " "Fault requested=%d\n", pad, !!(statp[2] & 0x1), !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x20)); if (nofilter || (0x1e & statp[3])) printf("%sDevice off=%d, Bypassed A=%d, Bypassed B=%d, Device " "bypassed A=%d\n", pad, !!(statp[3] & 0x10), !!(statp[3] & 0x8), !!(statp[3] & 0x4), !!(statp[3] & 0x2)); if (nofilter || (0x1 & statp[3])) printf("%sDevice bypassed B=%d\n", pad, !!(statp[3] & 0x1)); break; case POWER_SUPPLY_ETC: if (nofilter || ((0x80 & statp[1]) || (0xe & statp[2]))) printf("%sIdent=%d, DC overvoltage=%d, DC undervoltage=%d, DC " "overcurrent=%d\n", pad, !!(statp[1] & 0x80), !!(statp[2] & 0x8), !!(statp[2] & 0x4), !!(statp[2] & 0x2)); if (nofilter || (0xf8 & statp[3])) printf("%sHot swap=%d, Fail=%d, Requested on=%d, Off=%d, " "Overtmp fail=%d\n", pad, !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x20), !!(statp[3] & 0x10), !!(statp[3] & 0x8)); if (nofilter || (0x7 & statp[3])) printf("%sTemperature warn=%d, AC fail=%d, DC fail=%d\n", pad, !!(statp[3] & 0x4), !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case COOLING_ETC: if (nofilter || ((0xc0 & statp[1]) || (0xf0 & statp[3]))) printf("%sIdent=%d, Hot swap=%d, Fail=%d, Requested on=%d, " "Off=%d\n", pad, !!(statp[1] & 0x80), !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x20), !!(statp[3] & 0x10)); printf("%sActual speed=%d rpm, Fan %s\n", pad, (((0x7 & statp[1]) << 8) + statp[2]) * 10, actual_speed_desc[7 & statp[3]]); break; case TEMPERATURE_ETC: /* temperature sensor */ if (nofilter || ((0xc0 & statp[1]) || (0xf & statp[3]))) { printf("%sIdent=%d, Fail=%d, OT failure=%d, OT warning=%d, " "UT failure=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[3] & 0x8), !!(statp[3] & 0x4), !!(statp[3] & 0x2)); printf("%sUT warning=%d\n", pad, !!(statp[3] & 0x1)); } if (statp[2]) printf("%sTemperature=%d C\n", pad, (int)statp[2] - TEMPERAT_OFF); else printf("%sTemperature: \n", pad); break; case DOOR_ETC: /* OPEN field added in ses3r05 */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[3]))) printf("%sIdent=%d, Fail=%d, Open=%d, Unlock=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case AUD_ALARM_ETC: /* audible alarm */ if (nofilter || ((0xc0 & statp[1]) || (0xd0 & statp[3]))) printf("%sIdent=%d, Fail=%d, Request mute=%d, Mute=%d, " "Remind=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x10)); if (nofilter || (0xf & statp[3])) printf("%sTone indicator: Info=%d, Non-crit=%d, Crit=%d, " "Unrecov=%d\n", pad, !!(statp[3] & 0x8), !!(statp[3] & 0x4), !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case ENC_ELECTRONICS_ETC: /* enclosure services controller electronics */ if (nofilter || (0xc0 & statp[1]) || (0x1 & statp[2]) || (0x80 & statp[3])) printf("%sIdent=%d, Fail=%d, Report=%d, Hot swap=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[2] & 0x1), !!(statp[3] & 0x80)); break; case SCC_CELECTR_ETC: /* SCC controller electronics */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]))) printf("%sIdent=%d, Fail=%d, Report=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[2] & 0x1)); break; case NV_CACHE_ETC: /* Non volatile cache */ res = (statp[2] << 8) + statp[3]; printf("%sIdent=%d, Fail=%d, Size multiplier=%d, Non volatile cache " "size=0x%x\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), (statp[1] & 0x3), res); printf("%sHence non volatile cache size: %d %s\n", pad, res, nv_cache_unit[statp[1] & 0x3]); break; case INV_OP_REASON_ETC: /* Invalid operation reason */ res = ((statp[1] >> 6) & 3); printf("%sInvop type=%d %s\n", pad, res, invop_type_desc[res]); switch (res) { case 0: printf("%sPage not supported=%d\n", pad, (statp[1] & 1)); break; case 1: printf("%sByte offset=%d, bit number=%d\n", pad, (statp[2] << 8) + statp[3], (statp[1] & 7)); break; case 2: case 3: printf("%slast 3 bytes (hex): %02x %02x %02x\n", pad, statp[1], statp[2], statp[3]); break; default: break; } break; case UI_POWER_SUPPLY_ETC: /* Uninterruptible power supply */ if (0 == statp[1]) printf("%sBattery status: discharged or unknown\n", pad); else if (255 == statp[1]) printf("%sBattery status: 255 or more minutes remaining\n", pad); else printf("%sBattery status: %d minutes remaining\n", pad, statp[1]); if (nofilter || (0xf8 & statp[2])) printf("%sAC low=%d, AC high=%d, AC qual=%d, AC fail=%d, DC fail=" "%d\n", pad, !!(statp[2] & 0x80), !!(statp[2] & 0x40), !!(statp[2] & 0x20), !!(statp[2] & 0x10), !!(statp[2] & 0x8)); if (nofilter || ((0x7 & statp[2]) || (0xc3 & statp[3]))) { printf("%sUPS fail=%d, Warn=%d, Intf fail=%d, Ident=%d, Fail=%d, " "Batt fail=%d\n", pad, !!(statp[2] & 0x4), !!(statp[2] & 0x2), !!(statp[2] & 0x1), !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x2)); printf("%sBPF=%d\n", pad, !!(statp[3] & 0x1)); } break; case DISPLAY_ETC: /* Display (ses2r15) */ if (nofilter || (0xc0 & statp[1])) printf("%sIdent=%d, Fail=%d, Display mode status=%d, Display " "character status=0x%x\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), (statp[1] & 0x3), ((statp[2] << 8) & statp[3])); break; case KEY_PAD_ETC: /* Key pad entry */ if (nofilter || (0xc0 & statp[1])) printf("%sIdent=%d, Fail=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40)); break; case ENCLOSURE_ETC: a = ((statp[2] >> 2) & 0x3f); if (nofilter || ((0x80 & statp[1]) || a || (0x2 & statp[2]))) printf("%sIdent=%d, Time until power cycle=%d, " "Failure indication=%d\n", pad, !!(statp[1] & 0x80), a, !!(statp[2] & 0x2)); b = ((statp[3] >> 2) & 0x3f); if (nofilter || (0x1 & statp[2]) || a || b) printf("%sWarning indication=%d, Requested power off " "duration=%d\n", pad, !!(statp[2] & 0x2), b); if (nofilter || (0x3 & statp[3])) printf("%sFailure requested=%d, Warning requested=%d\n", pad, !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case SCSI_PORT_TRAN_ETC: /* SCSI port/transceiver */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) || (0x13 & statp[3]))) printf("%sIdent=%d, Fail=%d, Report=%d, Disabled=%d, Loss of " "link=%d, Xmit fail=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[2] & 0x1), !!(statp[3] & 0x10), !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case LANGUAGE_ETC: printf("%sIdent=%d, Language code: %.2s\n", pad, !!(statp[1] & 0x80), statp + 2); break; case COMM_PORT_ETC: /* Communication port */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[3]))) printf("%sIdent=%d, Fail=%d, Disabled=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[3] & 0x1)); break; case VOLT_SENSOR_ETC: /* Voltage sensor */ if (nofilter || (0xcf & statp[1])) { printf("%sIdent=%d, Fail=%d, Warn Over=%d, Warn Under=%d, " "Crit Over=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[1] & 0x8), !!(statp[1] & 0x4), !!(statp[1] & 0x2)); printf("%sCrit Under=%d\n", pad, !!(statp[1] & 0x1)); } #ifdef SG_LIB_MINGW printf("%sVoltage: %g volts\n", pad, ((int)(short)((statp[2] << 8) + statp[3]) / 100.0)); #else printf("%sVoltage: %.2f volts\n", pad, ((int)(short)((statp[2] << 8) + statp[3]) / 100.0)); #endif break; case CURR_SENSOR_ETC: /* Current sensor */ if (nofilter || (0xca & statp[1])) printf("%sIdent=%d, Fail=%d, Warn Over=%d, Crit Over=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[1] & 0x8), !!(statp[1] & 0x2)); #ifdef SG_LIB_MINGW printf("%sCurrent: %g amps\n", pad, ((int)(short)((statp[2] << 8) + statp[3]) / 100.0)); #else printf("%sCurrent: %.2f amps\n", pad, ((int)(short)((statp[2] << 8) + statp[3]) / 100.0)); #endif break; case SCSI_TPORT_ETC: /* SCSI target port */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) || (0x1 & statp[3]))) printf("%sIdent=%d, Fail=%d, Report=%d, Enabled=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[2] & 0x1), !!(statp[3] & 0x1)); break; case SCSI_IPORT_ETC: /* SCSI initiator port */ if (nofilter || ((0xc0 & statp[1]) || (0x1 & statp[2]) || (0x1 & statp[3]))) printf("%sIdent=%d, Fail=%d, Report=%d, Enabled=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[2] & 0x1), !!(statp[3] & 0x1)); break; case SIMPLE_SUBENC_ETC: /* Simple subenclosure */ printf("%sIdent=%d, Fail=%d, Short enclosure status: 0x%x\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), statp[3]); break; case ARRAY_DEV_ETC: /* Array device */ if (nofilter || (0xf0 & statp[1])) printf("%sOK=%d, Reserved device=%d, Hot spare=%d, Cons check=" "%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40), !!(statp[1] & 0x20), !!(statp[1] & 0x10)); if (nofilter || (0xf & statp[1])) printf("%sIn crit array=%d, In failed array=%d, Rebuild/remap=%d" ", R/R abort=%d\n", pad, !!(statp[1] & 0x8), !!(statp[1] & 0x4), !!(statp[1] & 0x2), !!(statp[1] & 0x1)); if (nofilter || (0xf0 & statp[2])) printf("%sApp client bypass A=%d, Do not remove=%d, Enc bypass " "A=%d, Enc bypass B=%d\n", pad, !!(statp[2] & 0x80), !!(statp[2] & 0x40), !!(statp[2] & 0x20), !!(statp[2] & 0x10)); if (nofilter || (0xf & statp[2])) printf("%sReady to insert=%d, RMV=%d, Ident=%d, Report=%d\n", pad, !!(statp[2] & 0x8), !!(statp[2] & 0x4), !!(statp[2] & 0x2), !!(statp[2] & 0x1)); if (nofilter || (0xf0 & statp[3])) printf("%sApp client bypass B=%d, Fault sensed=%d, Fault reqstd=" "%d, Device off=%d\n", pad, !!(statp[3] & 0x80), !!(statp[3] & 0x40), !!(statp[3] & 0x20), !!(statp[3] & 0x10)); if (nofilter || (0xf & statp[3])) printf("%sBypassed A=%d, Bypassed B=%d, Dev bypassed A=%d, " "Dev bypassed B=%d\n", pad, !!(statp[3] & 0x8), !!(statp[3] & 0x4), !!(statp[3] & 0x2), !!(statp[3] & 0x1)); break; case SAS_EXPANDER_ETC: printf("%sIdent=%d, Fail=%d\n", pad, !!(statp[1] & 0x80), !!(statp[1] & 0x40)); break; case SAS_CONNECTOR_ETC: /* OC (overcurrent) added in ses3r07 */ printf("%sIdent=%d, %s\n", pad, !!(statp[1] & 0x80), find_sas_connector_type((statp[1] & 0x7f), bb, sizeof(bb))); printf("%sConnector physical link=0x%x, Fail=%d, OC=%d\n", pad, statp[2], !!(statp[3] & 0x40), !!(statp[3] & 0x20)); break; default: if (etype < 0x80) printf("%sUnknown element type, status in hex: %02x %02x %02x " "%02x\n", pad, statp[0], statp[1], statp[2], statp[3]); else printf("%sVendor specific element type, status in hex: %02x " "%02x %02x %02x\n", pad, statp[0], statp[1], statp[2], statp[3]); break; } } /* DPC_ENC_STATUS [0x2] * Display enclosure status diagnostic page. */ static void ses_enc_status_dp(const struct type_desc_hdr_t * tdhp, int num_telems, unsigned int ref_gen_code, const unsigned char * resp, int resp_len, const struct opts_t * op) { int j, k, elem_ind, match_ind_th, got1; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; char b[64]; printf("Enclosure Status diagnostic page:\n"); if (resp_len < 4) goto truncated; printf(" INVOP=%d, INFO=%d, NON-CRIT=%d, CRIT=%d, UNRECOV=%d\n", !!(resp[1] & 0x10), !!(resp[1] & 0x8), !!(resp[1] & 0x4), !!(resp[1] & 0x2), !!(resp[1] & 0x1)); last_ucp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); if (ref_gen_code != gen_code) { pr2serr(" <>\n"); return; } printf(" status descriptor list\n"); ucp = resp + 8; for (k = 0, got1 = 0; k < num_telems; ++k, ++tdhp) { if ((ucp + 3) > last_ucp) goto truncated; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { printf(" Element type: %s, subenclosure id: %d [ti=%d]\n", find_element_tname(tdhp->etype, b, sizeof(b)), tdhp->se_id, k); printf(" Overall descriptor:\n"); enc_status_helper(" ", ucp, tdhp->etype, op); ++got1; } for (ucp += 4, j = 0, elem_ind = 0; j < tdhp->num_elements; ++j, ucp += 4, ++elem_ind) { if (op->ind_given) { if ((! match_ind_th) || (-1 == op->ind_indiv) || (elem_ind != op->ind_indiv)) continue; } printf(" Element %d descriptor:\n", elem_ind); enc_status_helper(" ", ucp, tdhp->etype, op); ++got1; } } if (op->ind_given && (0 == got1)) printf(" >>> no match on --index=%d,%d\n", op->ind_th, op->ind_indiv); return; truncated: pr2serr(" <<>>\n"); return; } static char * reserved_or_num(char * buff, int buff_len, int num, int reserve_num) { if (num == reserve_num) strncpy(buff, "", buff_len); else snprintf(buff, buff_len, "%d", num); if (buff_len > 0) buff[buff_len - 1] = '\0'; return buff; } static void ses_threshold_helper(const char * pad, const unsigned char *tp, int etype, const struct opts_t * op) { char b[128]; char b2[128]; if (op->inner_hex) { printf("%s%02x %02x %02x %02x\n", pad, tp[0], tp[1], tp[2], tp[3]); return; } switch (etype) { case 0x4: /*temperature */ printf("%shigh critical=%s, high warning=%s\n", pad, reserved_or_num(b, 128, tp[0] - TEMPERAT_OFF, -TEMPERAT_OFF), reserved_or_num(b2, 128, tp[1] - TEMPERAT_OFF, -TEMPERAT_OFF)); printf("%slow warning=%s, low critical=%s (in Celsius)\n", pad, reserved_or_num(b, 128, tp[2] - TEMPERAT_OFF, -TEMPERAT_OFF), reserved_or_num(b2, 128, tp[3] - TEMPERAT_OFF, -TEMPERAT_OFF)); break; case 0xb: /* UPS */ if (0 == tp[2]) strcpy(b, ""); else snprintf(b, sizeof(b), "%d", tp[2]); printf("%slow warning=%s, ", pad, b); if (0 == tp[3]) strcpy(b, ""); else snprintf(b, sizeof(b), "%d", tp[3]); printf("low critical=%s (in minutes)\n", b); break; case 0x12: /* voltage */ #ifdef SG_LIB_MINGW printf("%shigh critical=%g %%, high warning=%g %%\n", pad, 0.5 * tp[0], 0.5 * tp[1]); printf("%slow warning=%g %%, low critical=%g %% (from nominal " "voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]); #else printf("%shigh critical=%.1f %%, high warning=%.1f %%\n", pad, 0.5 * tp[0], 0.5 * tp[1]); printf("%slow warning=%.1f %%, low critical=%.1f %% (from nominal " "voltage)\n", pad, 0.5 * tp[2], 0.5 * tp[3]); #endif break; case 0x13: /* current */ #ifdef SG_LIB_MINGW printf("%shigh critical=%g %%, high warning=%g %%", pad, 0.5 * tp[0], 0.5 * tp[1]); #else printf("%shigh critical=%.1f %%, high warning=%.1f %%", pad, 0.5 * tp[0], 0.5 * tp[1]); #endif printf(" (above nominal current)\n"); break; default: if (op->verbose) printf("%s<< no thresholds for this element type >>\n", pad); break; } } /* DPC_THRESHOLD [0x5] */ static void ses_threshold_sdg(const struct type_desc_hdr_t * tdhp, int num_telems, unsigned int ref_gen_code, const unsigned char * resp, int resp_len, const struct opts_t * op) { int j, k, elem_ind, match_ind_th, got1; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; char b[64]; printf("Threshold In diagnostic page:\n"); if (resp_len < 4) goto truncated; printf(" INVOP=%d\n", !!(resp[1] & 0x10)); last_ucp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); if (ref_gen_code != gen_code) { pr2serr(" <>\n"); return; } printf(" Threshold status descriptor list\n"); ucp = resp + 8; for (k = 0, got1 = 0; k < num_telems; ++k, ++tdhp) { if ((ucp + 3) > last_ucp) goto truncated; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { printf(" Element type: %s, subenclosure id: %d [ti=%d]\n", find_element_tname(tdhp->etype, b, sizeof(b)), tdhp->se_id, k); printf(" Overall descriptor:\n"); ses_threshold_helper(" ", ucp, tdhp->etype, op); ++got1; } for (ucp += 4, j = 0, elem_ind = 0; j < tdhp->num_elements; ++j, ucp += 4, ++elem_ind) { if (op->ind_given) { if ((! match_ind_th) || (-1 == op->ind_indiv) || (elem_ind != op->ind_indiv)) continue; } printf(" Element %d descriptor:\n", elem_ind); ses_threshold_helper(" ", ucp, tdhp->etype, op); ++got1; } } if (op->ind_given && (0 == got1)) printf(" >>> no match on --index=%d,%d\n", op->ind_th, op->ind_indiv); return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_ELEM_DESC [0x7] * This page essentially contains names of overall and individual * elements. */ static void ses_element_desc_sdg(const struct type_desc_hdr_t * tdhp, int num_telems, unsigned int ref_gen_code, const unsigned char * resp, int resp_len, const struct opts_t * op) { int j, k, desc_len, elem_ind, match_ind_th, got1; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; const struct type_desc_hdr_t * tp; char b[64]; printf("Element Descriptor In diagnostic page:\n"); if (resp_len < 4) goto truncated; last_ucp = resp + resp_len - 1; if (resp_len < 8) goto truncated; gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); if (ref_gen_code != gen_code) { pr2serr(" <>\n"); return; } printf(" element descriptor list (grouped by type):\n"); ucp = resp + 8; for (k = 0, got1 = 0, tp = tdhp; k < num_telems; ++k, ++tp) { if ((ucp + 3) > last_ucp) goto truncated; desc_len = (ucp[2] << 8) + ucp[3] + 4; match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { printf(" Element type: %s, subenclosure id: %d [ti=%d]\n", find_element_tname(tp->etype, b, sizeof(b)), tp->se_id, k); if (desc_len > 4) printf(" Overall descriptor: %.*s\n", desc_len - 4, ucp + 4); else printf(" Overall descriptor: \n"); ++got1; } for (ucp += desc_len, j = 0, elem_ind = 0; j < tp->num_elements; ++j, ucp += desc_len, ++elem_ind) { desc_len = (ucp[2] << 8) + ucp[3] + 4; if (op->ind_given) { if ((! match_ind_th) || (-1 == op->ind_indiv) || (elem_ind != op->ind_indiv)) continue; } if (desc_len > 4) printf(" Element %d descriptor: %.*s\n", j, desc_len - 4, ucp + 4); else printf(" Element %d descriptor: \n", j); ++got1; } } if (op->ind_given && (0 == got1)) printf(" >>> no match on --index=%d,%d\n", op->ind_th, op->ind_indiv); return; truncated: pr2serr(" <<>>\n"); return; } static int saddr_non_zero(const unsigned char * ucp) { int k; for (k = 0; k < 8; ++k) { if (ucp[k]) return 1; } return 0; } static const char * sas_device_type[] = { "no SAS device attached", /* but might be SATA device */ "end device", "expander device", /* in SAS-1.1 this was a "edge expander device */ "expander device (fanout, SAS-1.1)", /* marked obsolete in SAS-2 */ "reserved [4]", "reserved [5]", "reserved [6]", "reserved [7]" }; static void additional_elem_helper(const char * pad, const unsigned char * ucp, int len, int elem_type, const struct opts_t * op) { int ports, phys, j, m, desc_type, eip_offset, print_sas_addr, saddr_nz; const unsigned char * per_ucp; int nofilter = ! op->do_filter; char b[64]; if (op->inner_hex) { for (j = 0; j < len; ++j) { if (0 == (j % 16)) printf("%s%s", ((0 == j) ? "" : "\n"), pad); printf("%02x ", ucp[j]); } printf("\n"); return; } eip_offset = (0x10 & ucp[0]) ? 2 : 0; switch (0xf & ucp[0]) { case TPROTO_FCP: printf("%sTransport protocol: FCP\n", pad); if (len < (12 + eip_offset)) break; ports = ucp[2 + eip_offset]; printf("%snumber of ports: %d\n", pad, ports); printf("%snode_name: ", pad); for (m = 0; m < 8; ++m) printf("%02x", ucp[6 + eip_offset + m]); if (eip_offset) printf(", device slot number: %d", ucp[5 + eip_offset]); printf("\n"); per_ucp = ucp + 14 + eip_offset; for (j = 0; j < ports; ++j, per_ucp += 16) { printf("%s port index: %d, port loop position: %d, port " "bypass reason: 0x%x\n", pad, j, per_ucp[0], per_ucp[1]); printf("%srequested hard address: %d, n_port identifier: " "%02x%02x%02x\n", pad, per_ucp[4], per_ucp[5], per_ucp[6], per_ucp[7]); printf("%s n_port name: ", pad); for (m = 0; m < 8; ++m) printf("%02x", per_ucp[8 + m]); printf("\n"); } break; case TPROTO_SAS: printf("%sTransport protocol: SAS\n", pad); if (len < (4 + eip_offset)) break; desc_type = (ucp[3 + eip_offset] >> 6) & 0x3; if (op->verbose > 1) printf("%sdescriptor_type: %d\n", pad, desc_type); if (0 == desc_type) { phys = ucp[2 + eip_offset]; printf("%snumber of phys: %d, not all phys: %d", pad, phys, ucp[3 + eip_offset] & 1); if (eip_offset) printf(", device slot number: %d", ucp[5 + eip_offset]); printf("\n"); per_ucp = ucp + 4 + eip_offset + eip_offset; for (j = 0; j < phys; ++j, per_ucp += 28) { printf("%sphy index: %d\n", pad, j); printf("%s SAS device type: %s\n", pad, sas_device_type[(0x70 & per_ucp[0]) >> 4]); if (nofilter || (0xe & per_ucp[2])) printf("%s initiator port for:%s%s%s\n", pad, ((per_ucp[2] & 8) ? " SSP" : ""), ((per_ucp[2] & 4) ? " STP" : ""), ((per_ucp[2] & 2) ? " SMP" : "")); if (nofilter || (0x8f & per_ucp[3])) printf("%s target port for:%s%s%s%s%s\n", pad, ((per_ucp[3] & 0x80) ? " SATA_port_selector" : ""), ((per_ucp[3] & 8) ? " SSP" : ""), ((per_ucp[3] & 4) ? " STP" : ""), ((per_ucp[3] & 2) ? " SMP" : ""), ((per_ucp[3] & 1) ? " SATA_device" : "")); print_sas_addr = 0; saddr_nz = saddr_non_zero(per_ucp + 4); if (nofilter || saddr_nz) { ++print_sas_addr; printf("%s attached SAS address: 0x", pad); if (saddr_nz) { for (m = 0; m < 8; ++m) printf("%02x", per_ucp[4 + m]); } else printf("0"); } saddr_nz = saddr_non_zero(per_ucp + 12); if (nofilter || saddr_nz) { ++print_sas_addr; printf("\n%s SAS address: 0x", pad); if (saddr_nz) { for (m = 0; m < 8; ++m) printf("%02x", per_ucp[12 + m]); } else printf("0"); } if (print_sas_addr) printf("\n%s phy identifier: 0x%x\n", pad, per_ucp[20]); } } else if (1 == desc_type) { phys = ucp[2 + eip_offset]; if (SAS_EXPANDER_ETC == elem_type) { printf("%snumber of phys: %d\n", pad, phys); printf("%sSAS address: 0x", pad); for (m = 0; m < 8; ++m) printf("%02x", ucp[6 + eip_offset + m]); printf("\n"); per_ucp = ucp + 14 + eip_offset; for (j = 0; j < phys; ++j, per_ucp += 2) { printf("%s [%d] ", pad, j); if (0xff == per_ucp[0]) printf("no attached connector"); else printf("connector element index: %d", per_ucp[0]); if (0xff != per_ucp[1]) printf(", other element index: %d", per_ucp[1]); printf("\n"); } } else if ((SCSI_TPORT_ETC == elem_type) || (SCSI_IPORT_ETC == elem_type) || (ENC_ELECTRONICS_ETC == elem_type)) { printf("%snumber of phys: %d\n", pad, phys); per_ucp = ucp + 6 + eip_offset; for (j = 0; j < phys; ++j, per_ucp += 12) { printf("%sphy index: %d\n", pad, j); printf("%s phy identifier: 0x%x\n", pad, per_ucp[0]); if (0xff == per_ucp[2]) printf("%s no attached connector", pad); else printf("%s connector element index: %d", pad, per_ucp[2]); if (0xff != per_ucp[3]) printf(", other element index: %d", per_ucp[3]); printf("\n"); printf("%s SAS address: 0x", pad); for (m = 0; m < 8; ++m) printf("%02x", per_ucp[4 + m]); printf("\n"); } } else printf("%sunrecognised element type [%d] for desc_type " "1\n", pad, elem_type); } else printf("%sunrecognised descriptor type [%d]\n", pad, desc_type); break; default: printf("%sTransport protocol: %s not decoded\n", pad, sg_get_trans_proto_str((0xf & ucp[0]), sizeof(b), b)); if (op->verbose) dStrHex((const char *)ucp, len, 0); break; } } /* DPC_ADD_ELEM_STATUS [0xa] * Previously called "Device element status descriptor". Changed "device" * to "additional" to allow for SAS expander and SATA devices */ static void ses_additional_elem_sdg(const struct type_desc_hdr_t * tdhp, int num_telems, unsigned int ref_gen_code, const unsigned char * resp, int resp_len, const struct opts_t * op) { int j, k, desc_len, elem_type, invalid, el_num, eip, ind, match_ind_th; int elem_count, ei, eiioe, my_eiioe_force, num_elems, skip; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; const struct type_desc_hdr_t * tp; char b[64]; printf("Additional element status diagnostic page:\n"); if (resp_len < 4) goto truncated; last_ucp = resp + resp_len - 1; gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); if (ref_gen_code != gen_code) { pr2serr(" <>\n"); return; } printf(" additional element status descriptor list\n"); ucp = resp + 8; my_eiioe_force = op->eiioe_force; for (k = 0, tp = tdhp, elem_count = 0; k < num_telems; ++k, ++tp) { elem_type = tp->etype; num_elems = tp->num_elements; if (! active_et_aesp(elem_type)) { elem_count += num_elems; continue; /* skip if not element type of interest */ } if ((ucp + 1) > last_ucp) goto truncated; /* if eip is 1, do bounds check on the element index */ if (ucp[0] & 0x10) /* eip=1 */ { ei = ucp[3]; skip = 0; if ((0 == k) && op->eiioe_auto && (1 == ei)) { /* heuristic: if first element index in this page is 1 * then act as if the EIIOE bit is set. */ my_eiioe_force = 1; } eiioe = my_eiioe_force ? 1 : (ucp[2] & 1); if (eiioe) { if ((ei < (elem_count + k)) || (ei > (elem_count + k + num_elems))) { elem_count += num_elems; skip = 1; } } else { if ((ei < elem_count) || (ei > elem_count + num_elems)) { elem_count += num_elems; skip = 1; } } if (skip) { if (op->verbose > 2) pr2serr("skipping elem_type=0x%x, k=%d due to " "element_index=%d bounds\n effective eiioe=%d, " "elem_count=%d, num_elems=%d\n", elem_type, k, ei, eiioe, elem_count, num_elems); continue; } } match_ind_th = (op->ind_given && (k == op->ind_th)); if ((! op->ind_given) || (match_ind_th && (-1 == op->ind_indiv))) { printf(" Element type: %s, subenclosure id: %d [ti=%d]\n", find_element_tname(elem_type, b, sizeof(b)), tp->se_id, k); } el_num = 0; for (j = 0; j < num_elems; ++j, ucp += desc_len, ++el_num) { invalid = !!(ucp[0] & 0x80); desc_len = ucp[1] + 2; eip = ucp[0] & 0x10; eiioe = eip ? (ucp[2] & 1) : 0; ind = eip ? ucp[3] : el_num; if (op->ind_given) { if ((! match_ind_th) || (-1 == op->ind_indiv) || (el_num != op->ind_indiv)) continue; } if (eip) printf(" Element index: %d eiioe=%d%s\n", ind, eiioe, (((! eiioe) && my_eiioe_force) ? " but overridden" : "")); else printf(" Element %d descriptor\n", ind); if (invalid && (0 == op->inner_hex)) printf(" flagged as invalid (no further " "information)\n"); else additional_elem_helper(" ", ucp, desc_len, elem_type, op); } elem_count += tp->num_elements; } return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_SUBENC_HELP_TEXT [0xb] */ static void ses_subenc_help_sdg(const unsigned char * resp, int resp_len) { int k, el, num_subs; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; printf("Subenclosure help text diagnostic page:\n"); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_ucp = resp + resp_len - 1; printf(" number of secondary subenclosures: %d\n", num_subs - 1); gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); ucp = resp + 8; for (k = 0; k < num_subs; ++k, ucp += el) { if ((ucp + 3) > last_ucp) goto truncated; el = (ucp[2] << 8) + ucp[3] + 4; printf(" subenclosure identifier: %d\n", ucp[1]); if (el > 4) printf(" %.*s\n", el - 4, ucp + 4); else printf(" \n"); } return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_SUBENC_STRING [0xc] */ static void ses_subenc_string_sdg(const unsigned char * resp, int resp_len) { int k, j, el, num_subs; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; printf("Subenclosure string in diagnostic page:\n"); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_ucp = resp + resp_len - 1; printf(" number of secondary subenclosures: %d\n", num_subs - 1); gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); ucp = resp + 8; for (k = 0; k < num_subs; ++k, ucp += el) { if ((ucp + 3) > last_ucp) goto truncated; el = (ucp[2] << 8) + ucp[3] + 4; printf(" subenclosure identifier: %d\n", ucp[1]); if (el > 4) { /* dStrHex((const char *)(ucp + 4), el - 4, 0); */ printf(" "); for (j = 0; j < (el - 4); ++j) { if ((j > 0) && (0 == (j % 16))) printf("\n "); printf("%02x ", *(ucp + 4 + j)); } printf("\n"); } else printf(" \n"); } return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_SUBENC_NICKNAME [0xf] */ static void ses_subenc_nickname_sdg(const unsigned char * resp, int resp_len) { int k, el, num_subs; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; printf("Subenclosure nickname status diagnostic page:\n"); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_ucp = resp + resp_len - 1; printf(" number of secondary subenclosures: %d\n", num_subs - 1); gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); ucp = resp + 8; el = 40; for (k = 0; k < num_subs; ++k, ucp += el) { if ((ucp + el - 1) > last_ucp) goto truncated; printf(" subenclosure identifier: %d\n", ucp[1]); printf(" nickname status: 0x%x\n", ucp[2]); printf(" nickname additional status: 0x%x\n", ucp[3]); printf(" nickname language code: %.2s\n", ucp + 6); printf(" nickname: %.*s\n", 32, ucp + 8); } return; truncated: pr2serr(" <<>>\n"); return; } /* DPC_SUPPORTED_SES [0xd] */ static void ses_supported_pages_sdg(const char * leadin, const unsigned char * resp, int resp_len) { int k, code, prev, got1; const char * cp; const struct diag_page_abbrev * ap; printf("%s:\n", leadin); for (k = 0, prev = 0; k < (resp_len - 4); ++k, prev = code) { code = resp[k + 4]; if (code < prev) break; /* assume to be padding at end */ cp = find_diag_page_desc(code); if (cp) { printf(" %s [", cp); for (ap = dp_abbrev, got1 = 0; ap->abbrev; ++ap) { if (ap->page_code == code) { printf("%s%s", (got1 ? "," : ""), ap->abbrev); ++got1; } } printf("] [0x%x]\n", code); } else printf(" [0x%x]\n", code); } } /* An array of Download microcode status field values and descriptions */ static struct diag_page_code mc_status_arr[] = { {0x0, "No download microcode operation in progress"}, {0x1, "Download in progress, awaiting more"}, {0x2, "Download complete, updating storage"}, {0x3, "Updating storage with deferred microcode"}, {0x10, "Complete, no error, starting now"}, {0x11, "Complete, no error, start after hard reset or power cycle"}, {0x12, "Complete, no error, start after power cycle"}, {0x13, "Complete, no error, start after activate_mc, hard reset or " "power cycle"}, {0x80, "Error, discarded, see additional status"}, {0x81, "Error, discarded, image error"}, {0x82, "Timeout, discarded"}, {0x83, "Internal error, need new microcode before reset"}, {0x84, "Internal error, need new microcode, reset safe"}, {0x85, "Unexpected activate_mc received"}, {0x1000, NULL}, }; static const char * get_mc_status(unsigned char status_val) { const struct diag_page_code * mcsp; for (mcsp = mc_status_arr; mcsp->desc; ++mcsp) { if (status_val == mcsp->page_code) return mcsp->desc; } return ""; } /* DPC_DOWNLOAD_MICROCODE [0xe] */ static void ses_download_code_sdg(const unsigned char * resp, int resp_len) { int k, num_subs; unsigned int gen_code; const unsigned char * ucp; const unsigned char * last_ucp; const char * cp; printf("Download microcode status diagnostic page:\n"); if (resp_len < 4) goto truncated; num_subs = resp[1] + 1; /* number of subenclosures (add 1 for primary) */ last_ucp = resp + resp_len - 1; printf(" number of secondary subenclosures: %d\n", num_subs - 1); gen_code = (resp[4] << 24) | (resp[5] << 16) | (resp[6] << 8) | resp[7]; printf(" generation code: 0x%x\n", gen_code); ucp = resp + 8; for (k = 0; k < num_subs; ++k, ucp += 16) { if ((ucp + 3) > last_ucp) goto truncated; cp = (0 == ucp[1]) ? " [primary]" : ""; printf(" subenclosure identifier: %d%s\n", ucp[1], cp); cp = get_mc_status(ucp[2]); if (strlen(cp) > 0) { printf(" download microcode status: %s [0x%x]\n", cp, ucp[2]); printf(" download microcode additional status: 0x%x\n", ucp[3]); } else printf(" download microcode status: 0x%x [additional " "status: 0x%x]\n", ucp[2], ucp[3]); printf(" download microcode maximum size: %d bytes\n", (ucp[4] << 24) + (ucp[5] << 16) + (ucp[6] << 8) + ucp[7]); printf(" download microcode expected buffer id: 0x%x\n", ucp[11]); printf(" download microcode expected buffer id offset: %d\n", (ucp[12] << 24) + (ucp[13] << 16) + (ucp[14] << 8) + ucp[15]); } return; truncated: pr2serr(" <<>>\n"); return; } /* Reads hex data from command line, stdin or a file. Returns 0 on success, * 1 otherwise. */ static int read_hex(const char * inp, unsigned char * arr, int * arr_len, int verb) { int in_len, k, j, m, off, split_line; unsigned int h; const char * lcp; char * cp; char * c2p; char line[512]; char carry_over[4]; FILE * fp = NULL; if ((NULL == inp) || (NULL == arr) || (NULL == arr_len)) return 1; lcp = inp; in_len = strlen(inp); if (0 == in_len) { *arr_len = 0; } if (('-' == inp[0]) || ('@' == inp[0])) { /* read from stdin or file */ if ('-' == inp[0]) fp = stdin; else { fp = fopen(inp + 1, "r"); if (NULL == fp) { pr2serr("read_hex: unable to open file: %s\n", inp + 1); return 1; } } carry_over[0] = 0; for (j = 0, off = 0; j < MX_DATA_IN; ++j) { /* limit lines read to MX_DATA_IN */ if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) arr[off - 1] = h; /* back up and overwrite */ else { pr2serr("read_hex: carry_over error ['%s'] around " "line %d\n", carry_over, j + 1); goto err_with_fp; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if (in_len != k) { pr2serr("read_hex: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto err_with_fp; } for (k = 0; k < (MX_DATA_IN - off); ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("read_hex: hex number larger than 0xff in " "line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto err_with_fp; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { pr2serr("read_hex: error in line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); goto err_with_fp; } } off += k + 1; if (off >= MX_DATA_IN) break; } *arr_len = off; } else { /* hex string on command line */ k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("read_hex: error at pos %d\n", k + 1); return 1; } for (k = 0; k < MX_DATA_IN; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("read_hex: hex number larger than 0xff at pos " "%d\n", (int)(lcp - inp + 1)); return 1; } arr[k] = h; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { pr2serr("read_hex: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } *arr_len = k + 1; } if (verb > 3) dStrHex((const char *)arr, *arr_len, 0); if (fp && (fp != stdin)) fclose(fp); return 0; err_with_fp: if (fp && (fp != stdin)) fclose(fp); return 1; } /* Display "status" page (op->page_code). Return 0 for success. */ static int ses_process_status_page(int sg_fd, struct opts_t * op) { int j, resp_len, res; int ret = 0; unsigned int ref_gen_code; unsigned char * resp; const char * cp; struct enclosure_info primary_info; resp = (unsigned char *)calloc(op->maxlen, 1); if (NULL == resp) { pr2serr("process_status_page: unable to allocate %d bytes on heap\n", op->maxlen); ret = -1; goto fini; } cp = find_in_diag_page_desc(op->page_code); ret = do_rec_diag(sg_fd, op->page_code, resp, op->maxlen, op, &resp_len); if (ret) goto fini; if (op->do_raw) { if (1 == op->do_raw) dStrHex((const char *)resp + 4, resp_len - 4, -1); else { if (sg_set_binary_mode(STDOUT_FILENO) < 0) perror("sg_set_binary_mode"); dStrRaw((const char *)resp, resp_len); } } else if (op->do_hex) { if (cp) printf("Response in hex from diagnostic page: %s\n", cp); else printf("Response in hex from unknown diagnostic page " "[0x%x]\n", op->page_code); dStrHex((const char *)resp, resp_len, 0); } else { memset(&primary_info, 0, sizeof(primary_info)); switch (op->page_code) { case DPC_SUPPORTED: ses_supported_pages_sdg("Supported diagnostic pages", resp, resp_len); break; case DPC_CONFIGURATION: ses_configuration_sdg(resp, resp_len); break; case DPC_ENC_STATUS: res = populate_type_desc_hdr_arr(sg_fd, type_desc_hdr_arr, &ref_gen_code, &primary_info, op); if (res < 0) { ret = res; goto fini; } if (primary_info.have_info) { printf(" Primary enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", primary_info.enc_log_id[j]); printf("\n"); } ses_enc_status_dp(type_desc_hdr_arr, res, ref_gen_code, resp, resp_len, op); break; case DPC_HELP_TEXT: printf("Help text diagnostic page (for primary " "subenclosure):\n"); if (resp_len > 4) printf(" %.*s\n", resp_len - 4, resp + 4); else printf(" \n"); break; case DPC_STRING: printf("String In diagnostic page (for primary " "subenclosure):\n"); if (resp_len > 4) dStrHex((const char *)(resp + 4), resp_len - 4, 0); else printf(" \n"); break; case DPC_THRESHOLD: res = populate_type_desc_hdr_arr(sg_fd, type_desc_hdr_arr, &ref_gen_code, &primary_info, op); if (res < 0) { ret = res; goto fini; } if (primary_info.have_info) { printf(" Primary enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", primary_info.enc_log_id[j]); printf("\n"); } ses_threshold_sdg(type_desc_hdr_arr, res, ref_gen_code, resp, resp_len, op); break; case DPC_ELEM_DESC: res = populate_type_desc_hdr_arr(sg_fd, type_desc_hdr_arr, &ref_gen_code, &primary_info, op); if (res < 0) { ret = res; goto fini; } if (primary_info.have_info) { printf(" Primary enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", primary_info.enc_log_id[j]); printf("\n"); } ses_element_desc_sdg(type_desc_hdr_arr, res, ref_gen_code, resp, resp_len, op); break; case DPC_SHORT_ENC_STATUS: printf("Short enclosure status diagnostic page, " "status=0x%x\n", resp[1]); break; case DPC_ENC_BUSY: printf("Enclosure Busy diagnostic page, " "busy=%d [vendor specific=0x%x]\n", resp[1] & 1, (resp[1] >> 1) & 0xff); break; case DPC_ADD_ELEM_STATUS: res = populate_type_desc_hdr_arr(sg_fd, type_desc_hdr_arr, &ref_gen_code, &primary_info, op); if (res < 0) { ret = res; goto fini; } if (primary_info.have_info) { printf(" Primary enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", primary_info.enc_log_id[j]); printf("\n"); } ses_additional_elem_sdg(type_desc_hdr_arr, res, ref_gen_code, resp, resp_len, op); break; case DPC_SUBENC_HELP_TEXT: ses_subenc_help_sdg(resp, resp_len); break; case DPC_SUBENC_STRING: ses_subenc_string_sdg(resp, resp_len); break; case DPC_SUPPORTED_SES: ses_supported_pages_sdg("Supported SES diagnostic pages", resp, resp_len); break; case DPC_DOWNLOAD_MICROCODE: ses_download_code_sdg(resp, resp_len); break; case DPC_SUBENC_NICKNAME: ses_subenc_nickname_sdg(resp, resp_len); break; default: printf("Cannot decode response from diagnostic " "page: %s\n", (cp ? cp : "")); dStrHex((const char *)resp, resp_len, 0); } } ret = 0; fini: if (resp) free(resp); return ret; } static void devslotnum_and_sasaddr(struct join_row_t * jrp, unsigned char * ae_ucp) { int m; if ((0 == jrp) || (0 == ae_ucp) || (0 == (0x10 & ae_ucp[0]))) return; /* sanity and expect EIP=1 */ switch (0xf & ae_ucp[0]) { case TPROTO_FCP: jrp->dev_slot_num = ae_ucp[7]; break; case TPROTO_SAS: if (0 == (0xc0 & ae_ucp[5])) { /* only for device slot and array device slot elements */ jrp->dev_slot_num = ae_ucp[7]; if (ae_ucp[4] > 0) { /* number of phys */ /* Use the first phy's "SAS ADDRESS" field */ for (m = 0; m < 8; ++m) jrp->sas_addr[m] = ae_ucp[(4 + 4 + 12) + m]; } } break; default: ; } } /* Fetch Configuration, Enclosure Status, Element Descriptor, Additional * Element Status and optionally Threshold In pages, place in static arrays. * Collate (join) overall and individual elements into the static join_arr[]. * Returns 0 for success, any other return value is an error. */ static int join_work(int sg_fd, struct opts_t * op, int display) { int k, j, res, num_t_hdrs, elem_ind, ei, desc_len, dn_len; int et4aes, broken_ei, ei2, got1, jr_max_ind, mlen; unsigned int ref_gen_code, gen_code; struct join_row_t * jrp; struct join_row_t * jr2p; unsigned char * es_ucp; unsigned char * ed_ucp; unsigned char * ae_ucp; unsigned char * t_ucp; /* const unsigned char * es_last_ucp; */ /* const unsigned char * ed_last_ucp; */ const unsigned char * ae_last_ucp; /* const unsigned char * t_last_ucp; */ const char * cp; const char * enc_state_changed = " <>\n"; const struct type_desc_hdr_t * tdhp; struct enclosure_info primary_info; char b[64]; memset(&primary_info, 0, sizeof(primary_info)); num_t_hdrs = populate_type_desc_hdr_arr(sg_fd, type_desc_hdr_arr, &ref_gen_code, &primary_info, op); if (num_t_hdrs < 0) return num_t_hdrs; if (display && primary_info.have_info) { printf(" Primary enclosure logical identifier (hex): "); for (j = 0; j < 8; ++j) printf("%02x", primary_info.enc_log_id[j]); printf("\n"); } mlen = sizeof(enc_stat_rsp); if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(sg_fd, DPC_ENC_STATUS, enc_stat_rsp, mlen, op, &enc_stat_rsp_len); if (res) return res; if (enc_stat_rsp_len < 8) { pr2serr("Enclosure Status response too short\n"); return -1; } gen_code = (enc_stat_rsp[4] << 24) | (enc_stat_rsp[5] << 16) | (enc_stat_rsp[6] << 8) | enc_stat_rsp[7]; if (ref_gen_code != gen_code) { pr2serr("%s", enc_state_changed); return -1; } es_ucp = enc_stat_rsp + 8; /* es_last_ucp = enc_stat_rsp + enc_stat_rsp_len - 1; */ mlen = sizeof(elem_desc_rsp); if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(sg_fd, DPC_ELEM_DESC, elem_desc_rsp, mlen, op, &elem_desc_rsp_len); if (0 == res) { if (elem_desc_rsp_len < 8) { pr2serr("Element Descriptor response too short\n"); return -1; } gen_code = (elem_desc_rsp[4] << 24) | (elem_desc_rsp[5] << 16) | (elem_desc_rsp[6] << 8) | elem_desc_rsp[7]; if (ref_gen_code != gen_code) { pr2serr("%s", enc_state_changed); return -1; } ed_ucp = elem_desc_rsp + 8; /* ed_last_ucp = elem_desc_rsp + elem_desc_rsp_len - 1; */ } else { elem_desc_rsp_len = 0; ed_ucp = NULL; res = 0; if (op->verbose) pr2serr(" Element Descriptor page not available\n"); } if (display || (DPC_ADD_ELEM_STATUS == op->page_code) || (op->dev_slot_num >= 0) || saddr_non_zero(op->sas_addr)) { mlen = sizeof(add_elem_rsp); if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(sg_fd, DPC_ADD_ELEM_STATUS, add_elem_rsp, mlen, op, &add_elem_rsp_len); if (0 == res) { if (add_elem_rsp_len < 8) { pr2serr("Additional Element Status response too short\n"); return -1; } gen_code = (add_elem_rsp[4] << 24) | (add_elem_rsp[5] << 16) | (add_elem_rsp[6] << 8) | add_elem_rsp[7]; if (ref_gen_code != gen_code) { pr2serr("%s", enc_state_changed); return -1; } ae_ucp = add_elem_rsp + 8; ae_last_ucp = add_elem_rsp + add_elem_rsp_len - 1; if (op->eiioe_auto && (add_elem_rsp_len > 11)) { /* heuristic: if first element index in this page is 1 * then act as if the EIIOE bit is set. */ if ((ae_ucp[0] & 0x10) && (1 == ae_ucp[3])) op->eiioe_force = 1; } } else { add_elem_rsp_len = 0; ae_ucp = NULL; ae_last_ucp = NULL; res = 0; if (op->verbose) pr2serr(" Additional Element Status page not available\n"); } } else { ae_ucp = NULL; ae_last_ucp = NULL; } if ((op->do_join > 1) || ((0 == display) && (DPC_THRESHOLD == op->page_code))) { mlen = sizeof(threshold_rsp); if (mlen > op->maxlen) mlen = op->maxlen; res = do_rec_diag(sg_fd, DPC_THRESHOLD, threshold_rsp, mlen, op, &threshold_rsp_len); if (0 == res) { if (threshold_rsp_len < 8) { pr2serr("Threshold In response too short\n"); return -1; } gen_code = (threshold_rsp[4] << 24) | (threshold_rsp[5] << 16) | (threshold_rsp[6] << 8) | threshold_rsp[7]; if (ref_gen_code != gen_code) { pr2serr("%s", enc_state_changed); return -1; } t_ucp = threshold_rsp + 8; /* t_last_ucp = threshold_rsp + threshold_rsp_len - 1; */ } else { threshold_rsp_len = 0; t_ucp = NULL; res = 0; if (op->verbose) pr2serr(" Threshold In page not available\n"); } } else { threshold_rsp_len = 0; t_ucp = NULL; } jrp = join_arr; tdhp = type_desc_hdr_arr; jr_max_ind = 0; for (k = 0, ei = 0, ei2 = 0; k < num_t_hdrs; ++k, ++tdhp) { jrp->el_ind_th = k; jrp->el_ind_indiv = -1; jrp->etype = tdhp->etype; jrp->ei_asc = -1; et4aes = active_et_aesp(tdhp->etype); jrp->ei_asc2 = -1; jrp->se_id = tdhp->se_id; /* check es_ucp < es_last_ucp still in range */ jrp->enc_statp = es_ucp; es_ucp += 4; jrp->elem_descp = ed_ucp; if (ed_ucp) ed_ucp += (ed_ucp[2] << 8) + ed_ucp[3] + 4; jrp->add_elem_statp = NULL; jrp->thresh_inp = t_ucp; jrp->dev_slot_num = -1; /* assume sas_addr[8] zeroed since it's static file scope */ if (t_ucp) t_ucp += 4; ++jrp; for (j = 0, elem_ind = 0; j < tdhp->num_elements; ++j, ++jrp, ++elem_ind) { if (jrp >= join_arr_lastp) break; jrp->el_ind_th = k; jrp->el_ind_indiv = elem_ind; jrp->ei_asc = ei++; if (et4aes) jrp->ei_asc2 = ei2++; else jrp->ei_asc2 = -1; jrp->etype = tdhp->etype; jrp->se_id = tdhp->se_id; jrp->enc_statp = es_ucp; es_ucp += 4; jrp->elem_descp = ed_ucp; if (ed_ucp) ed_ucp += (ed_ucp[2] << 8) + ed_ucp[3] + 4; jrp->thresh_inp = t_ucp; jrp->dev_slot_num = -1; /* assume sas_addr[8] zeroed since it's static file scope */ if (t_ucp) t_ucp += 4; jrp->add_elem_statp = NULL; ++jr_max_ind; } if (jrp >= join_arr_lastp) { ++k; break; /* leave last row all zeros */ } } broken_ei = 0; if (ae_ucp) { int eip, eiioe; int aes_i = 0; int get_out = 0; jrp = join_arr; tdhp = type_desc_hdr_arr; for (k = 0; k < num_t_hdrs; ++k, ++tdhp) { if (active_et_aesp(tdhp->etype)) { /* only consider element types that AES element are permiited * to refer to, then loop over those number of elements */ for (j = 0; j < tdhp->num_elements; ++j) { if ((ae_ucp + 1) > ae_last_ucp) { get_out = 1; if (op->verbose || op->warn) pr2serr("warning: %s: off end of ae page\n", __func__); break; } eip = !!(ae_ucp[0] & 0x10); /* element index present */ if (eip) eiioe = op->eiioe_force ? 1 : (ae_ucp[2] & 1); else eiioe = 0; if (eip && eiioe) { ei = ae_ucp[3]; jr2p = join_arr + ei; if ((ei >= jr_max_ind) || (NULL == jr2p->enc_statp)) { get_out = 1; pr2serr("%s: oi=%d, ei=%d [max_ind=%d], eiioe=1 " "not in join_arr\n", __func__, k, ei, jr_max_ind); break; } devslotnum_and_sasaddr(jr2p, ae_ucp); if (jr2p->add_elem_statp) { if (op->warn || op->verbose) pr2serr("warning: aes slot busy [oi=%d, " "ei=%d, aes_i=%d]\n", k, ei, aes_i); } else jr2p->add_elem_statp = ae_ucp; } else if (eip) { /* and EIIOE=0 */ ei = ae_ucp[3]; try_again: for (jr2p = join_arr; jr2p->enc_statp; ++jr2p) { if (broken_ei) { if (ei == jr2p->ei_asc2) break; } else { if (ei == jr2p->ei_asc) break; } } if (NULL == jr2p->enc_statp) { get_out = 1; pr2serr("warning: %s: oi=%d, ei=%d (broken_ei=%d) " "not in join_arr\n", __func__, k, ei, broken_ei); break; } if (! active_et_aesp(jr2p->etype)) { /* broken_ei must be 0 for that to be false */ ++broken_ei; goto try_again; } devslotnum_and_sasaddr(jr2p, ae_ucp); if (jr2p->add_elem_statp) { if (op->warn || op->verbose) pr2serr("warning: aes slot busy [oi=%d, " "ei=%d, aes_i=%d]\n", k, ei, aes_i); } else jr2p->add_elem_statp = ae_ucp; } else { /* EIP=0 */ while (jrp->enc_statp && ((-1 == jrp->el_ind_indiv) || jrp->add_elem_statp)) ++jrp; if (NULL == jrp->enc_statp) { get_out = 1; pr2serr("warning: %s: join_arr has no space for " "ae\n", __func__); break; } jrp->add_elem_statp = ae_ucp; ++jrp; } ae_ucp += ae_ucp[1] + 2; ++aes_i; } } else { /* element type not relevant to ae status */ /* step over overall and individual elements */ for (j = 0; j <= tdhp->num_elements; ++j, ++jrp) { if (NULL == jrp->enc_statp) { get_out = 1; pr2serr("warning: %s: join_arr has no space\n", __func__); break; } } } if (get_out) break; } } if (op->verbose > 3) { jrp = join_arr; for (k = 0; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) { pr2serr("el_ind_th=%d el_ind_indiv=%d etype=%d se_id=%d ei=%d " "ei2=%d dsn=%d sa=0x", jrp->el_ind_th, jrp->el_ind_indiv, jrp->etype, jrp->se_id, jrp->ei_asc, jrp->ei_asc2, jrp->dev_slot_num); if (saddr_non_zero(jrp->sas_addr)) { for (j = 0; j < 8; ++j) pr2serr("%02x", jrp->sas_addr[j]); } else pr2serr("0"); pr2serr(" %s %s %s %s\n", (jrp->enc_statp ? "ES" : ""), (jrp->elem_descp ? "ED" : ""), (jrp->add_elem_statp ? "AES" : ""), (jrp->thresh_inp ? "TI" : "")); } pr2serr(">> elements in join_arr: %d, broken_ei=%d\n", k, broken_ei); } if (! display) /* probably wanted join_arr[] built only */ return 0; /* Display contents of join_arr */ dn_len = op->desc_name ? (int)strlen(op->desc_name) : 0; for (k = 0, jrp = join_arr, got1 = 0; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) { if (op->ind_given) { if (op->ind_th != jrp->el_ind_th) continue; if (op->ind_indiv != jrp->el_ind_indiv) continue; } ed_ucp = jrp->elem_descp; if (op->desc_name) { if (NULL == ed_ucp) continue; desc_len = (ed_ucp[2] << 8) + ed_ucp[3]; /* some element descriptor strings have a trailing NULL and * count it in their length; adjust */ if ('\0' == ed_ucp[4 + desc_len - 1]) --desc_len; if (desc_len != dn_len) continue; if (0 != strncmp(op->desc_name, (const char *)(ed_ucp + 4), desc_len)) continue; } else if (op->dev_slot_num >= 0) { if (op->dev_slot_num != jrp->dev_slot_num) continue; } else if (saddr_non_zero(op->sas_addr)) { for (j = 0; j < 8; ++j) { if (op->sas_addr[j] != jrp->sas_addr[j]) break; } if (j < 8) continue; } ++got1; if ((op->do_filter > 1) && (1 != (0xf & jrp->enc_statp[0]))) continue; /* when '-ff' and status!=OK, skip */ cp = find_element_tname(jrp->etype, b, sizeof(b)); if (ed_ucp) { desc_len = (ed_ucp[2] << 8) + ed_ucp[3] + 4; if (desc_len > 4) printf("%.*s [%d,%d] Element type: %s\n", desc_len - 4, (const char *)(ed_ucp + 4), jrp->el_ind_th, jrp->el_ind_indiv, cp); else printf("[%d,%d] Element type: %s\n", jrp->el_ind_th, jrp->el_ind_indiv, cp); } else printf("[%d,%d] Element type: %s\n", jrp->el_ind_th, jrp->el_ind_indiv, cp); printf(" Enclosure Status:\n"); enc_status_helper(" ", jrp->enc_statp, jrp->etype, op); if (jrp->add_elem_statp) { printf(" Additional Element Status:\n"); ae_ucp = jrp->add_elem_statp; desc_len = ae_ucp[1] + 2; additional_elem_helper(" ", ae_ucp, desc_len, jrp->etype, op); } if (jrp->thresh_inp) { printf(" Threshold In:\n"); t_ucp = jrp->thresh_inp; ses_threshold_helper(" ", t_ucp, jrp->etype, op); } } if (0 == got1) { if (op->ind_given) printf(" >>> no match on --index=%d,%d\n", op->ind_th, op->ind_indiv); else if (op->desc_name) printf(" >>> no match on --descriptor=%s\n", op->desc_name); else if (op->dev_slot_num >= 0) printf(" >>> no match on --dev-slot-name=%d\n", op->dev_slot_num); else if (saddr_non_zero(op->sas_addr)) { printf(" >>> no match on --sas-addr=0x"); for (j = 0; j < 8; ++j) printf("%02x", op->sas_addr[j]); printf("\n"); } } return res; } static uint64_t get_big_endian(const unsigned char * from, int start_bit, int num_bits) { uint64_t res; int sbit_o1 = start_bit + 1; res = (*from++ & ((1 << sbit_o1) - 1)); num_bits -= sbit_o1; while (num_bits > 0) { res <<= 8; res |= *from++; num_bits -= 8; } if (num_bits < 0) res >>= (-num_bits); return res; } static void set_big_endian(uint64_t val, unsigned char * to, int start_bit, int num_bits) { int sbit_o1 = start_bit + 1; int mask, num, k, x; mask = (8 != sbit_o1) ? ((1 << sbit_o1) - 1) : 0xff; k = start_bit - ((num_bits - 1) % 8); if (0 != k) val <<= ((k > 0) ? k : (8 + k)); num = (num_bits + 15 - sbit_o1) / 8; for (k = 0; k < num; ++k) { if ((sbit_o1 - num_bits) > 0) mask &= ~((1 << (sbit_o1 - num_bits)) - 1); if (k < (num - 1)) x = (val >> ((num - k - 1) * 8)) & 0xff; else x = val & 0xff; to[k] = (to[k] & ~mask) | (x & mask); mask = 0xff; num_bits -= sbit_o1; sbit_o1 = 8; } } /* Returns 1 if strings equal (same length, characters same or only differ * by case), else returns 0. Assumes 7 bit ASCII (English alphabet). */ static int strcase_eq(const char * s1p, const char * s2p) { int c1, c2; do { c1 = *s1p++; c2 = *s2p++; if (c1 != c2) { if (c2 >= 'a') c2 = toupper(c2); else if (c1 >= 'a') c1 = toupper(c1); else return 0; if (c1 != c2) return 0; } } while (c1); return 1; } static int is_acronym_in_status_ctl(const struct tuple_acronym_val * tavp) { const struct acronym2tuple * ap; for (ap = ecs_a2t_arr; ap->acron; ++ ap) { if (strcase_eq(tavp->acron, ap->acron)) break; } return (ap->acron ? 1 : 0); } static int is_acronym_in_threshold(const struct tuple_acronym_val * tavp) { const struct acronym2tuple * ap; for (ap = th_a2t_arr; ap->acron; ++ ap) { if (strcase_eq(tavp->acron, ap->acron)) break; } return (ap->acron ? 1 : 0); } static int is_acronym_in_additional(const struct tuple_acronym_val * tavp) { const struct acronym2tuple * ap; for (ap = ae_sas_a2t_arr; ap->acron; ++ ap) { if (strcase_eq(tavp->acron, ap->acron)) break; } return (ap->acron ? 1 : 0); } /* DPC_ENC_STATUS DPC_ENC_CONTROL * Do clear/get/set (cgs) on Enclosure Control/Status page. Return 0 for ok * -2 for acronym not found, else -1 . */ static int cgs_enc_ctl_stat(int sg_fd, const struct join_row_t * jrp, const struct tuple_acronym_val * tavp, const struct opts_t * op) { int ret, len, s_byte, s_bit, n_bits, k; uint64_t ui; const struct acronym2tuple * ap; if (NULL == tavp->acron) { s_byte = tavp->start_byte; s_bit = tavp->start_bit; n_bits = tavp->num_bits; } if (tavp->acron) { for (ap = ecs_a2t_arr; ap->acron; ++ ap) { if (((jrp->etype == ap->etype) || (-1 == ap->etype)) && strcase_eq(tavp->acron, ap->acron)) break; } if (ap->acron) { s_byte = ap->start_byte; s_bit = ap->start_bit; n_bits = ap->num_bits; } else { if (-1 != ap->etype) { for (ap = ecs_a2t_arr; ap->acron; ++ap) { if (0 == strcase_eq(tavp->acron, ap->acron)) { pr2serr(">>> Found %s acronym but not for element " "type %d\n", tavp->acron, jrp->etype); break; } } } return -2; } } if (op->verbose > 1) pr2serr(" s_byte=%d, s_bit=%d, n_bits=%d\n", s_byte, s_bit, n_bits); if (op->get_str) { ui = get_big_endian(jrp->enc_statp + s_byte, s_bit, n_bits); if (op->do_hex) printf("0x%" PRIx64 "\n", ui); else printf("%" PRId64 "\n", (int64_t)ui); } else { /* --set or --clear */ if ((0 == op->mask_ign) && (jrp->etype < NUM_ETC)) { if (op->verbose > 2) pr2serr("Applying mask to element status [etc=%d] prior to " "modify then write\n", jrp->etype); for (k = 0; k < 4; ++k) jrp->enc_statp[k] &= ses3_element_cmask_arr[jrp->etype][k]; } else jrp->enc_statp[0] &= 0x40; /* keep PRDFAIL is set in byte 0 */ /* next we modify requested bit(s) */ set_big_endian((uint64_t)tavp->val, jrp->enc_statp + s_byte, s_bit, n_bits); jrp->enc_statp[0] |= 0x80; /* set SELECT bit */ if (op->byte1_given) enc_stat_rsp[1] = op->byte1; len = (enc_stat_rsp[2] << 8) + enc_stat_rsp[3] + 4; ret = do_senddiag(sg_fd, 1, enc_stat_rsp, len, 1, op->verbose); if (ret) { pr2serr("couldn't send Enclosure Control page\n"); return -1; } } return 0; } /* DPC_THRESHOLD * Do clear/get/set (cgs) on Threshold In/Out page. Return 0 for ok, * -2 for acronym not found, else -1 . */ static int cgs_threshold(int sg_fd, const struct join_row_t * jrp, const struct tuple_acronym_val * tavp, const struct opts_t * op) { int ret, len, s_byte, s_bit, n_bits; uint64_t ui; const struct acronym2tuple * ap; if (NULL == jrp->thresh_inp) { pr2serr("No Threshold In/Out element available\n"); return -1; } if (NULL == tavp->acron) { s_byte = tavp->start_byte; s_bit = tavp->start_bit; n_bits = tavp->num_bits; } if (tavp->acron) { for (ap = th_a2t_arr; ap->acron; ++ap) { if (((jrp->etype == ap->etype) || (-1 == ap->etype)) && strcase_eq(tavp->acron, ap->acron)) break; } if (ap->acron) { s_byte = ap->start_byte; s_bit = ap->start_bit; n_bits = ap->num_bits; } else return -2; } if (op->get_str) { ui = get_big_endian(jrp->thresh_inp + s_byte, s_bit, n_bits); if (op->do_hex) printf("0x%" PRIx64 "\n", ui); else printf("%" PRId64 "\n", (int64_t)ui); } else { set_big_endian((uint64_t)tavp->val, jrp->thresh_inp + s_byte, s_bit, n_bits); if (op->byte1_given) threshold_rsp[1] = op->byte1; len = (threshold_rsp[2] << 8) + threshold_rsp[3] + 4; ret = do_senddiag(sg_fd, 1, threshold_rsp, len, 1, op->verbose); if (ret) { pr2serr("couldn't send Threshold Out page\n"); return -1; } } return 0; } /* DPC_ADD_ELEM_STATUS * Do get (cgs) on Additional element status page. Return 0 for ok, * -2 for acronym not found, else -1 . */ static int cgs_additional_el(const struct join_row_t * jrp, const struct tuple_acronym_val * tavp, const struct opts_t * op) { int s_byte, s_bit, n_bits; uint64_t ui; const struct acronym2tuple * ap; if (NULL == jrp->add_elem_statp) { pr2serr("No additional element status element available\n"); return -1; } if (NULL == tavp->acron) { s_byte = tavp->start_byte; s_bit = tavp->start_bit; n_bits = tavp->num_bits; } if (tavp->acron) { for (ap = ae_sas_a2t_arr; ap->acron; ++ap) { if (((jrp->etype == ap->etype) || (-1 == ap->etype)) && strcase_eq(tavp->acron, ap->acron)) break; } if (ap->acron) { s_byte = ap->start_byte; s_bit = ap->start_bit; n_bits = ap->num_bits; } else return -2; } if (op->get_str) { ui = get_big_endian(jrp->add_elem_statp + s_byte, s_bit, n_bits); if (op->do_hex) printf("0x%" PRIx64 "\n", ui); else printf("%" PRId64 "\n", (int64_t)ui); } else { pr2serr("--clear and --set not available for Additional Element " "Status page\n"); return -1; } return 0; } /* Do --clear, --get or --set . * Returns 0 for success, any other return value is an error. */ static int ses_cgs(int sg_fd, const struct tuple_acronym_val * tavp, struct opts_t * op) { int ret, k, j, desc_len, dn_len, found; const struct join_row_t * jrp; const unsigned char * ed_ucp; char b[64]; found = 0; if (NULL == tavp->acron) { if (! op->page_code_given) op->page_code = DPC_ENC_CONTROL; ++found; } else if (is_acronym_in_status_ctl(tavp)) { op->page_code = DPC_ENC_CONTROL; ++found; } else if (is_acronym_in_threshold(tavp)) { op->page_code = DPC_THRESHOLD; ++found; } else if (is_acronym_in_additional(tavp)) { op->page_code = DPC_ADD_ELEM_STATUS; ++found; } if (! found) { pr2serr("acroynm %s not found (try '-ee' option)\n", tavp->acron); return -1; } ret = join_work(sg_fd, op, 0); if (ret) return ret; dn_len = op->desc_name ? (int)strlen(op->desc_name) : 0; for (k = 0, jrp = join_arr; ((k < MX_JOIN_ROWS) && jrp->enc_statp); ++k, ++jrp) { if (op->ind_given) { if (op->ind_th != jrp->el_ind_th) continue; if (op->ind_indiv != jrp->el_ind_indiv) continue; } else if (op->desc_name) { ed_ucp = jrp->elem_descp; if (NULL == ed_ucp) continue; desc_len = (ed_ucp[2] << 8) + ed_ucp[3]; /* some element descriptor strings have a trailing NULL and * count it; adjust */ if ('\0' == ed_ucp[4 + desc_len - 1]) --desc_len; if (desc_len != dn_len) continue; if (0 != strncmp(op->desc_name, (const char *)(ed_ucp + 4), desc_len)) continue; } else if (op->dev_slot_num >= 0) { if (op->dev_slot_num != jrp->dev_slot_num) continue; } else if (saddr_non_zero(op->sas_addr)) { for (j = 0; j < 8; ++j) { if (op->sas_addr[j] != jrp->sas_addr[j]) break; } if (j < 8) continue; } if (DPC_ENC_CONTROL == op->page_code) ret = cgs_enc_ctl_stat(sg_fd, jrp, tavp, op); else if (DPC_THRESHOLD == op->page_code) ret = cgs_threshold(sg_fd, jrp, tavp, op); else if (DPC_ADD_ELEM_STATUS == op->page_code) ret = cgs_additional_el(jrp, tavp, op); else { pr2serr("page %s not supported for cgs\n", find_element_tname(op->page_code, b, sizeof(b))); ret = -1; } if (ret) return ret; break; } if ((NULL == jrp->enc_statp) || (k >= MX_JOIN_ROWS)) { if (op->desc_name) pr2serr("descriptor name: %s not found (check the 'ed' page " "[0x7])\n", op->desc_name); else if (op->dev_slot_num >= 0) pr2serr("device slot number: %d not found\n", op->dev_slot_num); else if (saddr_non_zero(op->sas_addr)) pr2serr("SAS address not found\n"); else pr2serr("index: %d,%d not found\n", op->ind_th, op->ind_indiv); return -1; } return 0; } /* Called when '--nickname=SEN' given. First calls status page to fetch * the generation code. Returns 0 for success, any other return value is * an error. */ static int ses_set_nickname(int sg_fd, struct opts_t * op) { int res, len; int resp_len = 0; unsigned char b[64]; const int control_plen = 0x24; memset(b, 0, sizeof(b)); /* Only after the generation code, offset 4 for 4 bytes */ res = do_rec_diag(sg_fd, DPC_SUBENC_NICKNAME, b, 8, op, &resp_len); if (res) { pr2serr("set_nickname: Subenclosure nickname status page, res=%d\n", res); return -1; } if (resp_len < 8) { pr2serr("set_nickname: Subenclosure nickname status page, response " "length too short: %d\n", resp_len); return -1; } if (op->verbose) { unsigned int gc; gc = (b[4] << 24) + (b[5] << 16) + (b[6] << 8) + b[7]; pr2serr("set_nickname: generation code from status page: %u\n", gc); } b[0] = (unsigned char)DPC_SUBENC_NICKNAME; /* just in case */ b[1] = (unsigned char)op->seid; b[2] = (unsigned char)(control_plen >> 8); b[3] = (unsigned char)control_plen; len = strlen(op->nickname_str); if (len > 32) len = 32; memcpy(b + 8, op->nickname_str, len); return do_senddiag(sg_fd, 1, b, control_plen + 4, 1, op->verbose); } static void enumerate_diag_pages(void) { const struct diag_page_code * pcdp; const struct diag_page_abbrev * ap; int got1; printf("Diagnostic pages, followed by abbreviation(s) then page code:\n"); for (pcdp = dpc_arr; pcdp->desc; ++pcdp) { printf(" %s [", pcdp->desc); for (ap = dp_abbrev, got1 = 0; ap->abbrev; ++ap) { if (ap->page_code == pcdp->page_code) { printf("%s%s", (got1 ? "," : ""), ap->abbrev); ++got1; } } printf("] [0x%x]\n", pcdp->page_code); } } /* Output from --enumerate or --list option. Note that the output is * different when the option is given twice. */ static void enumerate_work(const struct opts_t * op) { int num; const struct element_type_t * etp; const struct acronym2tuple * ap; char b[64]; char a[160]; const char * cp; if (op->dev_name) printf(">>> DEVICE %s ignored when --%s option given.\n", op->dev_name, (op->do_list ? "list" : "enumerate")); num = op->enumerate + op->do_list; if (num < 2) { enumerate_diag_pages(); printf("\nSES element type names, followed by abbreviation and " "element type code:\n"); for (etp = element_type_arr; etp->desc; ++etp) printf(" %s [%s] [0x%x]\n", etp->desc, etp->abbrev, etp->elem_type_code); } else { /* command line has multiple --enumerate and/or --list options */ printf("--clear, --get, --set acronyms for Enclosure Status/Control " "['es' or 'ec'] page:\n"); for (ap = ecs_a2t_arr; ap->acron; ++ap) { cp = (ap->etype < 0) ? "*" : find_element_tname(ap->etype, b, sizeof(b)); snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron, (cp ? cp : "??"), ap->start_byte, ap->start_bit, ap->num_bits); if (ap->info) printf("%-44s %s\n", a, ap->info); else printf("%s\n", a); } printf("\n--clear, --get, --set acronyms for Threshold In/Out " "['th'] page:\n"); for (ap = th_a2t_arr; ap->acron; ++ap) { cp = (ap->etype < 0) ? "*" : find_element_tname(ap->etype, b, sizeof(b)); snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron, (cp ? cp : "??"), ap->start_byte, ap->start_bit, ap->num_bits); if (ap->info) printf("%-34s %s\n", a, ap->info); else printf("%s\n", a); } printf("\n--get acronyms for Additional Element Status ['aes'] page " "(SAS EIP=1):\n"); for (ap = ae_sas_a2t_arr; ap->acron; ++ap) { cp = (ap->etype < 0) ? "*" : find_element_tname(ap->etype, b, sizeof(b)); snprintf(a, sizeof(a), " %s [%s] [%d:%d:%d]", ap->acron, (cp ? cp : "??"), ap->start_byte, ap->start_bit, ap->num_bits); if (ap->info) printf("%-34s %s\n", a, ap->info); else printf("%s\n", a); } } } int main(int argc, char * argv[]) { int sg_fd, res; char buff[128]; char b[80]; int pd_type = 0; int have_cgs = 0; int ret = 0; struct sg_simple_inquiry_resp inq_resp; const char * cp; struct opts_t opts; struct opts_t * op; struct tuple_acronym_val tav; op = &opts; memset(op, 0, sizeof(*op)); res = cl_process(op, argc, argv); if (res) return SG_LIB_SYNTAX_ERROR; if (op->do_version) { pr2serr("version: %s\n", version_str); return 0; } if (op->do_help) { usage(op->do_help); return 0; } if (op->enumerate || op->do_list) { enumerate_work(op); return 0; } if (op->num_cgs) { have_cgs = 1; cp = op->clear_str ? op->clear_str : (op->get_str ? op->get_str : op->set_str); strncpy(buff, cp, sizeof(buff) - 1); buff[sizeof(buff) - 1] = '\0'; if (parse_cgs_str(buff, &tav)) { pr2serr("unable to decode STR argument to --clear, --get or " "--set\n"); return SG_LIB_SYNTAX_ERROR; } if (op->get_str && tav.val_str) pr2serr("--get option ignoring = at the end of STR " "argument\n"); if (! (op->ind_given || op->desc_name || (op->dev_slot_num >= 0) || saddr_non_zero(op->sas_addr))) { pr2serr("with --clear, --get or --set option need either\n " "--index, --descriptor, --dev-slot-num or --sas-addr\n"); return SG_LIB_SYNTAX_ERROR; } if (NULL == tav.val_str) { if (op->clear_str) tav.val = 0; if (op->set_str) tav.val = 1; } if (op->page_code_given && (DPC_ENC_STATUS != op->page_code) && (DPC_THRESHOLD != op->page_code) && (DPC_ADD_ELEM_STATUS != op->page_code)) { pr2serr("--clear, --get or --set options only supported for the " "Enclosure\nControl/Status, Threshold In/Out and " "Additional Element Status pages\n"); return SG_LIB_SYNTAX_ERROR; } } #ifdef SG_LIB_WIN32 #ifdef SG_LIB_WIN32_DIRECT if (op->verbose > 4) pr2serr("Initial win32 SPT interface state: %s\n", scsi_pt_win32_spt_state() ? "direct" : "indirect"); if (op->maxlen >= 16384) scsi_pt_win32_direct(SG_LIB_WIN32_DIRECT /* SPT pt interface */); #endif #endif sg_fd = sg_cmds_open_device(op->dev_name, op->o_readonly, op->verbose); if (sg_fd < 0) { pr2serr("open error: %s: %s\n", op->dev_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (! (op->do_raw || have_cgs)) { if (sg_simple_inquiry(sg_fd, &inq_resp, 1, op->verbose)) { pr2serr("%s doesn't respond to a SCSI INQUIRY\n", op->dev_name); ret = SG_LIB_CAT_OTHER; goto err_out; } else { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); pd_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(pd_type, sizeof(buff), buff); if (0xd == pd_type) { if (op->verbose) printf(" enclosure services device\n"); } else if (0x40 & inq_resp.byte_6) printf(" %s device has EncServ bit set\n", cp); else printf(" %s device (not an enclosure)\n", cp); } } if (op->nickname_str) ret = ses_set_nickname(sg_fd, op); else if (have_cgs) ret = ses_cgs(sg_fd, &tav, op); else if (op->do_join) ret = join_work(sg_fd, op, 1); else if (op->do_status) ret = ses_process_status_page(sg_fd, op); else { /* control page requested */ op->data_arr[0] = op->page_code; op->data_arr[1] = op->byte1; op->data_arr[2] = (op->arr_len >> 8) & 0xff; op->data_arr[3] = op->arr_len & 0xff; switch (op->page_code) { case DPC_ENC_CONTROL: /* Enclosure Control diagnostic page [0x2] */ printf("Sending Enclosure Control [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Enclosure Control page\n"); goto err_out; } break; case DPC_STRING: /* String Out diagnostic page [0x4] */ printf("Sending String Out [0x%x] page, with page length=%d " "bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send String Out page\n"); goto err_out; } break; case DPC_THRESHOLD: /* Threshold Out diagnostic page [0x5] */ printf("Sending Threshold Out [0x%x] page, with page length=%d " "bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Threshold Out page\n"); goto err_out; } break; case DPC_ARRAY_CONTROL: /* Array control diagnostic page [0x6] */ printf("Sending Array Control [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Array Control page\n"); goto err_out; } break; case DPC_SUBENC_STRING: /* Subenclosure String Out page [0xc] */ printf("Sending Subenclosure String Out [0x%x] page, with page " "length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Subenclosure String Out page\n"); goto err_out; } break; case DPC_DOWNLOAD_MICROCODE: /* Download Microcode Control [0xe] */ printf("Sending Download Microcode Control [0x%x] page, with " "page length=%d bytes\n", op->page_code, op->arr_len); printf(" Perhaps it would be better to use the sg_ses_microcode " "utility\n"); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Download Microcode Control page\n"); goto err_out; } break; case DPC_SUBENC_NICKNAME: /* Subenclosure Nickname Control [0xf] */ printf("Sending Subenclosure Nickname Control [0x%x] page, with " "page length=%d bytes\n", op->page_code, op->arr_len); ret = do_senddiag(sg_fd, 1, op->data_arr, op->arr_len + 4, 1, op->verbose); if (ret) { pr2serr("couldn't send Subenclosure Nickname Control page\n"); goto err_out; } break; default: pr2serr("Setting SES control page 0x%x not supported by this " "utility\n", op->page_code); pr2serr("That can be done with the sg_senddiag utility with its " "'--raw=' option\n"); ret = SG_LIB_SYNTAX_ERROR; break; } } err_out: if (0 == op->do_status) { sg_get_category_sense_str(ret, sizeof(b), b, op->verbose); pr2serr(" %s\n", b); } if (ret && (0 == op->verbose)) pr2serr("Problem detected, try again with --verbose option for more " "information\n"); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_vpd_vendor.c0000664000175000017500000011171112372451340016145 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifndef SG_LIB_MINGW #include #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" /* This is a companion file to sg_vpd.c . It contains logic to output and decode vendor specific VPD pages This program fetches Vital Product Data (VPD) pages from the given device and outputs it as directed. VPD pages are obtained via a SCSI INQUIRY command. Most of the data in this program is obtained from the SCSI SPC-4 document at http://www.t10.org . Acknowledgments: - Lars Marowsky-Bree contributed Unit Path Report VPD page decoding for EMC CLARiiON devices [20041016] - Hannes Reinecke contributed RDAC vendor specific VPD pages [20060421] - Jonathan McDowell contributed HP/3PAR InServ VPD page [0xc0] containing volume information [20110922] */ /* vendor/product identifiers */ #define VPD_VP_SEAGATE 0 #define VPD_VP_RDAC 1 #define VPD_VP_EMC 2 #define VPD_VP_DDS 3 #define VPD_VP_HP3PAR 4 #define VPD_VP_LTO5 5 #define VPD_VP_LTO6 6 /* vendor VPD pages */ #define VPD_V_HP3PAR 0xc0 #define VPD_V_FIRM_SEA 0xc0 #define VPD_V_UPR_EMC 0xc0 #define VPD_V_HVER_RDAC 0xc0 #define VPD_V_FVER_DDS 0xc0 #define VPD_V_FVER_LTO6 0xc0 #define VPD_V_DCRL_LTO5 0xc0 #define VPD_V_DATC_SEA 0xc1 #define VPD_V_FVER_RDAC 0xc1 #define VPD_V_HVER_LTO6 0xc1 #define VPD_V_DSN_LTO5 0xc1 #define VPD_V_JUMP_SEA 0xc2 #define VPD_V_SVER_RDAC 0xc2 #define VPD_V_PCA_LTO6 0xc2 #define VPD_V_DEV_BEH_SEA 0xc3 #define VPD_V_FEAT_RDAC 0xc3 #define VPD_V_MECH_LTO6 0xc3 #define VPD_V_SUBS_RDAC 0xc4 #define VPD_V_HEAD_LTO6 0xc4 #define VPD_V_ACI_LTO6 0xc5 #define VPD_V_DUCD_LTO5 0xc7 #define VPD_V_EDID_RDAC 0xc8 #define VPD_V_MPDS_LTO5 0xc8 #define VPD_V_VAC_RDAC 0xc9 #define VPD_V_RVSI_RDAC 0xca #define VPD_V_SAID_RDAC 0xd0 #define DEF_ALLOC_LEN 252 #define MX_ALLOC_LEN (0xc000 + 0x80) /* These structures are duplicates of those of the same name in * sg_vpd.c . Take care that both are the same. */ struct opts_t { int do_all; int do_enum; int do_hex; int num_vpd; int do_ident; int do_long; int maxlen; int do_quiet; int do_raw; int vend_prod_num; int verbose; const char * device_name; const char * page_str; const char * inhex_fn; const char * vend_prod; }; struct svpd_values_name_t { int value; /* VPD page number */ int subvalue; /* to differentiate if value+pdt are not unique */ int pdt; /* peripheral device type id, -1 is the default */ /* (all or not applicable) value */ const char * acron; const char * name; }; int vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page, int mxlen, int vb, int * rlenp); /* sharing large global buffer, defined in sg_vpd.c */ extern unsigned char rsp_buff[]; /* end of section copied from sg_vpd.c . Maybe sg_vpd.h is needed */ struct svpd_vp_name_t { int vend_prod_num; /* vendor/product identifier */ const char * acron; const char * name; }; /* Supported vendor specific VPD pages */ /* Arrange in alphabetical order by acronym */ static struct svpd_vp_name_t vp_arr[] = { {VPD_VP_DDS, "dds", "DDS tape family from IBM"}, {VPD_VP_EMC, "emc", "EMC (company)"}, {VPD_VP_HP3PAR, "hp3par", "3PAR array (HP was Left Hand)"}, {VPD_VP_LTO5, "lto5", "LTO-5 tape/systems (IBM)"}, {VPD_VP_LTO6, "lto6", "LTO-6 tape/systems (IBM)"}, {VPD_VP_RDAC, "rdac", "RDAC array (EMC Clariion)"}, {VPD_VP_SEAGATE, "sea", "Seagate disk"}, {0, NULL, NULL}, }; /* Supported vendor specific VPD pages */ /* 'subvalue' holds vendor/product number to disambiguate */ /* Arrange in alphabetical order by acronym */ static struct svpd_values_name_t vendor_vpd_pg[] = { {VPD_V_ACI_LTO6, VPD_VP_LTO6, 1, "aci", "ACI revision level (LTO-6)"}, {VPD_V_DATC_SEA, VPD_VP_SEAGATE, 0, "datc", "Date code (Seagate)"}, {VPD_V_DCRL_LTO5, VPD_VP_LTO5, 1, "dcrl" , "Drive component revision " "levels (LTO-5)"}, {VPD_V_FVER_DDS, VPD_VP_DDS, 1, "ddsver", "Firmware revision (DDS)"}, {VPD_V_DEV_BEH_SEA, VPD_VP_SEAGATE, 0, "devb", "Device behavior " "(Seagate)"}, {VPD_V_DSN_LTO5, VPD_VP_LTO5, 1, "dsn" , "Drive serial numbers (LTO-5)"}, {VPD_V_DUCD_LTO5, VPD_VP_LTO5, 1, "ducd" , "Device unique " "configuration data (LTO-5)"}, {VPD_V_EDID_RDAC, VPD_VP_RDAC, 0, "edid", "Extended device " "identification (RDAC)"}, {VPD_V_FEAT_RDAC, VPD_VP_RDAC, 0, "feat", "Feature Parameters (RDAC)"}, {VPD_V_FIRM_SEA, VPD_VP_SEAGATE, 0, "firm", "Firmware numbers " "(Seagate)"}, {VPD_V_FVER_LTO6, VPD_VP_LTO6, 0, "frl" , "Firmware revision level " "(LTO-6)"}, {VPD_V_FVER_RDAC, VPD_VP_RDAC, 0, "fver", "Firmware version (RDAC)"}, {VPD_V_HEAD_LTO6, VPD_VP_LTO6, 1, "head", "Head Assy revision level " "(LTO-6)"}, {VPD_V_HP3PAR, VPD_VP_HP3PAR, 0, "hp3par", "Volume information " "(HP/3PAR)"}, {VPD_V_HVER_LTO6, VPD_VP_LTO6, 1, "hrl", "Hardware revision level " "(LTO-6)"}, {VPD_V_HVER_RDAC, VPD_VP_RDAC, 0, "hver", "Hardware version (RDAC)"}, {VPD_V_JUMP_SEA, VPD_VP_SEAGATE, 0, "jump", "Jump setting (Seagate)"}, {VPD_V_MECH_LTO6, VPD_VP_LTO6, 1, "mech", "Mechanism revision level " "(LTO-6)"}, {VPD_V_MPDS_LTO5, VPD_VP_LTO5, 1, "mpds" , "Mode parameter default " "settings (LTO-5)"}, {VPD_V_PCA_LTO6, VPD_VP_LTO6, 1, "pca", "PCA revision level (LTO-6)"}, {VPD_V_RVSI_RDAC, VPD_VP_RDAC, 0, "rvsi", "Replicated volume source " "identifier (RDAC)"}, {VPD_V_SAID_RDAC, VPD_VP_RDAC, 0, "said", "Storage array world wide " "name (RDAC)"}, {VPD_V_SUBS_RDAC, VPD_VP_RDAC, 0, "sub", "Subsystem identifier (RDAC)"}, {VPD_V_SVER_RDAC, VPD_VP_RDAC, 0, "sver", "Software version (RDAC)"}, {VPD_V_UPR_EMC, VPD_VP_EMC, 0, "upr", "Unit path report (EMC)"}, {VPD_V_VAC_RDAC, VPD_VP_RDAC, 0, "vac", "Volume access control (RDAC)"}, {0, 0, 0, NULL, NULL}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static int is_like_pdt(int actual_pdt, const struct svpd_values_name_t * vnp) { if (actual_pdt == vnp->pdt) return 1; if (PDT_DISK == vnp->pdt) { switch (actual_pdt) { case PDT_DISK: case PDT_RBC: case PDT_PROCESSOR: case PDT_SAC: case PDT_ZBC: return 1; default: return 0; } } else if (PDT_TAPE == vnp->pdt) { switch (actual_pdt) { case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: return 1; default: return 0; } } else return 0; } static const struct svpd_values_name_t * svpd_get_v_detail(int page_num, int vend_prod_num, int pdt) { const struct svpd_values_name_t * vnp; int vp, ty; vp = (vend_prod_num < 0) ? 1 : 0; ty = (pdt < 0) ? 1 : 0; for (vnp = vendor_vpd_pg; vnp->acron; ++vnp) { if ((page_num == vnp->value) && (vp || (vend_prod_num == vnp->subvalue)) && (ty || is_like_pdt(pdt, vnp))) return vnp; } #if 0 if (! ty) return svpd_get_v_detail(page_num, vend_prod_num, -1); if (! vp) return svpd_get_v_detail(page_num, -1, pdt); #endif return NULL; } const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num, int vend_prod_num) { const struct svpd_values_name_t * vnp; for (vnp = vendor_vpd_pg; vnp->acron; ++vnp) { if ((page_num == vnp->value) && ((vend_prod_num < 0) || (vend_prod_num == vnp->subvalue))) return vnp; } return NULL; } int svpd_find_vp_num_by_acron(const char * vp_ap) { size_t len; const struct svpd_vp_name_t * vpp; for (vpp = vp_arr; vpp->acron; ++vpp) { len = strlen(vpp->acron); if (0 == strncmp(vpp->acron, vp_ap, len)) return vpp->vend_prod_num; } return -1; } const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap) { const struct svpd_values_name_t * vnp; for (vnp = vendor_vpd_pg; vnp->acron; ++vnp) { if (0 == strcmp(vnp->acron, ap)) return vnp; } return NULL; } /* if vend_prod_num < -1 then list vendor_product ids + vendor pages, =-1 * list only vendor_product ids, else list pages for that vend_prod_num */ void svpd_enumerate_vendor(int vend_prod_num) { const struct svpd_vp_name_t * vpp; const struct svpd_values_name_t * vnp; int seen; if (vend_prod_num < 0) { for (seen = 0, vpp = vp_arr; vpp->acron; ++vpp) { if (vpp->name) { if (! seen) { printf("\nVendor/product identifiers:\n"); seen = 1; } printf(" %-10s %d %s\n", vpp->acron, vpp->vend_prod_num, vpp->name); } } } if (-1 == vend_prod_num) return; for (seen = 0, vnp = vendor_vpd_pg; vnp->acron; ++vnp) { if ((vend_prod_num >= 0) && (vend_prod_num != vnp->subvalue)) continue; if (vnp->name) { if (! seen) { printf("\nVendor specific VPD pages:\n"); seen = 1; } printf(" %-10s 0x%02x,%d %s\n", vnp->acron, vnp->value, vnp->subvalue, vnp->name); } } } int svpd_count_vendor_vpds(int num_vpd, int vend_prod_num) { const struct svpd_values_name_t * vnp; int matches; for (vnp = vendor_vpd_pg, matches = 0; vnp->acron; ++vnp) { if ((num_vpd == vnp->value) && vnp->name) { if ((vend_prod_num < 0) || (vend_prod_num == vnp->subvalue)) { if (0 == matches) printf("Matching vendor specific VPD pages:\n"); ++matches; printf(" %-10s 0x%02x,%d %s\n", vnp->acron, vnp->value, vnp->subvalue, vnp->name); } } } return matches; } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } static void decode_vpd_c0_hp3par(unsigned char * buff, int len) { int rev; long offset; if (len < 24) { pr2serr("HP/3PAR vendor specific VPD page length too short=%d\n", len); return; } rev = buff[4]; printf(" Page revision: %d\n", rev); printf(" Volume type: %s\n", (buff[5] & 0x01) ? "tpvv" : (buff[5] & 0x02) ? "snap" : "base"); printf(" Reclaim supported: %s\n", (buff[5] & 0x04) ? "yes" : "no"); printf(" ATS supported: %s\n", (buff[5] & 0x10) ? "yes" : "no"); printf(" XCopy supported: %s\n", (buff[5] & 0x20) ? "yes" : "no"); if (rev > 3) { printf(" VV ID: %" PRIu64 "\n", ((uint64_t) buff[28] << 56) + ((uint64_t) buff[29] << 48) + ((uint64_t) buff[30] << 40) + ((uint64_t) buff[31] << 32) + ((uint64_t) buff[32] << 24) + (buff[33] << 16) + (buff[34] << 8) + buff[35]); offset = 44; printf(" Volume name: %s\n", &buff[offset]); printf(" Domain ID: %d\n", (buff[36] << 24) + (buff[37] << 16) + (buff[38] << 8) + buff[39]); offset += (buff[offset - 4] << 24) + (buff[offset - 3] << 16) + (buff[offset - 2] << 8) + buff[offset - 1] + 4; printf(" Domain Name: %s\n", &buff[offset]); offset += (buff[offset - 4] << 24) + (buff[offset - 3] << 16) + (buff[offset - 2] << 8) + buff[offset - 1] + 4; printf(" User CPG: %s\n", &buff[offset]); offset += (buff[offset - 4] << 24) + (buff[offset - 3] << 16) + (buff[offset - 2] << 8) + buff[offset - 1] + 4; printf(" Snap CPG: %s\n", &buff[offset]); offset += (buff[offset - 4] << 24) + (buff[offset - 3] << 16) + (buff[offset - 2] << 8) + buff[offset - 1]; printf(" VV policies: %s,%s,%s,%s\n", (buff[offset + 3] & 0x01) ? "stale_ss" : "no_stale_ss", (buff[offset + 3] & 0x02) ? "one_host" : "no_one_host", (buff[offset + 3] & 0x04) ? "tp_bzero" : "no_tp_bzero", (buff[offset + 3] & 0x08) ? "zero_detect" : "no_zero_detect"); } if (buff[5] & 0x04) { printf(" Allocation unit: %d\n", (buff[8] << 24) + (buff[9] << 16) + (buff[10] << 8) + buff[11]); printf(" Data pool size: %" PRIu64 "\n", (((uint64_t)buff[12]) << 56) + (((uint64_t)buff[13]) << 48) + (((uint64_t)buff[14]) << 40) + (((uint64_t)buff[15]) << 32) + (((uint64_t)buff[16]) << 24) + (buff[17] << 16) + (buff[18] << 8) + buff[19]); printf(" Space allocated: %" PRIu64 "\n", (((uint64_t)buff[20]) << 56) + (((uint64_t)buff[21]) << 48) + (((uint64_t)buff[22]) << 40) + (((uint64_t)buff[23]) << 32) + (((uint64_t)buff[24]) << 24) + (buff[25] << 16) + (buff[26] << 8) + buff[27]); } return; } static void decode_firm_vpd_c0_sea(unsigned char * buff, int len) { if (len < 28) { pr2serr("Seagate firmware numbers VPD page length too short=%d\n", len); return; } if (28 == len) { printf(" SCSI firmware release number: %.8s\n", buff + 4); printf(" Servo ROM release number: %.8s\n", buff + 20); } else { printf(" SCSI firmware release number: %.8s\n", buff + 4); printf(" Servo ROM release number: %.8s\n", buff + 12); printf(" SAP block point numbers (major/minor): %.8s\n", buff + 20); if (len < 36) return; printf(" Servo firmware release date: %.4s\n", buff + 28); printf(" Servo ROM release date: %.4s\n", buff + 32); if (len < 44) return; printf(" SAP firmware release number: %.8s\n", buff + 36); if (len < 52) return; printf(" SAP firmware release date: %.4s\n", buff + 44); printf(" SAP firmware release year: %.4s\n", buff + 48); if (len < 60) return; printf(" SAP manufacturing key: %.4s\n", buff + 52); printf(" Servo firmware product family and product family " "member: %.4s\n", buff + 56); } } static void decode_date_code_vpd_c1_sea(unsigned char * buff, int len) { if (len < 20) { pr2serr("Seagate Data code VPD page length too short=%d\n", len); return; } printf(" ETF log (mmddyyyy): %.8s\n", buff + 4); printf(" Compile date code (mmddyyyy): %.8s\n", buff + 12); } static void decode_dev_beh_vpd_c3_sea(unsigned char * buff, int len) { if (len < 25) { pr2serr("Seagate Device behaviour VPD page length too short=%d\n", len); return; } printf(" Version number: %d\n", buff[4]); printf(" Behaviour code: %d\n", buff[5]); printf(" Behaviour code version number: %d\n", buff[6]); printf(" ASCII family number: %.16s\n", buff + 7); printf(" Number of interleaves: %d\n", buff[23]); printf(" Default number of cache segments: %d\n", buff[24]); } static const char * lun_state_arr[] = { "LUN not bound or LUN_Z report", "LUN bound, but not owned by this SP", "LUN bound and owned by this SP", }; static const char * ip_mgmt_arr[] = { "No IP access", "Reserved (undefined)", "via IPv4", "via IPv6", }; static const char * sp_arr[] = { "SP A", "SP B", }; static const char * lun_op_arr[] = { "Normal operations", "I/O Operations being rejected, SP reboot or NDU in progress", }; static const char * failover_mode_arr[] = { "Legacy mode 0", "Unknown mode (1)", "Unknown mode (2)", "Unknown mode (3)", "Active/Passive (PNR) mode 1", "Unknown mode (5)", "Active/Active (ALUA) mode 4", "Unknown mode (7)", "Legacy mode 2", "Unknown mode (9)", "Unknown mode (10)", "Unknown mode (11)", "Unknown mode (12)", "Unknown mode (13)", "AIX Active/Passive (PAR) mode 3", "Unknown mode (15)", }; static void decode_upr_vpd_c0_emc(unsigned char * buff, int len) { int k, ip_mgmt, vpp80, lun_z; if (len < 3) { pr2serr("EMC upr VPD page [0xc0]: length too short=%d\n", len); return; } if (buff[9] != 0x00) { pr2serr("Unsupported page revision %d, decoding not possible.\n", buff[9]); return; } printf(" LUN WWN: "); for (k = 0; k < 16; ++k) printf("%02x", buff[10 + k]); printf("\n"); printf(" Array Serial Number: "); dStrRaw((const char *)&buff[50], buff[49]); printf("\n"); printf(" LUN State: "); if (buff[4] > 0x02) printf("Unknown (%x)\n", buff[4]); else printf("%s\n", lun_state_arr[buff[4]]); printf(" This path connects to: "); if (buff[8] > 0x01) printf("Unknown SP (%x)", buff[8]); else printf("%s", sp_arr[buff[8]]); printf(", Port Number: %u\n", buff[7]); printf(" Default Owner: "); if (buff[5] > 0x01) printf("Unknown (%x)\n", buff[5]); else printf("%s\n", sp_arr[buff[5]]); printf(" NO_ATF: %s, Access Logix: %s\n", buff[6] & 0x80 ? "set" : "not set", buff[6] & 0x40 ? "supported" : "not supported"); ip_mgmt = (buff[6] >> 4) & 0x3; printf(" SP IP Management Mode: %s\n", ip_mgmt_arr[ip_mgmt]); if (ip_mgmt == 2) printf(" SP IPv4 address: %u.%u.%u.%u\n", buff[44], buff[45], buff[46], buff[47]); else { printf(" SP IPv6 address: "); for (k = 0; k < 16; ++k) printf("%02x", buff[32 + k]); printf("\n"); } vpp80 = buff[30] & 0x08; lun_z = buff[30] & 0x04; printf(" System Type: %x, Failover mode: %s\n", buff[27], failover_mode_arr[buff[28] & 0x0f]); printf(" Inquiry VPP 0x80 returns: %s, Arraycommpath: %s\n", vpp80 ? "array serial#" : "LUN serial#", lun_z ? "Set to 1" : "Unknown"); printf(" Lun operations: %s\n", buff[48] > 1 ? "undefined" : lun_op_arr[buff[48]]); return; } static void decode_rdac_vpd_c0(unsigned char * buff, int len) { int memsize; char name[65]; if (len < 3) { pr2serr("Hardware Version VPD page length too short=%d\n", len); return; } if (buff[4] != 'h' && buff[5] != 'w' && buff[6] != 'r') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } printf(" Number of channels: %x\n", buff[8]); memsize = buff[10] << 8 | buff[11]; printf(" Processor Memory Size: %d\n", memsize); memset(name, 0, 65); memcpy(name, buff + 16, 64); printf(" Board Name: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 80, 16); printf(" Board Part Number: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 96, 12); printf(" Schematic Number: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 108, 4); printf(" Schematic Revision Number: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 112, 16); printf(" Board Serial Number: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 144, 8); printf(" Date of Manufacture: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 152, 2); printf(" Board Revision: %s\n", name); memset(name, 0, 65); memcpy(name, buff + 154, 2); printf(" Board Identifier: %s\n", name); return; } static void decode_rdac_vpd_c1(unsigned char * buff, int len) { int i, n, v, r, m, p, d, y, num_part; char part[5]; if (len < 3) { pr2serr("Firmware Version VPD page length too short=%d\n", len); return; } if (buff[4] != 'f' && buff[5] != 'w' && buff[6] != 'r') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } printf(" Firmware Version: %x.%x.%x\n", buff[8], buff[9], buff[10]); printf(" Firmware Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); num_part = (len - 12) / 16; n = 16; printf(" Partitions: %d\n", num_part); for (i = 0; i < num_part; i++) { memset(part,0, 5); memcpy(part, &buff[n], 4); printf(" Name: %s\n", part); n += 4; v = buff[n++]; r = buff[n++]; m = buff[n++]; p = buff[n++]; printf(" Version: %d.%d.%d.%d\n", v, r, m, p); m = buff[n++]; d = buff[n++]; y = buff[n++]; printf(" Date: %d/%d/%d\n", m, d, y); n += 5; } return; } static void decode_rdac_vpd_c2(unsigned char * buff, int len) { int i, n, v, r, m, p, d, y, num_part; char part[5]; if (len < 3) { pr2serr("Software Version VPD page length too short=%d\n", len); return; } if (buff[4] != 's' && buff[5] != 'w' && buff[6] != 'r') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } printf(" Software Version: %x.%x.%x\n", buff[8], buff[9], buff[10]); printf(" Software Date: %02d/%02d/%02d\n", buff[11], buff[12], buff[13]); printf(" Features:"); if (buff[14] & 0x01) printf(" Dual Active,"); if (buff[14] & 0x02) printf(" Series 3,"); if (buff[14] & 0x04) printf(" Multiple Sub-enclosures,"); if (buff[14] & 0x08) printf(" DCE/DRM,"); if (buff[14] & 0x10) printf(" AVT,"); printf("\n"); printf(" Max. #of LUNS: %d\n", buff[15]); num_part = (len - 12) / 16; n = 16; printf(" Partitions: %d\n", num_part); for (i = 0; i < num_part; i++) { memset(part,0, 5); memcpy(part, &buff[n], 4); printf(" Name: %s\n", part); n += 4; v = buff[n++]; r = buff[n++]; m = buff[n++]; p = buff[n++]; printf(" Version: %d.%d.%d.%d\n", v, r, m, p); m = buff[n++]; d = buff[n++]; y = buff[n++]; printf(" Date: %d/%d/%d\n", m, d, y); n += 5; } return; } static void decode_rdac_vpd_c3(unsigned char * buff, int len) { if (len < 0x2c) { pr2serr("Feature parameters VPD page length too short=%d\n", len); return; } if (buff[4] != 'p' && buff[5] != 'r' && buff[6] != 'm') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } printf(" Maximum number of drives per LUN: %d\n", buff[8]); printf(" Maximum number of hot spare drives: %d\n", buff[9]); printf(" UTM: %s\n", buff[11] & 0x80?"enabled":"disabled"); if ((buff[11] & 0x80)) printf(" UTM LUN: %02x\n", buff[11] & 0x7f); return; } static void decode_rdac_vpd_c4(unsigned char * buff, int len) { char subsystem_id[17]; char subsystem_rev[5]; char slot_id[3]; if (len < 0x1c) { pr2serr("Subsystem identifier VPD page length too short=%d\n", len); return; } if (buff[4] != 's' && buff[5] != 'u' && buff[6] != 'b') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } memset(subsystem_id, 0, 17); memcpy(subsystem_id, &buff[8], 16); memset(subsystem_rev, 0, 5); memcpy(subsystem_rev, &buff[24], 4); slot_id[0] = buff[28]; slot_id[1] = buff[29]; slot_id[2] = 0; printf(" Subsystem ID: %s\n Subsystem Revision: %s", subsystem_id, subsystem_rev); if (!strcmp(subsystem_rev, "10.0")) printf(" (Board ID 4884)\n"); else if (!strcmp(subsystem_rev, "12.0")) printf(" (Board ID 5884)\n"); else if (!strcmp(subsystem_rev, "13.0")) printf(" (Board ID 2882)\n"); else if (!strcmp(subsystem_rev, "13.1")) printf(" (Board ID 2880)\n"); else if (!strcmp(subsystem_rev, "14.0")) printf(" (Board ID 2822)\n"); else printf(" (Board ID unknown)\n"); printf(" Slot ID: %s\n", slot_id); return; } static void decode_rdac_vpd_c8(unsigned char * buff, int len) { int i; #ifndef SG_LIB_MINGW time_t tstamp; #endif char *c; char label[61]; int label_len; char uuid[33]; int uuid_len; if (len < 0xab) { pr2serr("Extended Device Identification VPD page length too " "short=%d\n", len); return; } if (buff[4] != 'e' && buff[5] != 'd' && buff[6] != 'i') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } uuid_len = buff[11]; for (i = 0, c = uuid; i < uuid_len; i++) { sprintf(c,"%02x",buff[12 + i]); c += 2; } printf(" Volume Unique Identifier: %s\n", uuid); #ifndef SG_LIB_MINGW tstamp = (buff[24] << 24) + (buff[25] << 16) + (buff[26] << 8) + buff[27]; printf(" Creation Number: %d, Timestamp: %s", (buff[22] << 8) + buff[23], ctime(&tstamp)); #else printf(" Creation Number: %d, Timestamp value: %u", (buff[22] << 8) + buff[23], (buff[24] << 24) + (buff[25] << 16) + (buff[26] << 8) + buff[27]); #endif memset(label, 0, 61); label_len = buff[28]; for(i = 0; i < (label_len - 1); ++i) *(label + i) = buff[29 + (2 * i) + 1]; printf(" Volume User Label: %s\n", label); uuid_len = buff[89]; for (i = 0, c = uuid; i < uuid_len; i++) { sprintf(c,"%02x",buff[90 + i]); c += 2; } printf(" Storage Array Unique Identifier: %s\n", uuid); memset(label, 0, 61); label_len = buff[106]; for(i = 0; i < (label_len - 1); ++i) *(label + i) = buff[107 + (2 * i) + 1]; printf(" Storage Array User Label: %s\n", label); for (i = 0, c = uuid; i < 8; i++) { sprintf(c,"%02x",buff[167 + i]); c += 2; } printf(" Logical Unit Number: %s\n", uuid); return; } static void decode_rdac_vpd_c9(unsigned char * buff, int len) { if (len < 3) { pr2serr("Volume Access Control VPD page length too short=%d\n", len); return; } if (buff[4] != 'v' && buff[5] != 'a' && buff[6] != 'c') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } if (buff[7] != '1') { pr2serr("Invalid page version '%c' (should be 1)\n", buff[7]); } printf(" AVT:"); if (buff[8] & 0x80) { printf(" Enabled"); if (buff[8] & 0x40) printf(" (Allow reads on sector 0)"); printf("\n"); } else { printf(" Disabled\n"); } printf(" Volume Access via: "); if (buff[8] & 0x01) printf("primary controller\n"); else printf("alternate controller\n"); printf(" Path priority: %d ", buff[9] & 0xf); switch(buff[9] & 0xf) { case 0x1: printf("(preferred path)\n"); break; case 0x2: printf("(secondary path)\n"); break; default: printf("(unknown)\n"); break; } return; } static void decode_rdac_vpd_ca(unsigned char * buff, int len) { int i; if (len < 16) { pr2serr("Replicated Volume Source Identifier VPD page length too " "short=%d\n", len); return; } if (buff[4] != 'r' && buff[5] != 'v' && buff[6] != 's') { pr2serr("Invalid page identifier %c%c%c%c, decoding not possible.\n", buff[4], buff[5], buff[6], buff[7]); return; } if (buff[8] & 0x01) { printf(" Snapshot Volume\n"); printf(" Base Volume WWID: "); for (i = 0; i < 16; i++) printf("%02x", buff[10 + i]); printf("\n"); } else if (buff[8] & 0x02) { printf(" Copy Target Volume\n"); printf(" Source Volume WWID: "); for (i = 0; i < 16; i++) printf("%02x", buff[10 + i]); printf("\n"); } else printf(" Neither a snapshot nor a copy target volume\n"); return; } static void decode_rdac_vpd_d0(unsigned char * buff, int len) { int i; if (len < 20) { pr2serr("Storage Array World Wide Name VPD page length too " "short=%d\n", len); return; } printf(" Storage Array WWN: "); for (i = 0; i < 16; i++) printf("%02x", buff[8 + i]); printf("\n"); return; } static void decode_dds_vpd_c0(unsigned char * buff, int len) { char firmware_rev[25]; char build_date[43]; char hw_conf[21]; char fw_conf[21]; if (len < 0xb3) { pr2serr("Vendor-Unique Firmware revision page invalid length=%d\n", len); return; } memset(firmware_rev, 0x0, 25); memcpy(firmware_rev, &buff[5], 24); printf(" %s\n", firmware_rev); memset(build_date, 0x0, 43); memcpy(build_date, &buff[30], 42); printf(" %s\n", build_date); memset(hw_conf, 0x0, 21); memcpy(hw_conf, &buff[73], 20); printf(" %s\n", hw_conf); memset(fw_conf, 0x0, 21); memcpy(fw_conf, &buff[94], 20); printf(" %s\n", fw_conf); return; } static void decode_lto6_vpd_cx(unsigned char * buff, int len, int page) { char str[32]; const char *comp = NULL; if (len < 0x5c) { pr2serr("Driver Component Revision Levels page invalid length=%d\n", len); return; } switch (page) { case 0xc0: comp = "Firmware"; break; case 0xc1: comp = "Hardware"; break; case 0xc2: comp = "PCA"; break; case 0xc3: comp = "Mechanism"; break; case 0xc4: comp = "Head Assy"; break; case 0xc5: comp = "ACI"; break; } if (!comp) { pr2serr("Driver Component Revision Level invalid page=0x%02x\n", page); return; } memset(str, 0x0, 32); memcpy(str, &buff[4], 26); printf(" %s\n", str); memset(str, 0x0, 32); memcpy(str, &buff[30], 19); printf(" %s\n", str); memset(str, 0x0, 32); memcpy(str, &buff[49], 24); printf(" %s\n", str); memset(str, 0x0, 32); memcpy(str, &buff[73], 23); printf(" %s\n", str); return; } static void decode_lto5_dcrl(unsigned char * buff, int len) { if (len < 0x2b) { pr2serr("Driver Component Revision Levels page (LTO-5) invalid " "length=%d\n", len); return; } printf(" Code name: %.12s\n", buff + 4); printf(" Time (hhmmss): %.7s\n", buff + 16); printf(" Date (yyyymmdd): %.8s\n", buff + 23); printf(" Platform: %.12s\n", buff + 31); } static void decode_lto5_dsn(unsigned char * buff, int len) { if (len < 0x1c) { pr2serr("Driver Serial Numbers page (LTO-5) invalid " "length=%d\n", len); return; } printf(" Manufacturing serial number: %.12s\n", buff + 4); printf(" Reported serial number: %.12s\n", buff + 16); } /* Returns 0 if successful, see sg_ll_inquiry() plus SG_LIB_SYNTAX_ERROR for unsupported page */ int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off) { int len, res; char name[64]; const struct svpd_values_name_t * vnp; int alloc_len = op->maxlen; unsigned char * rp; rp = rsp_buff + off; if (sg_fd >= 0) { if (0 == alloc_len) alloc_len = DEF_ALLOC_LEN; } res = vpd_fetch_page_from_dev(sg_fd, rp, op->num_vpd, alloc_len, op->verbose, &len); if (0 == res) { vnp = svpd_get_v_detail(op->num_vpd, op->vend_prod_num, 0xf & rp[0]); if (vnp && vnp->name) strcpy(name, vnp->name); else snprintf(name, sizeof(name) - 1, "Vendor VPD page=0x%x", op->num_vpd); if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 2)) printf("%s VPD Page:\n", name); if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, ((1 == op->do_hex) ? 0 : -1)); else { switch(op->num_vpd) { case 0xc0: if (VPD_VP_SEAGATE == op->vend_prod_num) decode_firm_vpd_c0_sea(rp, len); else if (VPD_VP_EMC == op->vend_prod_num) decode_upr_vpd_c0_emc(rp, len); else if (VPD_VP_HP3PAR == op->vend_prod_num) decode_vpd_c0_hp3par(rp, len); else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c0(rp, len); else if (VPD_VP_DDS == op->vend_prod_num) decode_dds_vpd_c0(rp, len); else if (VPD_VP_LTO5 == op->vend_prod_num) decode_lto5_dcrl(rp, len); else if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc1: if (VPD_VP_SEAGATE == op->vend_prod_num) decode_date_code_vpd_c1_sea(rp, len); else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c1(rp, len); else if (VPD_VP_LTO5 == op->vend_prod_num) decode_lto5_dsn(rp, len); else if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc2: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c2(rp, len); else if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc3: if (VPD_VP_SEAGATE == op->vend_prod_num) decode_dev_beh_vpd_c3_sea(rp, len); else if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c3(rp, len); else if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc4: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c4(rp, len); else if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc5: if (VPD_VP_LTO6 == op->vend_prod_num) decode_lto6_vpd_cx(rp, len, op->num_vpd); else dStrHex((const char *)rp, len, 0); break; case 0xc8: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c8(rp, len); else dStrHex((const char *)rp, len, 0); break; case 0xc9: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_c9(rp, len); else dStrHex((const char *)rp, len, 0); break; case 0xca: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_ca(rp, len); else dStrHex((const char *)rp, len, 0); break; case 0xd0: if (VPD_VP_RDAC == op->vend_prod_num) decode_rdac_vpd_d0(rp, len); else dStrHex((const char *)rp, len, 0); break; default: return SG_LIB_SYNTAX_ERROR; } return 0; } } else pr2serr("Vendor VPD page=0x%x failed to fetch", op->num_vpd); return res; } sg3_utils-1.40/src/sg_write_long.c0000664000175000017500000002175712335513125016161 0ustar douggdougg/* A utility program for the Linux OS SCSI subsystem. * Copyright (C) 2004-2014 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. * * This program issues the SCSI command WRITE LONG to a given SCSI device. * It sends the command with the logical block address passed as the lba * argument, and the transfer length set to the xfer_len argument. the * buffer to be writen to the device filled with 0xff, this buffer includes * the sector data and the ECC bytes. * * This code was contributed by Saeed Bishara */ #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "1.1( 20140516"; #define MAX_XFER_LEN 10000 /* #define SG_DEBUG */ #define ME "sg_write_long: " #define EBUFF_SZ 256 static struct option long_options[] = { {"16", 0, 0, 'S'}, {"cor_dis", 0, 0, 'c'}, {"help", 0, 0, 'h'}, {"in", 1, 0, 'i'}, {"lba", 1, 0, 'l'}, {"pblock", 0, 0, 'p'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {"wr_uncor", 0, 0, 'w'}, {"xfer_len", 1, 0, 'x'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_write_long [--16] [--cor_dis] [--help] [--in=IF] " "[--lba=LBA]\n" " [--pblock] [--verbose] [--version] " "[--wr_uncor]\n" " [--xfer_len=BTL] DEVICE\n" " where:\n" " --16|-S do WRITE LONG(16) (default: 10)\n" " --cor_dis|-c set correction disabled bit\n" " --help|-h print out usage message\n" " --in=IF|-i IF input from file called IF (default: " "use\n" " 0xff bytes as fill)\n" " --lba=LBA|-l LBA logical block address " "(default: 0)\n" " --pblock|-p physical block (default: logical " "block)\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --wr_uncor|-w set an uncorrectable error (no " "data transferred)\n" " --xfer_len=BTL|-x BTL byte transfer length (< 10000) " "(default:\n" " 520 bytes)\n\n" "Performs a SCSI WRITE LONG (10 or 16) command. Writes a single " "block\nincluding associated ECC data. Valid data can be obtained " "from the\nSCSI READ LONG command. See the sg_read_long utility.\n" ); } int main(int argc, char * argv[]) { int sg_fd, res, c, infd, offset; unsigned char * writeLongBuff = NULL; void * rawp = NULL; int xfer_len = 520; int cor_dis = 0; int pblock = 0; int wr_uncor = 0; int do_16 = 0; uint64_t llba = 0; int verbose = 0; int64_t ll; int got_stdin; const char * device_name = NULL; char file_name[256]; char b[80]; char ebuff[EBUFF_SZ]; const char * ten_or; int ret = 1; memset(file_name, 0, sizeof file_name); while (1) { int option_index = 0; c = getopt_long(argc, argv, "chi:l:pSvVwx:", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': cor_dis = 1; break; case 'h': case '?': usage(); return 0; case 'i': strncpy(file_name, optarg, sizeof(file_name)); break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } llba = (uint64_t)ll; break; case 'p': pblock = 1; break; case 'S': do_16 = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'w': wr_uncor = 1; break; case 'x': xfer_len = sg_get_num(optarg); if (-1 == xfer_len) { fprintf(stderr, "bad argument to '--xfer_len'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (wr_uncor) xfer_len = 0; else if (xfer_len >= MAX_XFER_LEN) { fprintf(stderr, "xfer_len (%d) is out of range ( < %d)\n", xfer_len, MAX_XFER_LEN); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (wr_uncor) { if ('\0' != file_name[0]) fprintf(stderr, ">>> warning: when '--wr_uncor' given " "'-in=' is ignored\n"); } else { if (NULL == (rawp = malloc(MAX_XFER_LEN))) { fprintf(stderr, ME "out of memory\n"); ret = SG_LIB_FILE_ERROR; goto err_out; } writeLongBuff = (unsigned char *)rawp; memset(rawp, 0xff, MAX_XFER_LEN); if (file_name[0]) { got_stdin = (0 == strcmp(file_name, "-")) ? 1 : 0; if (got_stdin) { infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { if ((infd = open(file_name, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for reading", file_name); perror(ebuff); goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } res = read(infd, writeLongBuff, xfer_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", file_name); perror(ebuff); if (! got_stdin) close(infd); goto err_out; } if (res < xfer_len) { fprintf(stderr, "tried to read %d bytes from %s, got %d " "bytes\n", xfer_len, file_name, res); fprintf(stderr, "pad with 0xff bytes and continue\n"); } if (! got_stdin) close(infd); } } if (verbose) fprintf(stderr, ME "issue write long to device %s\n\t\txfer_len= %d " "(0x%x), lba=%" PRIu64 " (0x%" PRIx64 ")\n cor_dis=%d, " "wr_uncor=%d, pblock=%d\n", device_name, xfer_len, xfer_len, llba, llba, cor_dis, wr_uncor, pblock); ten_or = do_16 ? "16" : "10"; if (do_16) res = sg_ll_write_long16(sg_fd, cor_dis, wr_uncor, pblock, llba, writeLongBuff, xfer_len, &offset, 1, verbose); else res = sg_ll_write_long10(sg_fd, cor_dis, wr_uncor, pblock, (unsigned int)llba, writeLongBuff, xfer_len, &offset, 1, verbose); ret = res; switch (res) { case 0: break; case SG_LIB_CAT_ILLEGAL_REQ_WITH_INFO: fprintf(stderr, "<<< device indicates 'xfer_len' should be %d " ">>>\n", xfer_len - offset); break; default: sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, " SCSI WRITE LONG (%s): %s\n", ten_or, b); break; } err_out: if (rawp) free(rawp); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_write_same.c0000664000175000017500000005216312422552302016137 0ustar douggdougg/* * Copyright (c) 2009-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_pt.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "1.07 20141021"; #define ME "sg_write_same: " #define WRITE_SAME10_OP 0x41 #define WRITE_SAME16_OP 0x93 #define VARIABLE_LEN_OP 0x7f #define WRITE_SAME32_SA 0xd #define WRITE_SAME32_ADD 0x18 #define WRITE_SAME10_LEN 10 #define WRITE_SAME16_LEN 16 #define WRITE_SAME32_LEN 32 #define RCAP10_RESP_LEN 8 #define RCAP16_RESP_LEN 32 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define DEF_TIMEOUT_SECS 60 #define DEF_WS_CDB_SIZE WRITE_SAME10_LEN #define DEF_WS_NUMBLOCKS 1 #define MAX_XFER_LEN (64 * 1024) #define EBUFF_SZ 256 static struct option long_options[] = { {"10", no_argument, 0, 'R'}, {"16", no_argument, 0, 'S'}, {"32", no_argument, 0, 'T'}, {"anchor", no_argument, 0, 'a'}, {"grpnum", required_argument, 0, 'g'}, {"help", no_argument, 0, 'h'}, {"in", required_argument, 0, 'i'}, {"lba", required_argument, 0, 'l'}, {"lbdata", no_argument, 0, 'L'}, {"ndob", no_argument, 0, 'N'}, {"num", required_argument, 0, 'n'}, {"pbdata", no_argument, 0, 'P'}, {"timeout", required_argument, 0, 'r'}, {"unmap", no_argument, 0, 'U'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {"wrprotect", required_argument, 0, 'w'}, {"xferlen", required_argument, 0, 'x'}, {0, 0, 0, 0}, }; struct opts_t { int anchor; int grpnum; char ifilename[256]; uint64_t lba; int lbdata; int ndob; int numblocks; int pbdata; int timeout; int unmap; int verbose; int wrprotect; int xfer_len; int pref_cdb_size; int want_ws10; }; static void usage() { fprintf(stderr, "Usage: " "sg_write_same [--10] [--16] [--32] [--anchor] [--grpnum=GN] " "[--help]\n" " [--in=IF] [--lba=LBA] [--lbdata] " "[--ndob] [--num=NUM]\n" " [--pbdata] [--timeout=TO] [--unmap] " "[--verbose]\n" " [--version] [--wrprotect=WRP] " "[xferlen=LEN]\n" " DEVICE\n" " where:\n" " --10|-R do WRITE SAME(10) (even if '--unmap' " "is given)\n" " --16|-S do WRITE SAME(16) (def: 10 unless " "'--unmap' given\n" " or LBA+NUM needs more than 32 bits)\n" " --32|-T do WRITE SAME(32) (def: 10 or 16)\n" " --anchor|-a set anchor field in cdb\n" " --grpnum=GN|-g GN GN is group number field (def: 0)\n" " --help|-h print out usage message\n" " --in=IF|-i IF IF is file to fetch one block of data " "from (use LEN\n" " bytes or whole file). Block written to " "DEVICE\n" " --lba=LBA|-l LBA LBA is the logical block address to " "start (def: 0)\n" " --lbdata|-L set LBDATA bit\n" " --ndob|-N set 'no data-out buffer' bit\n" " --num=NUM|-n NUM NUM is number of logical blocks to " "write (def: 1)\n" " [Beware NUM==0 means rest of device]\n" " --pbdata|-P set PBDATA bit\n" " --timeout=TO|-t TO command timeout (unit: seconds) (def: " "60)\n" " --unmap|-U set UNMAP bit\n" " --verbose|-v increase verbosity\n" " --version|-V print version string then exit\n" " --wrprotect=WPR|-w WPR WPR is the WRPROTECT field value " "(def: 0)\n" " --xferlen=LEN|-x LEN LEN is number of bytes from IF to " "send to\n" " DEVICE (def: IF file length)\n\n" "Performs a SCSI WRITE SAME (10, 16 or 32) command\n" ); } static int do_write_same(int sg_fd, const struct opts_t * op, const void * dataoutp, int * act_cdb_lenp) { int k, ret, res, sense_cat, cdb_len; uint64_t llba; uint32_t lba, unum; unsigned char wsCmdBlk[WRITE_SAME32_LEN]; unsigned char sense_b[SENSE_BUFF_LEN]; struct sg_pt_base * ptvp; cdb_len = op->pref_cdb_size; if (WRITE_SAME10_LEN == cdb_len) { llba = op->lba + op->numblocks; if ((op->numblocks > 0xffff) || (llba > ULONG_MAX) || op->ndob || (op->unmap && (0 == op->want_ws10))) { cdb_len = WRITE_SAME16_LEN; if (op->verbose) fprintf(stderr, "do_write_same: use WRITE SAME(16) instead " "of 10 byte cdb\n"); } } if (act_cdb_lenp) *act_cdb_lenp = cdb_len; memset(wsCmdBlk, 0, sizeof(wsCmdBlk)); switch (cdb_len) { case WRITE_SAME10_LEN: wsCmdBlk[0] = WRITE_SAME10_OP; wsCmdBlk[1] = ((op->wrprotect & 0x7) << 5); /* ANCHOR + UNMAP not allowed for WRITE_SAME10 in sbc3r24+r25 but * a proposal has been made to allow it. Anticipate approval. */ if (op->anchor) wsCmdBlk[1] |= 0x10; if (op->unmap) wsCmdBlk[1] |= 0x8; if (op->pbdata) wsCmdBlk[1] |= 0x4; if (op->lbdata) wsCmdBlk[1] |= 0x2; lba = (uint32_t)op->lba; for (k = 3; k >= 0; --k) { wsCmdBlk[2 + k] = (lba & 0xff); lba >>= 8; } wsCmdBlk[6] = (op->grpnum & 0x1f); wsCmdBlk[7] = ((op->numblocks >> 8) & 0xff); wsCmdBlk[8] = (op->numblocks & 0xff); break; case WRITE_SAME16_LEN: wsCmdBlk[0] = WRITE_SAME16_OP; wsCmdBlk[1] = ((op->wrprotect & 0x7) << 5); if (op->anchor) wsCmdBlk[1] |= 0x10; if (op->unmap) wsCmdBlk[1] |= 0x8; if (op->pbdata) wsCmdBlk[1] |= 0x4; if (op->lbdata) wsCmdBlk[1] |= 0x2; if (op->ndob) wsCmdBlk[1] |= 0x1; llba = op->lba; for (k = 7; k >= 0; --k) { wsCmdBlk[2 + k] = (llba & 0xff); llba >>= 8; } unum = op->numblocks; for (k = 3; k >= 0; --k) { wsCmdBlk[10 + k] = (unum & 0xff); unum >>= 8; } wsCmdBlk[14] = (op->grpnum & 0x1f); break; case WRITE_SAME32_LEN: /* Note: In Linux at this time the sg driver does not support * cdb_s > 16 bytes long, but the bsg driver does. */ wsCmdBlk[0] = VARIABLE_LEN_OP; wsCmdBlk[6] = (op->grpnum & 0x1f); wsCmdBlk[7] = WRITE_SAME32_ADD; wsCmdBlk[8] = ((WRITE_SAME32_SA >> 8) & 0xff); wsCmdBlk[9] = (WRITE_SAME32_SA & 0xff); wsCmdBlk[10] = ((op->wrprotect & 0x7) << 5); if (op->anchor) wsCmdBlk[10] |= 0x10; if (op->unmap) wsCmdBlk[10] |= 0x8; if (op->pbdata) wsCmdBlk[10] |= 0x4; if (op->lbdata) wsCmdBlk[10] |= 0x2; if (op->ndob) wsCmdBlk[10] |= 0x1; llba = op->lba; for (k = 7; k >= 0; --k) { wsCmdBlk[12 + k] = (llba & 0xff); llba >>= 8; } unum = op->numblocks; for (k = 3; k >= 0; --k) { wsCmdBlk[28 + k] = (unum & 0xff); unum >>= 8; } break; default: fprintf(stderr, "do_write_same: bad cdb length %d\n", cdb_len); return -1; } if (op->verbose > 1) { fprintf(stderr, " Write same(%d) cmd: ", cdb_len); for (k = 0; k < cdb_len; ++k) fprintf(stderr, "%02x ", wsCmdBlk[k]); fprintf(stderr, "\n Data-out buffer length=%d\n", op->xfer_len); } if ((op->verbose > 3) && (op->xfer_len > 0)) { fprintf(stderr, " Data-out buffer contents:\n"); dStrHexErr((const char *)dataoutp, op->xfer_len, 1); } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { fprintf(sg_warnings_strm, "Write same(%d): out of memory\n", cdb_len); return -1; } set_scsi_pt_cdb(ptvp, wsCmdBlk, cdb_len); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_out(ptvp, (unsigned char *)dataoutp, op->xfer_len); res = do_scsi_pt(ptvp, sg_fd, op->timeout, op->verbose); ret = sg_cmds_process_resp(ptvp, "Write same", res, 0, sense_b, 1 /*noisy */, op->verbose, &sense_cat); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; case SG_LIB_CAT_MEDIUM_HARD: { int valid, slen; uint64_t ull = 0; slen = get_scsi_pt_sense_len(ptvp); valid = sg_get_sense_info_fld(sense_b, slen, &ull); if (valid) fprintf(stderr, "Medium or hardware error starting at " "lba=%" PRIu64 " [0x%" PRIx64 "]\n", ull, ull); } ret = sense_cat; break; default: ret = sense_cat; break; } } else ret = 0; destruct_scsi_pt_obj(ptvp); return ret; } int main(int argc, char * argv[]) { int sg_fd, res, c, infd, prot_en, act_cdb_len, vb; int num_given = 0; int lba_given = 0; int if_given = 0; int got_stdin = 0; int64_t ll; uint32_t block_size; const char * device_name = NULL; char ebuff[EBUFF_SZ]; char b[80]; unsigned char resp_buff[RCAP16_RESP_LEN]; unsigned char * wBuff = NULL; int ret = -1; struct opts_t opts; struct opts_t * op; struct stat a_stat; op = &opts; memset(op, 0, sizeof(opts)); op->numblocks = DEF_WS_NUMBLOCKS; op->pref_cdb_size = DEF_WS_CDB_SIZE; op->timeout = DEF_TIMEOUT_SECS; vb = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "ag:hi:l:Ln:NPRSt:TUvVw:x:", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++op->anchor; break; case 'g': op->grpnum = sg_get_num(optarg); if ((op->grpnum < 0) || (op->grpnum > 31)) { fprintf(stderr, "bad argument to '--grpnum'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'h': case '?': usage(); return 0; case 'i': strncpy(op->ifilename, optarg, sizeof(op->ifilename)); if_given = 1; break; case 'l': ll = sg_get_llnum(optarg); if (-1 == ll) { fprintf(stderr, "bad argument to '--lba'\n"); return SG_LIB_SYNTAX_ERROR; } op->lba = (uint64_t)ll; lba_given = 1; break; case 'L': ++op->lbdata; break; case 'n': op->numblocks = sg_get_num(optarg); if (op->numblocks < 0) { fprintf(stderr, "bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } num_given = 1; break; case 'N': ++op->ndob; break; case 'P': ++op->pbdata; break; case 'R': ++op->want_ws10; break; case 'S': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { fprintf(stderr, "only one '--10', '--16' or '--32' " "please\n"); return SG_LIB_SYNTAX_ERROR; } op->pref_cdb_size = 16; break; case 't': op->timeout = sg_get_num(optarg); if (op->timeout < 0) { fprintf(stderr, "bad argument to '--timeout'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'T': if (DEF_WS_CDB_SIZE != op->pref_cdb_size) { fprintf(stderr, "only one '--10', '--16' or '--32' " "please\n"); return SG_LIB_SYNTAX_ERROR; } op->pref_cdb_size = 32; break; case 'U': ++op->unmap; break; case 'v': ++op->verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; case 'w': op->wrprotect = sg_get_num(optarg); if ((op->wrprotect < 0) || (op->wrprotect > 7)) { fprintf(stderr, "bad argument to '--wrprotect'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'x': op->xfer_len = sg_get_num(optarg); if (op->xfer_len < 0) { fprintf(stderr, "bad argument to '--xferlen'\n"); return SG_LIB_SYNTAX_ERROR; } break; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (op->want_ws10 && (DEF_WS_CDB_SIZE != op->pref_cdb_size)) { fprintf(stderr, "only one '--10', '--16' or '--32' please\n"); return SG_LIB_SYNTAX_ERROR; } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } vb = op->verbose; if ((! if_given) && (! lba_given) && (! num_given)) { fprintf(stderr, "As a precaution, one of '--in=', '--lba=' or " "'--num=' is required\n"); return SG_LIB_SYNTAX_ERROR; } if (op->ndob) { if (if_given) { fprintf(stderr, "Can't have both --ndob and '--in='\n"); return SG_LIB_SYNTAX_ERROR; } if (0 != op->xfer_len) { fprintf(stderr, "With --ndob only '--xferlen=0' (or not given) " "is acceptable\n"); return SG_LIB_SYNTAX_ERROR; } } else if (op->ifilename[0]) { got_stdin = (0 == strcmp(op->ifilename, "-")) ? 1 : 0; if (! got_stdin) { memset(&a_stat, 0, sizeof(a_stat)); if (stat(op->ifilename, &a_stat) < 0) { if (vb) fprintf(stderr, "unable to stat(%s): %s\n", op->ifilename, safe_strerror(errno)); return SG_LIB_FILE_ERROR; } if (op->xfer_len <= 0) op->xfer_len = (int)a_stat.st_size; } } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, vb); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (! op->ndob) { prot_en = 0; if (0 == op->xfer_len) { res = sg_ll_readcap_16(sg_fd, 0 /* pmi */, 0 /* llba */, resp_buff, RCAP16_RESP_LEN, 1, (vb ? (vb - 1): 0)); if (SG_LIB_CAT_UNIT_ATTENTION == res) { fprintf(stderr, "Read capacity(16) unit attention, try " "again\n"); res = sg_ll_readcap_16(sg_fd, 0, 0, resp_buff, RCAP16_RESP_LEN, 1, (vb ? (vb - 1): 0)); } if (0 == res) { if (vb > 3) dStrHexErr((const char *)resp_buff, RCAP16_RESP_LEN, 1); block_size = ((resp_buff[8] << 24) | (resp_buff[9] << 16) | (resp_buff[10] << 8) | resp_buff[11]); prot_en = !!(resp_buff[12] & 0x1); op->xfer_len = block_size; if (prot_en && (op->wrprotect > 0)) op->xfer_len += 8; } else if ((SG_LIB_CAT_INVALID_OP == res) || (SG_LIB_CAT_ILLEGAL_REQ == res)) { if (vb) fprintf(stderr, "Read capacity(16) not supported, try " "Read capacity(10)\n"); res = sg_ll_readcap_10(sg_fd, 0 /* pmi */, 0 /* lba */, resp_buff, RCAP10_RESP_LEN, 1, (vb ? (vb - 1): 0)); if (0 == res) { if (vb > 3) dStrHexErr((const char *)resp_buff, RCAP10_RESP_LEN, 1); block_size = ((resp_buff[4] << 24) | (resp_buff[5] << 16) | (resp_buff[6] << 8) | resp_buff[7]); op->xfer_len = block_size; } else { sg_get_category_sense_str(res, sizeof(b), b, vb); fprintf(stderr, "Read capacity(10): %s\n", b); fprintf(stderr, "Unable to calculate block size\n"); } } else if (vb) { sg_get_category_sense_str(res, sizeof(b), b, vb); fprintf(stderr, "Read capacity(16): %s\n", b); fprintf(stderr, "Unable to calculate block size\n"); } } if (op->xfer_len < 1) { fprintf(stderr, "unable to deduce block size, please give " "'--xferlen=' argument\n"); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->xfer_len > MAX_XFER_LEN) { fprintf(stderr, "'--xferlen=%d is out of range ( want <= %d)\n", op->xfer_len, MAX_XFER_LEN); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } wBuff = (unsigned char*)calloc(op->xfer_len, 1); if (NULL == wBuff) { fprintf(stderr, "unable to allocate %d bytes of memory with " "calloc()\n", op->xfer_len); ret = SG_LIB_SYNTAX_ERROR; goto err_out; } if (op->ifilename[0]) { if (got_stdin) { infd = STDIN_FILENO; if (sg_set_binary_mode(STDIN_FILENO) < 0) perror("sg_set_binary_mode"); } else { if ((infd = open(op->ifilename, O_RDONLY)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for " "reading", op->ifilename); perror(ebuff); ret = SG_LIB_FILE_ERROR; goto err_out; } else if (sg_set_binary_mode(infd) < 0) perror("sg_set_binary_mode"); } res = read(infd, wBuff, op->xfer_len); if (res < 0) { snprintf(ebuff, EBUFF_SZ, ME "couldn't read from %s", op->ifilename); perror(ebuff); if (! got_stdin) close(infd); ret = SG_LIB_FILE_ERROR; goto err_out; } if (res < op->xfer_len) { fprintf(stderr, "tried to read %d bytes from %s, got %d " "bytes\n", op->xfer_len, op->ifilename, res); fprintf(stderr, " so pad with 0x0 bytes and continue\n"); } if (! got_stdin) close(infd); } else { if (vb) fprintf(stderr, "Default data-out buffer set to %d zeros\n", op->xfer_len); if (prot_en && (op->wrprotect > 0)) { /* default for protection is 0xff, rest get 0x0 */ memset(wBuff + op->xfer_len - 8, 0xff, 8); if (vb) fprintf(stderr, " ... apart from last 8 bytes which are " "set to 0xff\n"); } } } ret = do_write_same(sg_fd, op, wBuff, &act_cdb_len); if (ret) { sg_get_category_sense_str(ret, sizeof(b), b, vb); fprintf(stderr, "Write same(%d): %s\n", act_cdb_len, b); } err_out: if (wBuff) free(wBuff); res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_requests.c0000664000175000017500000002562112335513125015655 0ustar douggdougg/* * Copyright (c) 2004-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" /* A utility program for the Linux OS SCSI subsystem. * * * This program issues the SCSI command REQUEST SENSE to the given SCSI device. */ static const char * version_str = "1.25 20140515"; #define MAX_REQS_RESP_LEN 255 #define DEF_REQS_RESP_LEN 252 /* Not all environments support the Unix sleep() */ #if defined(MSC_VER) || defined(__MINGW32__) #define HAVE_MS_SLEEP #endif #ifdef HAVE_MS_SLEEP #include #define sleep_for(seconds) Sleep( (seconds) * 1000) #else #define sleep_for(seconds) sleep(seconds) #endif #define ME "sg_requests: " static struct option long_options[] = { {"desc", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"maxlen", required_argument, 0, 'm'}, {"num", required_argument, 0, 'n'}, {"progress", no_argument, 0, 'p'}, {"raw", no_argument, 0, 'r'}, {"status", no_argument, 0, 's'}, {"time", no_argument, 0, 't'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; static void usage() { fprintf(stderr, "Usage: " "sg_requests [--desc] [--help] [--hex] [--maxlen=LEN] " "[--num=NUM]\n" " [--progress] [--raw] [--status] [--time] " "[--verbose]\n" " [--version] DEVICE\n" " where:\n" " --desc|-d set flag for descriptor sense " "format\n" " --help|-h print out usage message\n" " --hex|-H output in hexadecimal\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 252 bytes)\n" " --num=NUM|-n NUM number of REQUEST SENSE commands " "to send (def: 1)\n" " --progress|-p output a progress indication (percentage) " "if available\n" " --raw|-r output in binary (to stdout)\n" " --status|-s set exit status from parameter data " "(def: only set\n" " exit status from autosense)\n" " --time|-t time the transfer, calculate commands " "per second\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REQUEST SENSE command\n" ); } static void dStrRaw(const char* str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } int main(int argc, char * argv[]) { int sg_fd, res, c, resp_len, k, progress; unsigned char requestSenseBuff[MAX_REQS_RESP_LEN + 1]; int desc = 0; int num_rs = 1; int do_hex = 0; int maxlen = 0; int do_progress = 0; int do_raw = 0; int do_status = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; char b[80]; #ifndef SG_LIB_MINGW int do_time = 0; struct timeval start_tm, end_tm; #endif while (1) { int option_index = 0; c = getopt_long(argc, argv, "dhHm:n:prstvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'd': desc = 1; break; case 'h': case '?': usage(); return 0; case 'H': ++do_hex; break; case 'm': maxlen = sg_get_num(optarg); if ((maxlen < 0) || (maxlen > MAX_REQS_RESP_LEN)) { fprintf(stderr, "argument to '--maxlen' should be %d or " "less\n", MAX_REQS_RESP_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'n': num_rs = sg_get_num(optarg); if (num_rs < 1) { fprintf(stderr, "bad argument to '--num'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': ++do_progress; break; case 'r': ++do_raw; break; case 's': do_status = 1; break; case 't': #ifndef SG_LIB_MINGW do_time = 1; #endif break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (0 == maxlen) maxlen = DEF_REQS_RESP_LEN; if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } sg_fd = sg_cmds_open_device(device_name, 1 /* ro */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (do_progress) { for (k = 0; k < num_rs; ++k) { if (k > 0) sleep_for(30); memset(requestSenseBuff, 0x0, sizeof(requestSenseBuff)); res = sg_ll_request_sense(sg_fd, desc, requestSenseBuff, maxlen, 1, verbose); if (res) { ret = res; if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Request Sense command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "bad field in Request Sense cdb\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "Request Sense, aborted command\n"); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Request Sense command: %s\n", b); } break; } /* "Additional sense length" same in descriptor and fixed */ resp_len = requestSenseBuff[7] + 8; if (verbose > 1) { fprintf(stderr, "Parameter data in hex\n"); dStrHexErr((const char *)requestSenseBuff, resp_len, 1); } progress = -1; sg_get_sense_progress_fld(requestSenseBuff, resp_len, &progress); if (progress < 0) { ret = res; if (verbose > 1) fprintf(stderr, "No progress indication found, " "iteration %d\n", k + 1); /* N.B. exits first time there isn't a progress indication */ break; } else printf("Progress indication: %d.%02d%% done\n", (progress * 100) / 65536, ((progress * 100) % 65536) / 656); } goto finish; } #ifndef SG_LIB_MINGW if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); } #endif requestSenseBuff[0] = '\0'; requestSenseBuff[7] = '\0'; for (k = 0; k < num_rs; ++k) { memset(requestSenseBuff, 0x0, sizeof(requestSenseBuff)); res = sg_ll_request_sense(sg_fd, desc, requestSenseBuff, maxlen, 1, verbose); ret = res; if (0 == res) { resp_len = requestSenseBuff[7] + 8; if (do_raw) dStrRaw((const char *)requestSenseBuff, resp_len); else if (do_hex) dStrHex((const char *)requestSenseBuff, resp_len, 1); else if (1 == num_rs) { fprintf(stderr, "Decode parameter data as sense data:\n"); sg_print_sense(NULL, requestSenseBuff, resp_len, 0); if (verbose > 1) { fprintf(stderr, "\nParameter data in hex\n"); dStrHexErr((const char *)requestSenseBuff, resp_len, 1); } } continue; } else if (SG_LIB_CAT_INVALID_OP == res) fprintf(stderr, "Request Sense command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) fprintf(stderr, "bad field in Request Sense cdb\n"); else if (SG_LIB_CAT_ABORTED_COMMAND == res) fprintf(stderr, "Request Sense, aborted command\n"); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Request Sense command: %s\n", b); } break; } if ((0 == ret) && do_status) { resp_len = requestSenseBuff[7] + 8; ret = sg_err_category_sense(requestSenseBuff, resp_len); if (SG_LIB_CAT_NO_SENSE == ret) { struct sg_scsi_sense_hdr ssh; if (sg_scsi_normalize_sense(requestSenseBuff, resp_len, &ssh)) { if ((0 == ssh.asc) && (0 == ssh.ascq)) ret = 0; } } } #ifndef SG_LIB_MINGW if ((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)num_rs; 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 finish: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_sat_read_gplog.c0000664000175000017500000003721112430315266016754 0ustar douggdougg/* * Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* This program uses a ATA PASS-THROUGH SCSI command. This usage is * defined in the SCSI to ATA Translation (SAT) drafts and standards. * See http://www.t10.org for drafts. SAT is a standard: SAT ANSI INCITS * 431-2007 (draft prior to that is sat-r09.pdf). SAT-2 is also a * standard: SAT-2 ANSI INCITS 465-2010 and the draft prior to that is * sat2r09.pdf . The SAT-3 project has started and the most recent draft * is sat3r01.pdf . */ /* This program performs a ATA PASS-THROUGH (16) SCSI command in order * to perform an ATA READ LOG EXT or ATA READ LOG DMA EXT command. * * See man page (sg_sat_read_gplog.8) for details. */ #define SAT_ATA_PASS_THROUGH16 0x85 #define SAT_ATA_PASS_THROUGH16_LEN 16 #define SAT_ATA_PASS_THROUGH12 0xa1 /* clashes with MMC BLANK comand */ #define SAT_ATA_PASS_THROUGH12_LEN 12 #define SAT_ATA_RETURN_DESC 9 /* ATA Return (sense) Descriptor */ #define ASCQ_ATA_PT_INFO_AVAILABLE 0x1d #define ATA_READ_LOG_EXT 0x2f #define ATA_READ_LOG_DMA_EXT 0x47 #define DEF_TIMEOUT 20 static const char * version_str = "1.09 20141110"; struct opts_t { int cdb_len; int ck_cond; int count; int hex; int la; /* log address */ int pn; /* page number within log address */ int rdonly; int verbose; const char * device_name; }; static struct option long_options[] = { {"count", required_argument, 0, 'c'}, {"ck_cond", no_argument, 0, 'C'}, {"dma", no_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"len", required_argument, 0, 'l'}, {"log", required_argument, 0, 'L'}, {"page", required_argument, 0, 'p'}, {"readonly", no_argument, 0, 'r'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: " "sg_sat_read_gplog [--ck_cond] [--count=CO] [--dma] [--help]\n" " [--hex] [--len=16|12] [--log=LA] " "[--page=PN]\n" " [--readonly] [--verbose] [--version] " "DEVICE\n" " where:\n" " --ck_cond | -C set ck_cond field in pass-through " "(def: 0)\n" " --count=CO | -c CO block count (def: 1)\n" " --dma | -d Use READ LOG DMA EXT (def: READ LOG " "EXT)\n" " --help | -h output this usage message\n" " --hex | -H output response in hex bytes, -HH " "yields hex\n" " words + ASCII (def), -HHH hex words " "only\n" " --len=16|12 | -l 16|12 cdb length: 16 or 12 bytes " "(def: 16)\n" " --log=LA | -L LA Log address to be read (def: 0)\n" " --page=PN|-p PN Log page number within address (def: " "0)\n" " --readonly | -r open DEVICE read-only (def: " "read-write)\n" " --verbose | -v increase verbosity\n" " recommended if DEVICE is ATA disk\n" " --version | -V print version string and exit\n\n" "Sends an ATA READ LOG EXT (or READ LOG DMA EXT) command via a " "SAT pass\nthrough to fetch a General Purpose (GP) log page. Each " "page is accessed\nvia a log address and then a page number " "within that address: LA,PN .\n" "By default the output is the response in hex (16 bit) words.\n" ); } static int do_read_gplog(int sg_fd, int ata_cmd, unsigned char *inbuff, const struct opts_t * op) { int res, ret; int extend = 1; int protocol; int t_dir = 1; /* 0 -> to device, 1 -> from device */ int byte_block = 1; /* 0 -> bytes, 1 -> 512 byte blocks */ int t_length = 2; /* 0 -> no data transferred, 2 -> sector count */ int t_type = 0; /* 0 -> 512 byte blocks, 1 -> logical sectors */ int resid = 0; int got_ard = 0; /* got ATA result descriptor */ int sb_sz; struct sg_scsi_sense_hdr ssh; unsigned char sense_buffer[64]; unsigned char ata_return_desc[16]; unsigned char aptCmdBlk[SAT_ATA_PASS_THROUGH16_LEN] = {SAT_ATA_PASS_THROUGH16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; unsigned char apt12CmdBlk[SAT_ATA_PASS_THROUGH12_LEN] = {SAT_ATA_PASS_THROUGH12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; char cmd_name[32]; snprintf(cmd_name, sizeof(cmd_name), "ATA PASS-THROUGH (%d)", op->cdb_len); if (ata_cmd == ATA_READ_LOG_DMA_EXT) { protocol = 6; /* DMA */ } else { protocol = 4; /* PIO Data-In */ } sb_sz = sizeof(sense_buffer); memset(sense_buffer, 0, sb_sz); memset(ata_return_desc, 0, sizeof(ata_return_desc)); memset(inbuff, 0, op->count * 512); if (op->verbose > 1) pr2serr("Building ATA READ LOG%s EXT command; la=0x%x, pn=0x%x\n", ((ata_cmd == ATA_READ_LOG_DMA_EXT) ? " DMA" : ""), op->la, op->pn); if (op->cdb_len == 16) { /* Prepare ATA PASS-THROUGH COMMAND (16) command */ aptCmdBlk[14] = ata_cmd; aptCmdBlk[5] = (op->count >> 8) & 0xff; aptCmdBlk[6] = op->count & 0xff; aptCmdBlk[8] = op->la; aptCmdBlk[9] = (op->pn >> 8) & 0xff; aptCmdBlk[10] = op->pn & 0xff; aptCmdBlk[1] = (protocol << 1) | extend; aptCmdBlk[2] = (op->ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, aptCmdBlk, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, op->count * 512, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, op->verbose); } else { /* Prepare ATA PASS-THROUGH COMMAND (12) command */ apt12CmdBlk[9] = ata_cmd; apt12CmdBlk[4] = op->count; apt12CmdBlk[5] = op->la; apt12CmdBlk[6] = op->pn & 0xff; apt12CmdBlk[7] = (op->pn >> 8) & 0xff; apt12CmdBlk[1] = (protocol << 1); apt12CmdBlk[2] = (op->ck_cond << 5) | (t_type << 4) | (t_dir << 3) | (byte_block << 2) | t_length; res = sg_ll_ata_pt(sg_fd, apt12CmdBlk, op->cdb_len, DEF_TIMEOUT, inbuff, NULL, op->count * 512, sense_buffer, sb_sz, ata_return_desc, sizeof(ata_return_desc), &resid, op->verbose); } if (0 == res) { if (op->verbose > 2) pr2serr("command completed with SCSI GOOD status\n"); if ((0 == op->hex) || (2 == op->hex)) dWordHex((const unsigned short *)inbuff, op->count * 256, 0, sg_is_big_endian()); else if (1 == op->hex) dStrHex((const char *)inbuff, 512, 0); else if (3 == op->hex) /* '-HHH' suitable for "hdparm --Istdin" */ dWordHex((const unsigned short *)inbuff, 256, -2, sg_is_big_endian()); else /* '-HHHH' hex bytes only */ dStrHex((const char *)inbuff, 512, -1); } else if ((res > 0) && (res & SAM_STAT_CHECK_CONDITION)) { if (op->verbose > 1) sg_print_sense("ATA pass through", sense_buffer, sb_sz, ((op->verbose > 2) ? 1 : 0)); if (sg_scsi_normalize_sense(sense_buffer, sb_sz, &ssh)) { switch (ssh.sense_key) { case SPC_SK_ILLEGAL_REQUEST: if ((0x20 == ssh.asc) && (0x0 == ssh.ascq)) { ret = SG_LIB_CAT_INVALID_OP; if (op->verbose < 2) pr2serr("%s not supported\n", cmd_name); } else { ret = SG_LIB_CAT_ILLEGAL_REQ; if (op->verbose < 2) pr2serr("%s, bad field in cdb\n", cmd_name); } return ret; case SPC_SK_NO_SENSE: case SPC_SK_RECOVERED_ERROR: if ((0x0 == ssh.asc) && (ASCQ_ATA_PT_INFO_AVAILABLE == ssh.ascq)) { if (SAT_ATA_RETURN_DESC != ata_return_desc[0]) { if (op->verbose) pr2serr("did not find ATA Return (sense) " "Descriptor\n"); return SG_LIB_CAT_RECOVERED; } got_ard = 1; break; } else if (SPC_SK_RECOVERED_ERROR == ssh.sense_key) return SG_LIB_CAT_RECOVERED; else { if ((0x0 == ssh.asc) && (0x0 == ssh.ascq)) break; return SG_LIB_CAT_SENSE; } case SPC_SK_UNIT_ATTENTION: if (op->verbose < 2) pr2serr("%s, Unit Attention detected\n", cmd_name); return SG_LIB_CAT_UNIT_ATTENTION; case SPC_SK_NOT_READY: if (op->verbose < 2) pr2serr("%s, device not ready\n", cmd_name); return SG_LIB_CAT_NOT_READY; case SPC_SK_MEDIUM_ERROR: case SPC_SK_HARDWARE_ERROR: if (op->verbose < 2) pr2serr("%s, medium or hardware error\n", cmd_name); return SG_LIB_CAT_MEDIUM_HARD; case SPC_SK_ABORTED_COMMAND: if (0x10 == ssh.asc) { pr2serr("Aborted command: protection information\n"); return SG_LIB_CAT_PROTECTION; } else { pr2serr("Aborted command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } case SPC_SK_DATA_PROTECT: pr2serr("%s: data protect, read only media?\n", cmd_name); return SG_LIB_CAT_DATA_PROTECT; default: if (op->verbose < 2) pr2serr("%s, some sense data, use '-v' for more " "information\n", cmd_name); return SG_LIB_CAT_SENSE; } } else { pr2serr("CHECK CONDITION without response code ??\n"); return SG_LIB_CAT_SENSE; } if (0x72 != (sense_buffer[0] & 0x7f)) { pr2serr("expected descriptor sense format, response " "code=0x%x\n", sense_buffer[0]); return SG_LIB_CAT_MALFORMED; } } else if (res > 0) { if (SAM_STAT_RESERVATION_CONFLICT == res) { pr2serr("SCSI status: RESERVATION CONFLICT\n"); return SG_LIB_CAT_RES_CONFLICT; } else { pr2serr("Unexpected SCSI status=0x%x\n", res); return SG_LIB_CAT_MALFORMED; } } else { pr2serr("%s failed\n", cmd_name); if (op->verbose < 2) pr2serr(" try adding '-v' for more information\n"); return -1; } if ((SAT_ATA_RETURN_DESC == ata_return_desc[0]) && (0 == got_ard)) pr2serr("Seem to have got ATA Result Descriptor but it was not " "indicated\n"); if (got_ard) { if (ata_return_desc[3] & 0x4) { pr2serr("error indication in returned FIS: aborted " "command\n"); return SG_LIB_CAT_ABORTED_COMMAND; } } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, ret, res, n; int ata_cmd = ATA_READ_LOG_EXT; unsigned char *inbuff; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->cdb_len = SAT_ATA_PASS_THROUGH16_LEN; op->count = 1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "c:CdhHl:L:p:rvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'c': op->count = sg_get_num(optarg); if ((op->count < 1) || (op->count > 0xffff)) { pr2serr("bad argument for '--count'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'C': op->ck_cond = 1; break; case 'd': ata_cmd = ATA_READ_LOG_DMA_EXT; break; case 'h': case '?': usage(); return 0; case 'H': ++op->hex; break; case 'l': op->cdb_len = sg_get_num(optarg); if (! ((op->cdb_len == 12) || (op->cdb_len == 16))) { pr2serr("argument to '--len' should be 12 or 16\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'L': op->la = sg_get_num(optarg); if (op->la < 0 || op->la > 0xff) { pr2serr("bad argument for '--log'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'p': op->pn = sg_get_num(optarg); if ((op->pn < 0) || (op->pn > 0xffff)) { pr2serr("bad argument for '--page'\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': ++op->rdonly; break; case 'v': ++op->verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (NULL == op->device_name) { pr2serr("missing device name!\n"); usage(); return 1; } if ((op->count > 0xff) && (12 == op->cdb_len)) { op->cdb_len = 16; if (op->verbose) pr2serr("Since count > 0xff, forcing cdb length to " "16\n"); } n = op->count * 512; inbuff = malloc(n); if (!inbuff) { pr2serr("Cannot allocate output buffer of size %d\n", n); return SG_LIB_CAT_OTHER; } if ((sg_fd = sg_cmds_open_device(op->device_name, op->rdonly, op->verbose)) < 0) { pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } ret = do_read_gplog(sg_fd, ata_cmd, inbuff, op); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_persist.c0000664000175000017500000013617712415077207015511 0ustar douggdougg/* A utility program originally written for the Linux OS SCSI subsystem. * Copyright (C) 2004-2014 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. * * This program issues the SCSI PERSISTENT IN and OUT commands. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" static const char * version_str = "0.49 20141007"; #define PRIN_RKEY_SA 0x0 #define PRIN_RRES_SA 0x1 #define PRIN_RCAP_SA 0x2 #define PRIN_RFSTAT_SA 0x3 #define PROUT_REG_SA 0x0 #define PROUT_RES_SA 0x1 #define PROUT_REL_SA 0x2 #define PROUT_CLEAR_SA 0x3 #define PROUT_PREE_SA 0x4 #define PROUT_PREE_AB_SA 0x5 #define PROUT_REG_IGN_SA 0x6 #define PROUT_REG_MOVE_SA 0x7 #define PROUT_REPL_LOST_SA 0x8 #define MX_ALLOC_LEN 8192 #define MX_TIDS 32 #define MX_TID_LEN 256 #define SG_PERSIST_IN_RDONLY "SG_PERSIST_IN_RDONLY" struct opts_t { unsigned int prout_type; uint64_t param_rk; uint64_t param_sark; unsigned int param_rtp; int prin; int prin_sa; int prout_sa; int param_alltgpt; int param_aptpl; int param_unreg; int inquiry; int hex; int readonly; unsigned char transportid_arr[MX_TIDS * MX_TID_LEN]; int num_transportids; unsigned int alloc_len; int verbose; }; static struct option long_options[] = { {"alloc-length", required_argument, 0, 'l'}, {"clear", no_argument, 0, 'C'}, {"device", required_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"in", no_argument, 0, 'i'}, {"no-inquiry", no_argument, 0, 'n'}, {"out", no_argument, 0, 'o'}, {"param-alltgpt", no_argument, 0, 'Y'}, {"param-aptpl", no_argument, 0, 'Z'}, {"param-rk", required_argument, 0, 'K'}, {"param-sark", required_argument, 0, 'S'}, {"param-unreg", no_argument, 0, 'U'}, {"preempt", no_argument, 0, 'P'}, {"preempt-abort", no_argument, 0, 'A'}, {"prout-type", required_argument, 0, 'T'}, {"read-full-status", no_argument, 0, 's'}, {"read-keys", no_argument, 0, 'k'}, {"readonly", no_argument, 0, 'y'}, {"read-reservation", no_argument, 0, 'r'}, {"read-status", no_argument, 0, 's'}, {"register", no_argument, 0, 'G'}, {"register-ignore", no_argument, 0, 'I'}, {"register-move", no_argument, 0, 'M'}, {"release", no_argument, 0, 'L'}, {"relative-target-port", required_argument, 0, 'Q'}, {"replace-lost", no_argument, 0, 'z'}, {"report-capabilities", no_argument, 0, 'c'}, {"reserve", no_argument, 0, 'R'}, {"transport-id", required_argument, 0, 'X'}, {"unreg", no_argument, 0, 'U'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0} }; static const char * prin_sa_strs[] = { "Read keys", "Read reservation", "Report capabilities", "Read full status", "[reserved 0x4]", "[reserved 0x5]", "[reserved 0x6]", "[reserved 0x7]", }; static const int num_prin_sa_strs = sizeof(prin_sa_strs) / sizeof(prin_sa_strs[0]); static const char * prout_sa_strs[] = { "Register", "Reserve", "Release", "Clear", "Preempt", "Preempt and abort", "Register and ignore existing key", "Register and move", "Replace lost reservation", "[reserved 0x9]", }; static const int num_prout_sa_strs = sizeof(prout_sa_strs) / sizeof(prout_sa_strs[0]); static const char * pr_type_strs[] = { "obsolete [0]", "Write Exclusive", "obsolete [2]", "Exclusive Access", "obsolete [4]", "Write Exclusive, registrants only", "Exclusive Access, registrants only", "Write Exclusive, all registrants", "Exclusive Access, all registrants", "obsolete [9]", "obsolete [0xa]", "obsolete [0xb]", "obsolete [0xc]", "obsolete [0xd]", "obsolete [0xe]", "obsolete [0xf]", }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage(int help) { if (help < 2) { pr2serr("Usage: sg_persist [OPTIONS] [DEVICE]\n" " where the main OPTIONS are:\n" " --clear|-C PR Out: Clear\n" " --help|-h print usage message, " "twice for more\n" " --in|-i request PR In command " "(default)\n" " --out|-o request PR Out command\n" " --param-rk=RK|-K RK PR Out parameter reservation " "key\n" " (RK is in hex)\n" " --param-sark=SARK|-S SARK PR Out parameter service " "action\n" " reservation key (SARK is " "in hex)\n" " --preempt|-P PR Out: Preempt\n" " --preempt-abort|-A PR Out: Preempt and Abort\n" " --prout-type=TYPE|-T TYPE PR Out type field (see " "'-hh')\n" " --read-full-status|-s PR In: Read Full Status\n" " --read-keys|-k PR In: Read Keys " "(default)\n"); pr2serr(" --read-reservation|-r PR In: Read Reservation\n" " --read-status|-s PR In: Read Full Status\n" " --register|-G PR Out: Register\n" " --register-ignore|-I PR Out: Register and Ignore\n" " --register-move|-M PR Out: Register and Move\n" " for '--register-move'\n" " --release|-L PR Out: Release\n" " --replace-lost|-x PR Out: Replace Lost " "Reservation\n" " --report-capabilities|-c PR In: Report Capabilities\n" " --reserve|-R PR Out: Reserve\n" " --unreg|-U optional with PR Out " "Register and Move\n\n" "Performs a SCSI PERSISTENT RESERVE (IN or OUT) command. " "Invoking\n'sg_persist DEVICE' will do a PR In Read Keys " "command. Use '-hh'\nfor more options and TYPE meanings.\n"); } else { pr2serr("Usage: sg_persist [OPTIONS] [DEVICE]\n" " where the other OPTIONS are:\n" " --alloc-length=LEN|-l LEN allocation length hex " "value (used with\n" " PR In only) (default: 8192 " "(2000 in hex))\n" " --device=DEVICE|-d DEVICE supply DEVICE as an option " "rather than\n" " an argument\n" " --hex|-H output response in hex (for " "PR In commands)\n" " --no-inquiry|-n skip INQUIRY (default: do " "INQUIRY)\n" " --param-alltgpt|-Y PR Out parameter " "'ALL_TG_PT'\n" " --param-aptpl|-Z PR Out parameter 'APTPL'\n" " --readonly|-y open DEVICE read-only (def: " "read-write)\n" " --relative-target-port=RTPI|-Q RTPI relative target " "port " "identifier\n" " --transport-id=TIDS|-X TIDS one or more " "TransportIDs can\n" " be given in several " "forms\n" " --verbose|-v output additional debug " "information\n" " --version|-V output version string\n\n" "For the main options use '--help' or '-h' once.\n\n\n"); pr2serr("PR Out TYPE field value meanings:\n" " 0: obsolete (was 'read shared' in SPC)\n" " 1: write exclusive\n" " 2: obsolete (was 'read exclusive')\n" " 3: exclusive access\n" " 4: obsolete (was 'shared access')\n" " 5: write exclusive, registrants only\n" " 6: exclusive access, registrants only\n" " 7: write exclusive, all registrants\n" " 8: exclusive access, all registrants\n"); } } /* If num_tids==0 then only one TransportID is assumed with len bytes in * it. If num_tids>0 then that many TransportIDs is assumed, each in an * element that is MX_TID_LEN bytes long (and the 'len' argument is * ignored). */ static void decode_transport_id(const char * leadin, unsigned char * ucp, int len, int num_tids) { int format_code, proto_id, num, j, k; uint64_t ull; int bump; if (num_tids > 0) len = num_tids * MX_TID_LEN; for (k = 0, bump = MX_TID_LEN; k < len; k += bump, ucp += bump) { if ((len < 24) || (0 != (len % 4))) printf("%sTransport Id short or not multiple of 4 " "[length=%d]:\n", leadin, len); else printf("%sTransport Id of initiator:\n", leadin); format_code = ((ucp[0] >> 6) & 0x3); proto_id = (ucp[0] & 0xf); switch (proto_id) { case TPROTO_FCP: /* Fibre channel */ printf("%s FCP-2 World Wide Name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); break; case TPROTO_SPI: /* Parallel SCSI */ printf("%s Parallel SCSI initiator SCSI address: 0x%x\n", leadin, ((ucp[2] << 8) | ucp[3])); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); printf("%s relative port number (of corresponding target): " "0x%x\n", leadin, ((ucp[6] << 8) | ucp[7])); break; case TPROTO_SSA: printf("%s SSA (transport id not defined):\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); break; case TPROTO_1394: /* IEEE 1394 */ printf("%s IEEE 1394 EUI-64 name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); break; case TPROTO_SRP: printf("%s RDMA initiator port identifier:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 16, -1); break; case TPROTO_ISCSI: printf("%s iSCSI ", leadin); num = ((ucp[2] << 8) | ucp[3]); if (0 == format_code) printf("name: %.*s\n", num, &ucp[4]); else if (1 == format_code) printf("name and session id: %.*s\n", num, &ucp[4]); else { printf(" [Unexpected format code: %d]\n", format_code); dStrHex((const char *)ucp, num + 4, -1); } break; case TPROTO_SAS: ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[4 + j]; } printf("%s SAS address: 0x%016" PRIx64 "\n", leadin, ull); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); break; case TPROTO_ADT: printf("%s ADT:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); break; case TPROTO_ATA: printf("%s ATAPI:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); break; case TPROTO_UAS: printf("%s UAS:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); break; case TPROTO_SOP: printf("%s SOP ", leadin); num = ((ucp[2] << 8) | ucp[3]); if (0 == format_code) printf("Routing ID: 0x%x\n", num); else { printf(" [Unexpected format code: %d]\n", format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), -1); } break; case TPROTO_NONE: pr2serr("%s No specified protocol\n", leadin); /* dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), -1); */ break; default: pr2serr("%s unknown protocol id=0x%x format_code=%d\n", leadin, proto_id, format_code); dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), -1); break; } } } static int prin_work(int sg_fd, const struct opts_t * op) { int k, j, num, res, add_len, add_desc_len, rel_pt_addr; unsigned int pr_gen; uint64_t ull; unsigned char * ucp; unsigned char pr_buff[MX_ALLOC_LEN]; memset(pr_buff, 0, sizeof(pr_buff)); res = sg_ll_persistent_reserve_in(sg_fd, op->prin_sa, pr_buff, op->alloc_len, 1, op->verbose); if (res) { char b[64]; char bb[80]; if (op->prin_sa < num_prin_sa_strs) snprintf(b, sizeof(b), "%s", prin_sa_strs[op->prin_sa]); else snprintf(b, sizeof(b), "service action=0x%x", op->prin_sa); if (SG_LIB_CAT_INVALID_OP == res) pr2serr("PR in (%s): command not supported\n", b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("PR in (%s): bad field in cdb or parameter list (perhaps " "unsupported service action)\n", b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("PR in (%s): %s\n", b, bb); } return res; } if (PRIN_RCAP_SA == op->prin_sa) { if (8 != pr_buff[1]) { pr2serr("Unexpected response for PRIN Report Capabilities\n"); if (op->hex) dStrHex((const char *)pr_buff, pr_buff[1], 1); return SG_LIB_CAT_MALFORMED; } if (op->hex) dStrHex((const char *)pr_buff, 8, 1); else { printf("Report capabilities response:\n"); printf(" Compatible Reservation Handling(CRH): %d\n", !!(pr_buff[2] & 0x10)); printf(" Specify Initiator Ports Capable(SIP_C): %d\n", !!(pr_buff[2] & 0x8)); printf(" All Target Ports Capable(ATP_C): %d\n", !!(pr_buff[2] & 0x4)); printf(" Persist Through Power Loss Capable(PTPL_C): %d\n", !!(pr_buff[2] & 0x1)); printf(" Type Mask Valid(TMV): %d\n", !!(pr_buff[3] & 0x80)); printf(" Allow Commands: %d\n", (pr_buff[3] >> 4) & 0x7); printf(" Persist Through Power Loss Active(PTPL_A): %d\n", !!(pr_buff[3] & 0x1)); if (pr_buff[3] & 0x80) { printf(" Support indicated in Type mask:\n"); printf(" %s: %d\n", pr_type_strs[7], !!(pr_buff[4] & 0x80)); printf(" %s: %d\n", pr_type_strs[6], !!(pr_buff[4] & 0x40)); printf(" %s: %d\n", pr_type_strs[5], !!(pr_buff[4] & 0x20)); printf(" %s: %d\n", pr_type_strs[3], !!(pr_buff[4] & 0x8)); printf(" %s: %d\n", pr_type_strs[1], !!(pr_buff[4] & 0x2)); printf(" %s: %d\n", pr_type_strs[8], !!(pr_buff[5] & 0x1)); } } } else { pr_gen = ((pr_buff[0] << 24) | (pr_buff[1] << 16) | (pr_buff[2] << 8) | pr_buff[3]); add_len = ((pr_buff[4] << 24) | (pr_buff[5] << 16) | (pr_buff[6] << 8) | pr_buff[7]); if (op->hex) { if (op->hex > 1) dStrHex((const char *)pr_buff, add_len + 8, ((2 == op->hex) ? 1 : -1)); else { printf(" PR generation=0x%x, ", pr_gen); if (add_len <= 0) printf("Additional length=%d\n", add_len); if (add_len > ((int)sizeof(pr_buff) - 8)) { printf("Additional length too large=%d, truncate\n", add_len); dStrHex((const char *)(pr_buff + 8), sizeof(pr_buff) - 8, 1); } else { printf("Additional length=%d\n", add_len); dStrHex((const char *)(pr_buff + 8), add_len, 1); } } } else if (PRIN_RKEY_SA == op->prin_sa) { printf(" PR generation=0x%x, ", pr_gen); num = add_len / 8; if (num > 0) { if (1 == num) printf("1 registered reservation key follows:\n"); else printf("%d registered reservation keys follow:\n", num); ucp = pr_buff + 8; for (k = 0; k < num; ++k, ucp += 8) { ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[j]; } printf(" 0x%" PRIx64 "\n", ull); } } else printf("there are NO registered reservation keys\n"); } else if (PRIN_RRES_SA == op->prin_sa) { printf(" PR generation=0x%x, ", pr_gen); num = add_len / 16; if (num > 0) { printf("Reservation follows:\n"); ucp = pr_buff + 8; ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[j]; } printf(" Key=0x%" PRIx64 "\n", ull); j = ((ucp[13] >> 4) & 0xf); if (0 == j) printf(" scope: LU_SCOPE, "); else printf(" scope: %d ", j); j = (ucp[13] & 0xf); printf(" type: %s\n", pr_type_strs[j]); } else printf("there is NO reservation held\n"); } else if (PRIN_RFSTAT_SA == op->prin_sa) { printf(" PR generation=0x%x\n", pr_gen); ucp = pr_buff + 8; if (0 == add_len) { printf(" No full status descriptors\n"); if (op->verbose) printf(" So there are no registered IT nexuses\n"); } for (k = 0; k < add_len; k += num, ucp += num) { add_desc_len = ((ucp[20] << 24) | (ucp[21] << 16) | (ucp[22] << 8) | ucp[23]); num = 24 + add_desc_len; ull = 0; for (j = 0; j < 8; ++j) { if (j > 0) ull <<= 8; ull |= ucp[j]; } printf(" Key=0x%" PRIx64 "\n", ull); if (ucp[12] & 0x2) printf(" All target ports bit set\n"); else { printf(" All target ports bit clear\n"); rel_pt_addr = ((ucp[18] << 8) | ucp[19]); printf(" Relative port address: 0x%x\n", rel_pt_addr); } if (ucp[12] & 0x1) { printf(" << Reservation holder >>\n"); j = ((ucp[13] >> 4) & 0xf); if (0 == j) printf(" scope: LU_SCOPE, "); else printf(" scope: %d ", j); j = (ucp[13] & 0xf); printf(" type: %s\n", pr_type_strs[j]); } else printf(" not reservation holder\n"); if (add_desc_len > 0) decode_transport_id(" ", &ucp[24], add_desc_len, 0); } } } return 0; } /* Compact the 2 dimensional transportid_arr into a one dimensional * array in place returning the length. */ static int compact_transportid_array(struct opts_t * op) { int k, off, protocol_id, len; int compact_len = 0; unsigned char * ucp = op->transportid_arr; for (k = 0, off = 0; ((k < op->num_transportids) && (k < MX_TIDS)); ++k, off += MX_TID_LEN) { protocol_id = ucp[off] & 0xf; if (TPROTO_ISCSI == protocol_id) { len = (ucp[off + 2] << 8) + ucp[off + 3] + 4; if (len < 24) len = 24; if (off > compact_len) memmove(ucp + compact_len, ucp + off, len); compact_len += len; } else { if (off > compact_len) memmove(ucp + compact_len, ucp + off, 24); compact_len += 24; } } return compact_len; } static int prout_work(int sg_fd, struct opts_t * op) { int j, len, res, t_arr_len; unsigned char pr_buff[MX_ALLOC_LEN]; uint64_t param_rk; uint64_t param_sark; char b[64]; char bb[80]; t_arr_len = compact_transportid_array(op); param_rk = op->param_rk; memset(pr_buff, 0, sizeof(pr_buff)); for (j = 7; j >= 0; --j) { pr_buff[j] = (param_rk & 0xff); param_rk >>= 8; } param_sark = op->param_sark; for (j = 7; j >= 0; --j) { pr_buff[8 + j] = (param_sark & 0xff); param_sark >>= 8; } if (op->param_alltgpt) pr_buff[20] |= 0x4; if (op->param_aptpl) pr_buff[20] |= 0x1; len = 24; if (t_arr_len > 0) { pr_buff[20] |= 0x8; /* set SPEC_I_PT bit */ memcpy(&pr_buff[28], op->transportid_arr, t_arr_len); len += (t_arr_len + 4); pr_buff[24] = (unsigned char)((t_arr_len >> 24) & 0xff); pr_buff[25] = (unsigned char)((t_arr_len >> 16) & 0xff); pr_buff[26] = (unsigned char)((t_arr_len >> 8) & 0xff); pr_buff[27] = (unsigned char)(t_arr_len & 0xff); } res = sg_ll_persistent_reserve_out(sg_fd, op->prout_sa, 0, op->prout_type, pr_buff, len, 1, op->verbose); if (res || op->verbose) { if (op->prout_sa < num_prout_sa_strs) snprintf(b, sizeof(b), "%s", prout_sa_strs[op->prout_sa]); else snprintf(b, sizeof(b), "service action=0x%x", op->prout_sa); if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("PR out (%s): command not supported\n", b); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("PR out (%s): bad field in cdb or parameter list " "(perhaps unsupported service action)\n", b); else { sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("PR out (%s): %s\n", b, bb); } return res; } else if (op->verbose) pr2serr("PR out: command (%s) successful\n", b); } return 0; } static int prout_reg_move_work(int sg_fd, struct opts_t * op) { int j, len, res, t_arr_len; unsigned char pr_buff[MX_ALLOC_LEN]; uint64_t param_rk; uint64_t param_sark; t_arr_len = compact_transportid_array(op); param_rk = op->param_rk; memset(pr_buff, 0, sizeof(pr_buff)); for (j = 7; j >= 0; --j) { pr_buff[j] = (param_rk & 0xff); param_rk >>= 8; } param_sark = op->param_sark; for (j = 7; j >= 0; --j) { pr_buff[8 + j] = (param_sark & 0xff); param_sark >>= 8; } if (op->param_unreg) pr_buff[17] |= 0x2; if (op->param_aptpl) pr_buff[17] |= 0x1; pr_buff[18] = (unsigned char)((op->param_rtp >> 8) & 0xff); pr_buff[19] = (unsigned char)(op->param_rtp & 0xff); len = 24; if (t_arr_len > 0) { memcpy(&pr_buff[24], op->transportid_arr, t_arr_len); len += t_arr_len; pr_buff[20] = (unsigned char)((t_arr_len >> 24) & 0xff); pr_buff[21] = (unsigned char)((t_arr_len >> 16) & 0xff); pr_buff[22] = (unsigned char)((t_arr_len >> 8) & 0xff); pr_buff[23] = (unsigned char)(t_arr_len & 0xff); } res = sg_ll_persistent_reserve_out(sg_fd, PROUT_REG_MOVE_SA, 0, op->prout_type, pr_buff, len, 1, op->verbose); if (res) { if (SG_LIB_CAT_INVALID_OP == res) pr2serr("PR out (register and move): command not supported\n"); else if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("PR out (register and move): bad field in cdb or " "parameter list (perhaps unsupported service action)\n"); else { char bb[80]; sg_get_category_sense_str(res, sizeof(bb), bb, op->verbose); pr2serr("PR out (register and move): %s\n", bb); } return res; } else if (op->verbose) pr2serr("PR out: 'register and move' command successful\n"); return 0; } /* Decode various symbolic forms of TransportIDs into SPC-4 format. * Returns 1 if one found, else returns 0. */ static int decode_sym_transportid(const char * lcp, unsigned char * tidp) { int k, j, n, b, c, len, alen; unsigned int ui; const char * ecp; const char * isip; memset(tidp, 0, 24); if ((0 == memcmp("sas,", lcp, 4)) || (0 == memcmp("SAS,", lcp, 4))) { lcp += 4; k = strspn(lcp, "0123456789aAbBcCdDeEfF"); if (16 != k) { pr2serr("badly formed symbolic SAS TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_SAS; for (k = 0, j = 0, b = 0; k < 16; ++k) { c = lcp[k]; if (isdigit(c)) n = c - 0x30; else if (isupper(c)) n = c - 0x37; else n = c - 0x57; if (k & 1) { tidp[4 + j] = b | n; ++j; } else b = n << 4; } return 1; } else if ((0 == memcmp("spi,", lcp, 4)) || (0 == memcmp("SPI,", lcp, 4))) { lcp += 4; if (2 != sscanf(lcp, "%d,%d", &b, &c)) { pr2serr("badly formed symbolic SPI TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_SPI; tidp[2] = (b >> 8) & 0xff; tidp[3] = b & 0xff; tidp[6] = (c >> 8) & 0xff; tidp[7] = c & 0xff; return 1; } else if ((0 == memcmp("fcp,", lcp, 4)) || (0 == memcmp("FCP,", lcp, 4))) { lcp += 4; k = strspn(lcp, "0123456789aAbBcCdDeEfF"); if (16 != k) { pr2serr("badly formed symbolic FCP TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_FCP; for (k = 0, j = 0, b = 0; k < 16; ++k) { c = lcp[k]; if (isdigit(c)) n = c - 0x30; else if (isupper(c)) n = c - 0x37; else n = c - 0x57; if (k & 1) { tidp[8 + j] = b | n; ++j; } else b = n << 4; } return 1; } else if ((0 == memcmp("sbp,", lcp, 4)) || (0 == memcmp("SBP,", lcp, 4))) { lcp += 4; k = strspn(lcp, "0123456789aAbBcCdDeEfF"); if (16 != k) { pr2serr("badly formed symbolic SBP TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_1394; for (k = 0, j = 0, b = 0; k < 16; ++k) { c = lcp[k]; if (isdigit(c)) n = c - 0x30; else if (isupper(c)) n = c - 0x37; else n = c - 0x57; if (k & 1) { tidp[8 + j] = b | n; ++j; } else b = n << 4; } return 1; } else if ((0 == memcmp("srp,", lcp, 4)) || (0 == memcmp("SRP,", lcp, 4))) { lcp += 4; k = strspn(lcp, "0123456789aAbBcCdDeEfF"); if (16 != k) { pr2serr("badly formed symbolic SRP TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_SRP; for (k = 0, j = 0, b = 0; k < 32; ++k) { c = lcp[k]; if (isdigit(c)) n = c - 0x30; else if (isupper(c)) n = c - 0x37; else n = c - 0x57; if (k & 1) { tidp[8 + j] = b | n; ++j; } else b = n << 4; } return 1; } else if (0 == memcmp("iqn.", lcp, 4)) { ecp = strpbrk(lcp, " \t"); isip = strstr(lcp, ",i,0x"); if (ecp && (isip > ecp)) isip = NULL; len = ecp ? (ecp - lcp) : (int)strlen(lcp); tidp[0] = TPROTO_ISCSI | (isip ? 0x40 : 0x0); alen = len + 1; /* at least one trailing null */ if (alen < 20) alen = 20; else if (0 != (alen % 4)) alen = ((alen / 4) + 1) * 4; if (alen > 241) { /* sam5r02.pdf A.2 (Annex) */ pr2serr("iSCSI name too long, alen=%d\n", alen); return 0; } tidp[3] = alen & 0xff; memcpy(tidp + 4, lcp, len); return 1; } else if ((0 == memcmp("sop,", lcp, 4)) || (0 == memcmp("SOP,", lcp, 4))) { lcp += 4; if (2 != sscanf(lcp, "%x", &ui)) { pr2serr("badly formed symbolic SOP TransportID: %s\n", lcp); return 0; } tidp[0] = TPROTO_SOP; tidp[2] = (ui >> 8) & 0xff; tidp[3] = ui & 0xff; return 1; } pr2serr("unable to parse symbolic TransportID: %s\n", lcp); return 0; } /* Read one or more TransportIDs from the given file or from stdin. * Returns 0 if successful, 1 otherwise. */ static int decode_file_tids(const char * fnp, struct opts_t * op) { FILE * fp = stdin; int in_len, k, j, m, split_line; unsigned int h; const char * lcp; char line[1024]; char carry_over[4]; int off = 0; int num = 0; unsigned char * tid_arr = op->transportid_arr; if (fnp) { fp = fopen(fnp, "r"); if (NULL == fp) { pr2serr("decode_file_tids: unable to open %s\n", fnp); return 1; } } carry_over[0] = 0; for (j = 0, off = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) tid_arr[off - 1] = h; /* back up and overwrite */ else { pr2serr("decode_file_tids: carry_over error ['%s'] " "around line %d\n", carry_over, j + 1); goto bad; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; if (decode_sym_transportid(lcp, tid_arr + off)) goto my_cont_a; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("decode_file_tids: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto bad; } for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("decode_file_tids: hex number larger than 0xff " "in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= (int)sizeof(op->transportid_arr)) { pr2serr("decode_file_tids: array length exceeded\n"); goto bad; } tid_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("decode_file_tids: error in line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } } my_cont_a: off += MX_TID_LEN; if (off >= (MX_TIDS * MX_TID_LEN)) { pr2serr("decode_file_tids: array length exceeded\n"); goto bad; } ++num; } op->num_transportids = num; return 0; bad: if (fnp) fclose(fp); return 1; } /* Build transportid array which may contain one or more TransportIDs. * A single TransportID can appear on the command line either as a list of * comma (or single space) separated ASCII hex bytes, or in some transport * protocol specific form (e.g. "sas,5000c50005b32001"). One or more * TransportIDs may be given in a file (syntax: "file=") or read from * stdin in (when "-" is given). Fuller description in manpage of * sg_persist(8). Returns 0 if successful, else 1 . */ static int build_transportid(const char * inp, struct opts_t * op) { int in_len; int k = 0; unsigned int h; const char * lcp; unsigned char * tid_arr = op->transportid_arr; char * cp; char * c2p; lcp = inp; in_len = strlen(inp); if (0 == in_len) { op->num_transportids = 0; } if (('-' == inp[0]) || (0 == memcmp("file=", inp, 5)) || (0 == memcmp("FILE=", inp, 5))) { if ('-' == inp[0]) lcp = NULL; /* read from stdin */ else lcp = inp + 5; /* read from given file */ return decode_file_tids(lcp, op); } else { /* TransportID given directly on command line */ if (decode_sym_transportid(lcp, tid_arr)) goto my_cont_b; k = strspn(inp, "0123456789aAbBcCdDeEfF, "); if (in_len != k) { pr2serr("build_transportid: error at pos %d\n", k + 1); return 1; } for (k = 0; k < (int)sizeof(op->transportid_arr); ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("build_transportid: hex number larger than 0xff " "at pos %d\n", (int)(lcp - inp + 1)); return 1; } tid_arr[k] = h; cp = (char *)strchr(lcp, ','); c2p = (char *)strchr(lcp, ' '); if (NULL == cp) cp = c2p; if (NULL == cp) break; if (c2p && (c2p < cp)) cp = c2p; lcp = cp + 1; } else { pr2serr("build_transportid: error at pos %d\n", (int)(lcp - inp + 1)); return 1; } } my_cont_b: op->num_transportids = 1; if (k >= (int)sizeof(op->transportid_arr)) { pr2serr("build_transportid: array length exceeded\n"); return 1; } } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, res; const char * device_name = NULL; char buff[48]; int help =0; int num_prin_sa = 0; int num_prout_sa = 0; int num_prout_param = 0; int want_prin = 0; int want_prout = 0; int peri_type = 0; int ret = 0; struct sg_simple_inquiry_resp inq_resp; const char * cp; struct opts_t opts; struct opts_t * op; op = &opts; memset(op, 0, sizeof(opts)); op->prin = 1; op->prin_sa = -1; op->prout_sa = -1; op->inquiry = 1; op->alloc_len = MX_ALLOC_LEN; while (1) { int option_index = 0; c = getopt_long(argc, argv, "AcCd:GHhiIkK:l:LMnoPQ:rRsS:T:UvVX:yYzZ", long_options, &option_index); if (c == -1) break; switch (c) { case 'A': op->prout_sa = PROUT_PREE_AB_SA; ++num_prout_sa; break; case 'c': op->prin_sa = PRIN_RCAP_SA; ++num_prin_sa; break; case 'C': op->prout_sa = PROUT_CLEAR_SA; ++num_prout_sa; break; case 'd': device_name = optarg; break; case 'G': op->prout_sa = PROUT_REG_SA; ++num_prout_sa; break; case 'h': ++help; break; case 'H': ++op->hex; break; case 'i': want_prin = 1; break; case 'I': op->prout_sa = PROUT_REG_IGN_SA; ++num_prout_sa; break; case 'k': op->prin_sa = PRIN_RKEY_SA; ++num_prin_sa; break; case 'K': if (1 != sscanf(optarg, "%" SCNx64 "", &op->param_rk)) { pr2serr("bad argument to '--param-rk'\n"); return SG_LIB_SYNTAX_ERROR; } ++num_prout_param; break; case 'l': if (1 != sscanf(optarg, "%x", &op->alloc_len)) { pr2serr("bad argument to '--alloc-length'\n"); return SG_LIB_SYNTAX_ERROR; } else if (MX_ALLOC_LEN < op->alloc_len) { pr2serr("'--alloc-length' argument exceeds maximum value " "(%d)\n", MX_ALLOC_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'L': op->prout_sa = PROUT_REL_SA; ++num_prout_sa; break; case 'M': op->prout_sa = PROUT_REG_MOVE_SA; ++num_prout_sa; break; case 'n': op->inquiry = 0; break; case 'o': want_prout = 1; break; case 'P': op->prout_sa = PROUT_PREE_SA; ++num_prout_sa; break; case 'Q': if (1 != sscanf(optarg, "%x", &op->param_rtp)) { pr2serr("bad argument to '--relative-target-port'\n"); return SG_LIB_SYNTAX_ERROR; } if (op->param_rtp > 0xffff) { pr2serr("argument to '--relative-target-port' 0 to ffff " "inclusive\n"); return SG_LIB_SYNTAX_ERROR; } ++num_prout_param; break; case 'r': op->prin_sa = PRIN_RRES_SA; ++num_prin_sa; break; case 'R': op->prout_sa = PROUT_RES_SA; ++num_prout_sa; break; case 's': op->prin_sa = PRIN_RFSTAT_SA; ++num_prin_sa; break; case 'S': if (1 != sscanf(optarg, "%" SCNx64 "", &op->param_sark)) { pr2serr("bad argument to '--param-sark'\n"); return SG_LIB_SYNTAX_ERROR; } ++num_prout_param; break; case 'T': if (1 != sscanf(optarg, "%x", &op->prout_type)) { pr2serr("bad argument to '--prout-type'\n"); return SG_LIB_SYNTAX_ERROR; } ++num_prout_param; break; case 'U': op->param_unreg = 1; break; case 'v': ++op->verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; case 'X': if (0 != build_transportid(optarg, op)) { pr2serr("bad argument to '--transport-id'\n"); return SG_LIB_SYNTAX_ERROR; } ++num_prout_param; break; case 'y': ++op->readonly; break; case 'Y': op->param_alltgpt = 1; ++num_prout_param; break; case 'z': op->prout_sa = PROUT_REPL_LOST_SA; ++num_prout_sa; break; case 'Z': op->param_aptpl = 1; ++num_prout_param; break; case '?': usage(1); return 0; default: pr2serr("unrecognised switch code 0x%x ??\n", c); usage(1); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(1); return SG_LIB_SYNTAX_ERROR; } } if (help > 0) { usage(help); return 0; } if (NULL == device_name) { pr2serr("No device name given\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } if ((want_prout + want_prin) > 1) { pr2serr("choose '--in' _or_ '--out' (not both)\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } else if (want_prout) { /* syntax check on PROUT arguments */ op->prin = 0; if ((1 != num_prout_sa) || (0 != num_prin_sa)) { pr2serr(">> For Persistent Reserve Out one and only one " "appropriate\n>> service action must be chosen (e.g. " "'--register')\n"); return SG_LIB_SYNTAX_ERROR; } } else { /* syntax check on PRIN arguments */ if (num_prout_sa > 0) { pr2serr(">> When a service action for Persistent Reserve Out " "is chosen the\n>> '--out' option must be given (as a " "safeguard)\n"); return SG_LIB_SYNTAX_ERROR; } if (0 == num_prin_sa) { pr2serr(">> No service action given; assume Persistent Reserve " "In command\n>> with Read Keys service action\n"); op->prin_sa = 0; ++num_prin_sa; } else if (num_prin_sa > 1) { pr2serr("Too many service actions given; choose one only\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } } if ((op->param_unreg || op->param_rtp) && (PROUT_REG_MOVE_SA != op->prout_sa)) { pr2serr("--unreg or --relative-target-port only useful with " "--register-move\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } if ((PROUT_REG_MOVE_SA == op->prout_sa) && (1 != op->num_transportids)) { pr2serr("with --register-move one (and only one) --transport-id " "should be given\n"); usage(1); return SG_LIB_SYNTAX_ERROR; } if (((PROUT_RES_SA == op->prout_sa) || (PROUT_REL_SA == op->prout_sa) || (PROUT_PREE_SA == op->prout_sa) || (PROUT_PREE_AB_SA == op->prout_sa)) && (0 == op->prout_type)) { pr2serr("warning>>> --prout-type probably needs to be given\n"); } if ((op->verbose > 2) && op->num_transportids) { pr2serr("number of tranport-ids decoded from command line (or " "stdin): %d\n", op->num_transportids); pr2serr(" Decode given transport-ids:\n"); decode_transport_id(" ", op->transportid_arr, 0, op->num_transportids); } if (op->inquiry) { if ((sg_fd = sg_cmds_open_device(device_name, 1 /* ro */, op->verbose)) < 0) { pr2serr("sg_persist: error opening file (ro): %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (0 == sg_simple_inquiry(sg_fd, &inq_resp, 1, op->verbose)) { printf(" %.8s %.16s %.4s\n", inq_resp.vendor, inq_resp.product, inq_resp.revision); peri_type = inq_resp.peripheral_type; cp = sg_get_pdt_str(peri_type, sizeof(buff), buff); if (strlen(cp) > 0) printf(" Peripheral device type: %s\n", cp); else printf(" Peripheral device type: 0x%x\n", peri_type); } else { printf("sg_persist: %s doesn't respond to a SCSI INQUIRY\n", device_name); return SG_LIB_CAT_OTHER; } sg_cmds_close_device(sg_fd); } if (0 == op->readonly) { cp = getenv(SG_PERSIST_IN_RDONLY); if (cp && op->prin) op->readonly = 1; } else if (op->readonly > 1) /* -yy forces open(RW) */ op->readonly = 0; if ((sg_fd = sg_cmds_open_device(device_name, op->readonly, op->verbose)) < 0) { pr2serr("sg_persist: error opening file (rw): %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->prin) ret = prin_work(sg_fd, op); else if (PROUT_REG_MOVE_SA == op->prout_sa) ret = prout_reg_move_work(sg_fd, op); else /* PROUT commands other than 'register and move' */ ret = prout_work(sg_fd, op); res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_xcopy.c0000664000175000017500000021147412353021654015150 0ustar douggdougg/* A utility program for copying files. Similar to 'dd' but using * the 'Extended Copy' command. * * Copyright (c) 2011-2014 Hannes Reinecke, SUSE Labs * * Largely taken from 'sg_dd', which has the * * Copyright (C) 1999 - 2010 D. Gilbert and P. Allworth * 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. This program is a specialisation of the Unix "dd" command in which either the input or the output file is a scsi generic device, raw device, a block device or a normal file. The block size ('bs') is assumed to be 512 if not given. This program complains if 'ibs' or 'obs' are given with a value that differs from 'bs' (or the default 512). If 'if' is not given or 'if=-' then stdin is assumed. If 'of' is not given or 'of=-' then stdout assumed. A non-standard argument "bpt" (blocks per transfer) is added to control the maximum number of blocks in each transfer. The default value is 128. For example if "bs=512" and "bpt=32" then a maximum of 32 blocks (16 KiB in this case) is transferred to or from the sg device in a single SCSI command. This version is designed for the linux kernel 2.4, 2.6 and 3 series. */ #define _XOPEN_SOURCE 600 #ifndef _GNU_SOURCE #define _GNU_SOURCE /* resolves u_char typedef in scsi/scsi.h [lk 2.4] */ #endif #include #include #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #include #include #include #include #include /* */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" #include "sg_io_linux.h" static const char * version_str = "0.46 20140625"; #define ME "sg_xcopy: " #define STR_SZ 1024 #define INOUTF_SZ 512 #define EBUFF_SZ 512 #define DEF_BLOCK_SIZE 512 #define DEF_BLOCKS_PER_TRANSFER 128 #define MAX_BLOCKS_PER_TRANSFER 65535 #define DEF_MODE_RESP_LEN 252 #define RW_ERR_RECOVERY_MP 1 #define CACHING_MP 8 #define CONTROL_MP 0xa #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define READ_CAP_REPLY_LEN 8 #define RCAP16_REPLY_LEN 32 #define DEF_TIMEOUT 60000 /* 60,000 millisecs == 60 seconds */ #ifndef RAW_MAJOR #define RAW_MAJOR 255 /*unlikey value */ #endif #define SG_LIB_FLOCK_ERR 90 /* In SPC-4 the cdb opcodes have more generic names */ #define THIRD_PARTY_COPY_OUT_CMD 0x83 #define THIRD_PARTY_COPY_IN_CMD 0x84 /* Third party copy IN (opcode 0x84) and OUT (opcode 0x83) command service * actions */ #define SA_XCOPY_LID1 0x0 /* OUT, originate */ #define SA_XCOPY_LID4 0x1 /* OUT, originate */ #define SA_POP_TOK 0x10 /* OUT, originate */ #define SA_WR_USING_TOK 0x11 /* OUT, originate */ #define SA_COPY_ABORT 0x1C /* OUT, abort */ #define SA_COPY_STATUS_LID1 0x0 /* IN, retrieve */ #define SA_COPY_DATA_LID1 0x1 /* IN, retrieve */ #define SA_COPY_OP_PARAMS 0x3 /* IN, retrieve */ #define SA_COPY_FAIL_DETAILS 0x4 /* IN, retrieve */ #define SA_COPY_STATUS_LID4 0x5 /* IN, retrieve */ #define SA_COPY_DATA_LID4 0x6 /* IN, retrieve */ #define SA_ROD_TOK_INFO 0x7 /* IN, retrieve */ #define SA_ALL_ROD_TOKS 0x8 /* IN, retrieve */ #define DEF_3PC_OUT_TIMEOUT (10 * 60) /* is 10 minutes enough? */ #define DEF_GROUP_NUM 0x0 #define VPD_DEVICE_ID 0x83 #define VPD_3PARTY_COPY 0x8f #define FT_OTHER 1 /* filetype is probably normal */ #define FT_SG 2 /* filetype is sg or bsg char device */ #define FT_RAW 4 /* filetype is raw char device */ #define FT_DEV_NULL 8 /* either "/dev/null" or "." as filename */ #define FT_ST 16 /* filetype is st char device (tape) */ #define FT_BLOCK 32 /* filetype is block device */ #define FT_FIFO 64 /* filetype is a fifo (name pipe) */ #define FT_ERROR 128 /* couldn't "stat" file */ #define TD_FC_WWPN 1 #define TD_FC_PORT 2 #define TD_FC_WWPN_AND_PORT 4 #define TD_SPI 8 #define TD_VPD 16 #define TD_IPV4 32 #define TD_ALIAS 64 #define TD_RDMA 128 #define TD_FW 256 #define TD_SAS 512 #define TD_IPV6 1024 #define TD_IP_COPY_SERVICE 2048 #define TD_ROD 4096 #define XCOPY_TO_SRC "XCOPY_TO_SRC" #define XCOPY_TO_DST "XCOPY_TO_DST" #define DEF_XCOPY_SRC0_DST1 1 #define DEV_NULL_MINOR_NUM 3 #define MIN_RESERVED_SIZE 8192 #define MAX_UNIT_ATTENTIONS 10 #define MAX_ABORTED_CMDS 256 static int64_t dd_count = -1; static int64_t in_full = 0; static int in_partial = 0; static int64_t out_full = 0; static int out_partial = 0; static int do_time = 0; static int verbose = 0; static int start_tm_valid = 0; static struct timeval start_tm; static int blk_sz = 0; static int priority = 1; static int list_id_usage = -1; static char xcopy_flag_cat = 0; static char xcopy_flag_dc = 0; struct xcopy_fp_t { char fname[INOUTF_SZ]; dev_t devno; int sg_type; int sg_fd; unsigned long min_bytes; unsigned long max_bytes; int64_t num_sect; int sect_sz; int append; int excl; int flock; int pad; /* Data descriptor PAD bit (residual data treatment) */ int pdt; /* Peripheral device type */ int xcopy_given; }; static struct xcopy_fp_t ixcf; static struct xcopy_fp_t oxcf; static const char * read_cap_str = "Read capacity"; static const char * rec_copy_op_params_str = "Receive copy operating " "parameters"; static void calc_duration_throughput(int contin); #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void install_handler(int sig_num, void (*sig_handler) (int sig)) { struct sigaction sigact; sigaction (sig_num, NULL, &sigact); if (sigact.sa_handler != SIG_IGN) { sigact.sa_handler = sig_handler; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig_num, &sigact, NULL); } } static void print_stats(const char * str) { if (0 != dd_count) pr2serr(" remaining block count=%" PRId64 "\n", dd_count); pr2serr("%s%" PRId64 "+%d records in\n", str, in_full - in_partial, in_partial); pr2serr("%s%" PRId64 "+%d records out\n", str, out_full - out_partial, out_partial); } static void interrupt_handler(int sig) { struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; sigaction(sig, &sigact, NULL); pr2serr("Interrupted by signal,"); if (do_time) calc_duration_throughput(0); print_stats(""); kill(getpid (), sig); } static void siginfo_handler(int sig) { if (sig) { ; } /* unused, dummy to suppress warning */ pr2serr("Progress report, continuing ...\n"); if (do_time) calc_duration_throughput(1); print_stats(" "); } static int bsg_major_checked = 0; static int bsg_major = 0; static void find_bsg_major(void) { const char * proc_devices = "/proc/devices"; FILE *fp; char a[128]; char b[128]; char * cp; int n; if (NULL == (fp = fopen(proc_devices, "r"))) { if (verbose) pr2serr("fopen %s failed: %s\n", proc_devices, strerror(errno)); return; } while ((cp = fgets(b, sizeof(b), fp))) { if ((1 == sscanf(b, "%s", a)) && (0 == memcmp(a, "Character", 9))) break; } while (cp && (cp = fgets(b, sizeof(b), fp))) { if (2 == sscanf(b, "%d %s", &n, a)) { if (0 == strcmp("bsg", a)) { bsg_major = n; break; } } else break; } if (verbose > 5) { if (cp) pr2serr("found bsg_major=%d\n", bsg_major); else pr2serr("found no bsg char device in %s\n", proc_devices); } fclose(fp); } /* Returns a file descriptor on success (0 or greater), -1 for an open * error, -2 for a standard INQUIRY problem. */ static int open_sg(struct xcopy_fp_t * fp, int verbose) { int devmajor, devminor, offset; struct sg_simple_inquiry_resp sir; char ebuff[EBUFF_SZ]; int len; devmajor = major(fp->devno); devminor = minor(fp->devno); if (fp->sg_type & FT_SG) { snprintf(ebuff, EBUFF_SZ, "%s", fp->fname); } else if (fp->sg_type & FT_BLOCK || fp->sg_type & FT_OTHER) { int fd; snprintf(ebuff, EBUFF_SZ, "/sys/dev/block/%d:%d/partition", devmajor, devminor); if ((fd = open(ebuff, O_RDONLY)) >= 0) { len = read(fd, ebuff, EBUFF_SZ); if (len < 0) { perror("read partition"); } else { offset = strtoul(ebuff, NULL, 10); devminor -= offset; } close(fd); } snprintf(ebuff, EBUFF_SZ, "/dev/block/%d:%d", devmajor, devminor); } else { snprintf(ebuff, EBUFF_SZ, "/dev/char/%d:%d", devmajor, devminor); } fp->sg_fd = sg_cmds_open_device(ebuff, 0, verbose); if (fp->sg_fd < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s device %d:%d for sg", fp->sg_type & FT_BLOCK ? "block" : "char", devmajor, devminor); perror(ebuff); return -1; } if (sg_simple_inquiry(fp->sg_fd, &sir, 0, verbose)) { pr2serr("INQUIRY failed on %s\n", ebuff); sg_cmds_close_device(fp->sg_fd); fp->sg_fd = -1; return -2; } fp->pdt = sir.peripheral_type; if (verbose) pr2serr(" %s: %.8s %.16s %.4s [pdt=%d, 3pc=%d]\n", fp->fname, sir.vendor, sir.product, sir.revision, fp->pdt, !! (0x8 & sir.byte_5)); return fp->sg_fd; } static int dd_filetype(struct xcopy_fp_t * fp) { struct stat st; size_t len = strlen(fp->fname); if ((1 == len) && ('.' == fp->fname[0])) return FT_DEV_NULL; if (stat(fp->fname, &st) < 0) return FT_ERROR; if (S_ISCHR(st.st_mode)) { fp->devno = st.st_rdev; /* major() and minor() defined in sys/sysmacros.h */ if ((MEM_MAJOR == major(st.st_rdev)) && (DEV_NULL_MINOR_NUM == minor(st.st_rdev))) return FT_DEV_NULL; if (RAW_MAJOR == major(st.st_rdev)) return FT_RAW; if (SCSI_GENERIC_MAJOR == major(st.st_rdev)) return FT_SG; if (SCSI_TAPE_MAJOR == major(st.st_rdev)) return FT_ST; if (! bsg_major_checked) { bsg_major_checked = 1; find_bsg_major(); } if (bsg_major == (int)major(st.st_rdev)) return FT_SG; } else if (S_ISBLK(st.st_mode)) { fp->devno = st.st_rdev; return FT_BLOCK; } else if (S_ISFIFO(st.st_mode)) { fp->devno = st.st_dev; return FT_FIFO; } fp->devno = st.st_dev; return FT_OTHER | FT_BLOCK; } static char * dd_filetype_str(int ft, char * buff) { int off = 0; if (FT_DEV_NULL & ft) off += snprintf(buff + off, 32, "null device "); if (FT_SG & ft) off += snprintf(buff + off, 32, "SCSI generic (sg) device "); if (FT_BLOCK & ft) off += snprintf(buff + off, 32, "block device "); if (FT_FIFO & ft) off += snprintf(buff + off, 32, "fifo (named pipe) "); if (FT_ST & ft) off += snprintf(buff + off, 32, "SCSI tape device "); if (FT_RAW & ft) off += snprintf(buff + off, 32, "raw device "); if (FT_OTHER & ft) off += snprintf(buff + off, 32, "other (perhaps ordinary file) "); if (FT_ERROR & ft) off += snprintf(buff + off, 32, "unable to 'stat' file "); return buff; } static int simplified_ft(const struct xcopy_fp_t * xfp) { int ftype = xfp->sg_type; switch (ftype) { case FT_BLOCK: case FT_ST: case FT_OTHER: /* typically regular file */ case FT_DEV_NULL: case FT_FIFO: case FT_ERROR: return ftype; default: if (FT_SG & ftype) { if ((0 == xfp->pdt) || (0xe == xfp->pdt)) /* D-A or RBC */ return FT_BLOCK; else if (0x1 == xfp->pdt) return FT_ST; } return FT_OTHER; } } static int seg_desc_from_dd_type(int in_ft, int in_off, int out_ft, int out_off) { int desc_type = -1; switch (in_ft) { case FT_BLOCK: switch (out_ft) { case FT_ST: if (out_off) break; if (in_off) desc_type = 0x8; else desc_type = 0; break; case FT_BLOCK: if (in_off || out_off) desc_type = 0xA; else desc_type = 2; break; default: break; } break; case FT_ST: if (in_off) break; switch (out_ft) { case FT_ST: if (!out_off) { desc_type = 3; break; } break; case FT_BLOCK: if (out_off) desc_type = 9; else desc_type = 3; break; case FT_DEV_NULL: desc_type = 6; break; default: break; } break; default: break; } return desc_type; } static void usage(int n_help) { if (n_help < 2) goto primary_help; else goto secondary_help; primary_help: pr2serr("Usage: " "sg_xcopy [bpt=BPT] [bs=BS] [cat=0|1] [count=COUNT] [dc=0|1] " "[ibs=BS]\n" " [id_usage=hold|discard|disable] [if=IFILE] " "[iflag=FLAGS]\n" " [list_id=ID] [obs=BS] [of=OFILE] [oflag=FLAGS] " "[prio=PRIO]\n" " [seek=SEEK] [skip=SKIP] [time=0|1] " "[verbose=VERB] [--help]\n" " [--on_dst|--on_src] [--verbose] [--version]\n\n" " where:\n" " bpt is blocks_per_transfer (default: 128)\n" " bs block size (default is 512)\n"); pr2serr(" cat xcopy segment descriptor CAT bit (default: " "0)\n" " count number of blocks to copy (def: device size)\n" " dc xcopy segment descriptor DC bit (default: 0)\n" " ibs input block size (if given must be same as " "'bs=')\n" " id_usage sets list_id_usage field to hold (0), " "discard (2) or\n" " disable (3)\n" " if file or device to read from (def: stdin)\n" " iflag comma separated list of flags applying to " "IFILE\n" " list_id sets list_id field to ID (default: 1 or 0)\n" " obs output block size (if given must be same as " "'bs=')\n" " of file or device to write to (def: stdout), " "OFILE of '.'\n"); pr2serr(" treated as /dev/null\n" " oflag comma separated list of flags applying to " "OFILE\n" " prio set xcopy priority field to PRIO (def: 1)\n" " seek block position to start writing to OFILE\n" " skip block position to start reading from IFILE\n" " time 0->no timing(def), 1->time plus calculate " "throughput\n" " verbose 0->quiet(def), 1->some noise, 2->more noise, " "etc\n" " --help print out this usage message then exit\n" " --on_dst send XCOPY command to OFILE\n" " --on_src send XCOPY command to IFILE\n" " --verbose same action as verbose=1\n" " --version print version information then exit\n\n" "Copy from IFILE to OFILE, similar to dd command; " "but using the SCSI\nEXTENDED COPY (XCOPY(LID1)) command. For " "list of flags, use '-hh'.\n"); return; secondary_help: pr2serr("FLAGS:\n" " append (o) ignored\n" " excl open corresponding device with O_EXCL\n" " flock call flock(LOCK_EX|LOCK_NB)\n" " null does nothing, placeholder\n" " pad set xcopy data descriptor PAD bit on\n" " corresponding device\n" " xcopy send XCOPY command to corresponding device\n" "\n" "ENVIRONMENT VARIABLES:\n" " XCOPY_TO_DST send XCOPY command to OFILE (destination) " "if no other\n" " indication\n" " XCOPY_TO_SRC send XCOPY command to IFILE (source)\n" ); } static int scsi_encode_seg_desc(unsigned char *seg_desc, int seg_desc_type, int64_t num_blk, uint64_t src_lba, uint64_t dst_lba) { int seg_desc_len = 0; seg_desc[0] = seg_desc_type; seg_desc[1] = xcopy_flag_cat | (xcopy_flag_dc << 1); if (seg_desc_type == 0x02) { seg_desc_len = 0x18; seg_desc[4] = 0; seg_desc[5] = 0; /* Source target index */ seg_desc[7] = 1; /* Destination target index */ seg_desc[10] = (num_blk >> 8) & 0xff; seg_desc[11] = num_blk & 0xff; seg_desc[12] = (src_lba >> 56) & 0xff; seg_desc[13] = (src_lba >> 48) & 0xff; seg_desc[14] = (src_lba >> 40) & 0xff; seg_desc[15] = (src_lba >> 32) & 0xff; seg_desc[16] = (src_lba >> 24) & 0xff; seg_desc[17] = (src_lba >> 16) & 0xff; seg_desc[18] = (src_lba >> 8) & 0xff; seg_desc[19] = src_lba & 0xff; seg_desc[20] = (dst_lba >> 56) & 0xff; seg_desc[21] = (dst_lba >> 48) & 0xff; seg_desc[22] = (dst_lba >> 40) & 0xff; seg_desc[23] = (dst_lba >> 32) & 0xff; seg_desc[24] = (dst_lba >> 24) & 0xff; seg_desc[25] = (dst_lba >> 16) & 0xff; seg_desc[26] = (dst_lba >> 8) & 0xff; seg_desc[27] = dst_lba & 0xff; } seg_desc[2] = (seg_desc_len >> 8) & 0xFF; seg_desc[3] = seg_desc_len & 0xFF; return seg_desc_len + 4; } static int scsi_extended_copy(int sg_fd, unsigned char list_id, unsigned char *src_desc, int src_desc_len, unsigned char *dst_desc, int dst_desc_len, int seg_desc_type, int64_t num_blk, uint64_t src_lba, uint64_t dst_lba) { unsigned char xcopyBuff[256]; int desc_offset = 16; int seg_desc_len; int verb, res; char b[80]; verb = (verbose > 1) ? (verbose - 2) : 0; memset(xcopyBuff, 0, 256); xcopyBuff[0] = list_id; xcopyBuff[1] = (list_id_usage << 3) | priority; xcopyBuff[2] = 0; xcopyBuff[3] = src_desc_len + dst_desc_len; /* Two target descriptors */ memcpy(xcopyBuff + desc_offset, src_desc, src_desc_len); desc_offset += src_desc_len; memcpy(xcopyBuff + desc_offset, dst_desc, dst_desc_len); desc_offset += dst_desc_len; seg_desc_len = scsi_encode_seg_desc(xcopyBuff + desc_offset, seg_desc_type, num_blk, src_lba, dst_lba); xcopyBuff[11] = seg_desc_len; /* One segment descriptor */ desc_offset += seg_desc_len; /* set noisy so if a UA happens it will be printed to stderr */ res = sg_ll_3party_copy_out(sg_fd, SA_XCOPY_LID1, list_id, DEF_GROUP_NUM, DEF_3PC_OUT_TIMEOUT, xcopyBuff, desc_offset, 1, verb); if (res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Xcopy(LID1): %s\n", b); } return res; } /* Return of 0 -> success, see sg_ll_read_capacity*() otherwise */ static int scsi_read_capacity(struct xcopy_fp_t *xfp) { int k, res; unsigned int ui; unsigned char rcBuff[RCAP16_REPLY_LEN]; int verb; char b[80]; verb = (verbose ? verbose - 1: 0); res = sg_ll_readcap_10(xfp->sg_fd, 0, 0, rcBuff, READ_CAP_REPLY_LEN, 1, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Read capacity(10): %s\n", b); return res; } if ((0xff == rcBuff[0]) && (0xff == rcBuff[1]) && (0xff == rcBuff[2]) && (0xff == rcBuff[3])) { int64_t ls; res = sg_ll_readcap_16(xfp->sg_fd, 0, 0, rcBuff, RCAP16_REPLY_LEN, 1, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Read capacity(16): %s\n", b); return res; } for (k = 0, ls = 0; k < 8; ++k) { ls <<= 8; ls |= rcBuff[k]; } xfp->num_sect = ls + 1; xfp->sect_sz = (rcBuff[8] << 24) | (rcBuff[9] << 16) | (rcBuff[10] << 8) | rcBuff[11]; } else { ui = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]); /* take care not to sign extend values > 0x7fffffff */ xfp->num_sect = (int64_t)ui + 1; xfp->sect_sz = (rcBuff[4] << 24) | (rcBuff[5] << 16) | (rcBuff[6] << 8) | rcBuff[7]; } if (verbose) pr2serr(" %s: number of blocks=%" PRId64 " [0x%" PRIx64 "], block " "size=%d\n", xfp->fname, xfp->num_sect, xfp->num_sect, xfp->sect_sz); return 0; } static int scsi_operating_parameter(struct xcopy_fp_t *xfp, int is_target) { int res, ftype, snlid; unsigned char rcBuff[256]; unsigned int rcBuffLen = 256, len, n, td_list = 0; unsigned long num, max_target_num, max_segment_num, max_segment_len; unsigned long max_desc_len, max_inline_data, held_data_limit; int verb, valid = 0; char b[80]; verb = (verbose ? verbose - 1: 0); ftype = xfp->sg_type; if (FT_SG & ftype) { if ((0 == xfp->pdt) || (0xe == xfp->pdt)) /* direct-access or RBC */ ftype |= FT_BLOCK; else if (0x1 == xfp->pdt) ftype |= FT_ST; } res = sg_ll_receive_copy_results(xfp->sg_fd, SA_COPY_OP_PARAMS, 0, rcBuff, rcBuffLen, 1, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verb); pr2serr("Xcopy operating parameters: %s\n", b); return -res; } len = ((rcBuff[0] << 24) | (rcBuff[1] << 16) | (rcBuff[2] << 8) | rcBuff[3]) + 4; if (len > rcBuffLen) { pr2serr(" < %d too long for internal buffer, output " "truncated\n", len, rcBuffLen); } if (verbose > 2) { pr2serr("\nOutput response in hex:\n"); dStrHexErr((const char *)rcBuff, len, 1); } snlid = rcBuff[4] & 0x1; max_target_num = rcBuff[8] << 8 | rcBuff[9]; max_segment_num = rcBuff[10] << 8 | rcBuff[11]; max_desc_len = rcBuff[12] << 24 | rcBuff[13] << 16 | rcBuff[14] << 8 | rcBuff[15]; max_segment_len = rcBuff[16] << 24 | rcBuff[17] << 16 | rcBuff[18] << 8 | rcBuff[19]; xfp->max_bytes = max_segment_len ? max_segment_len : ULONG_MAX; max_inline_data = rcBuff[20] << 24 | rcBuff[21] << 16 | rcBuff[22] << 8 | rcBuff[23]; if (verbose) { pr2serr(" >> %s response:\n", rec_copy_op_params_str); pr2serr(" Support No List IDentifier (SNLID): %d\n", snlid); pr2serr(" Maximum target descriptor count: %lu\n", max_target_num); pr2serr(" Maximum segment descriptor count: %lu\n", max_segment_num); pr2serr(" Maximum descriptor list length: %lu\n", max_desc_len); pr2serr(" Maximum segment length: %lu\n", max_segment_len); pr2serr(" Maximum inline data length: %lu\n", max_inline_data); } held_data_limit = rcBuff[24] << 24 | rcBuff[25] << 16 | rcBuff[26] << 8 | rcBuff[27]; if (list_id_usage < 0) { if (!held_data_limit) list_id_usage = 2; else list_id_usage = 0; } if (verbose) { pr2serr(" Held data limit: %lu (list_id_usage: %d)\n", held_data_limit, list_id_usage); num = rcBuff[28] << 24 | rcBuff[29] << 16 | rcBuff[30] << 8 | rcBuff[31]; pr2serr(" Maximum stream device transfer size: %lu\n", num); pr2serr(" Maximum concurrent copies: %u\n", rcBuff[36]); pr2serr(" Data segment granularity: %u bytes\n", 1 << rcBuff[37]); pr2serr(" Inline data granularity: %u bytes\n", 1 << rcBuff[38]); pr2serr(" Held data granularity: %u bytes\n", 1 << rcBuff[39]); pr2serr(" Implemented descriptor list:\n"); } xfp->min_bytes = 1 << rcBuff[37]; for (n = 0; n < rcBuff[43]; n++) { switch(rcBuff[44 + n]) { case 0x00: /* copy block to stream device */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy Block to Stream device\n"); break; case 0x01: /* copy stream to block device */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy Stream to Block device\n"); break; case 0x02: /* copy block to block device */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy Block to Block device\n"); break; case 0x03: /* copy stream to stream device */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy Stream to Stream device\n"); break; case 0x04: /* copy inline data to stream device */ if (!is_target && (ftype & FT_OTHER)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy inline data to Stream device\n"); break; case 0x05: /* copy embedded data to stream device */ if (!is_target && (ftype & FT_OTHER)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy embedded data to Stream device\n"); break; case 0x06: /* Read from stream device and discard */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_DEV_NULL)) valid++; if (verbose) pr2serr(" Read from stream device and discard\n"); break; case 0x07: /* Verify block or stream device operation */ if (!is_target && (ftype & (FT_ST | FT_BLOCK))) valid++; if (is_target && (ftype & (FT_ST | FT_BLOCK))) valid++; if (verbose) pr2serr(" Verify block or stream device operation\n"); break; case 0x08: /* copy block device with offset to stream device */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy block device with offset to stream " "device\n"); break; case 0x09: /* copy stream device to block device with offset */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy stream device to block device with " "offset\n"); break; case 0x0a: /* copy block device with offset to block device with * offset */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy block device with offset to block " "device with offset\n"); break; case 0x0b: /* copy block device to stream device and hold data */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy block device to stream device and hold " "data\n"); break; case 0x0c: /* copy stream device to block device and hold data */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy stream device to block device and hold " "data\n"); break; case 0x0d: /* copy block device to block device and hold data */ if (!is_target && (ftype & FT_BLOCK)) valid++; if (is_target && (ftype & FT_BLOCK)) valid++; if (verbose) pr2serr(" Copy block device to block device and hold " "data\n"); break; case 0x0e: /* copy stream device to stream device and hold data */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_ST)) valid++; if (verbose) pr2serr(" Copy block device to block device and hold " "data\n"); break; case 0x0f: /* read from stream device and hold data */ if (!is_target && (ftype & FT_ST)) valid++; if (is_target && (ftype & FT_DEV_NULL)) valid++; if (verbose) pr2serr(" Read from stream device and hold data\n"); break; case 0xe0: /* FC N_Port_Name */ if (verbose) pr2serr(" FC N_Port_Name target descriptor\n"); td_list |= TD_FC_WWPN; break; case 0xe1: /* FC Port_ID */ if (verbose) pr2serr(" FC Port_ID target descriptor\n"); td_list |= TD_FC_PORT; break; case 0xe2: /* FC N_Port_ID with N_Port_Name checking */ if (verbose) pr2serr(" FC N_Port_ID with N_Port_Name target " "descriptor\n"); td_list |= TD_FC_WWPN_AND_PORT; break; case 0xe3: /* Parallel Interface T_L */ if (verbose) pr2serr(" SPI T_L target descriptor\n"); td_list |= TD_SPI; break; case 0xe4: /* identification descriptor */ if (verbose) pr2serr(" Identification target descriptor\n"); td_list |= TD_VPD; break; case 0xe5: /* IPv4 */ if (verbose) pr2serr(" IPv4 target descriptor\n"); td_list |= TD_IPV4; break; case 0xe6: /* Alias */ if (verbose) pr2serr(" Alias target descriptor\n"); td_list |= TD_ALIAS; break; case 0xe7: /* RDMA */ if (verbose) pr2serr(" RDMA target descriptor\n"); td_list |= TD_RDMA; break; case 0xe8: /* FireWire */ if (verbose) pr2serr(" IEEE 1394 target descriptor\n"); td_list |= TD_FW; break; case 0xe9: /* SAS */ if (verbose) pr2serr(" SAS target descriptor\n"); td_list |= TD_SAS; break; case 0xea: /* IPv6 */ if (verbose) pr2serr(" IPv6 target descriptor\n"); td_list |= TD_IPV6; break; case 0xeb: /* IP Copy Service */ if (verbose) pr2serr(" IP Copy Service target descriptor\n"); td_list |= TD_IP_COPY_SERVICE; break; case 0xfe: /* ROD */ if (verbose) pr2serr(" ROD target descriptor\n"); td_list |= TD_ROD; break; default: pr2serr(">> Unhandled target descriptor 0x%02x\n", rcBuff[44 + n]); break; } } if (!valid) { pr2serr(">> no matching target descriptor supported\n"); td_list = 0; } return td_list; } static void decode_designation_descriptor(const unsigned char * ucp, int i_len) { int m, p_id, piv, c_set, assoc, desig_type, d_id, naa; int k; const unsigned char * ip; uint64_t vsei; char b[64]; ip = ucp + 4; p_id = ((ucp[0] >> 4) & 0xf); c_set = (ucp[0] & 0xf); piv = ((ucp[1] & 0x80) ? 1 : 0); assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); pr2serr(" designator type: %d, code set: %d\n", desig_type, c_set); if (piv && ((1 == assoc) || (2 == assoc))) pr2serr(" transport: %s\n", sg_get_trans_proto_str(p_id, sizeof(b), b)); switch (desig_type) { case 0: /* vendor specific */ k = 0; if ((1 == c_set) || (2 == c_set)) { /* ASCII or UTF-8 */ for (k = 0; (k < i_len) && isprint(ip[k]); ++k) ; if (k >= i_len) k = 1; } if (k) pr2serr(" vendor specific: %.*s\n", i_len, ip); else { pr2serr(" vendor specific:\n"); dStrHexErr((const char *)ip, i_len, 0); } break; case 1: /* T10 vendor identification */ pr2serr(" vendor id: %.8s\n", ip); if (i_len > 8) pr2serr(" vendor specific: %.*s\n", i_len - 8, ip + 8); break; case 2: /* EUI-64 based */ if ((8 != i_len) && (12 != i_len) && (16 != i_len)) { pr2serr(" << expect 8, 12 and 16 byte EUI, got %d>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } pr2serr(" 0x"); for (m = 0; m < i_len; ++m) pr2serr("%02x", (unsigned int)ip[m]); pr2serr("\n"); break; case 3: /* NAA */ if (1 != c_set) { pr2serr(" << unexpected code set %d for NAA>>\n", c_set); dStrHexErr((const char *)ip, i_len, 0); break; } naa = (ip[0] >> 4) & 0xff; if (! ((2 == naa) || (5 == naa) || (6 == naa))) { pr2serr(" << unexpected NAA [0x%x]>>\n", naa); dStrHexErr((const char *)ip, i_len, 0); break; } if ((5 == naa) && (0x10 == i_len)) { if (verbose > 2) pr2serr(" << unexpected NAA 5 len 16, assuming NAA 6 " ">>\n"); naa = 6; } if (2 == naa) { if (8 != i_len) { pr2serr(" << unexpected NAA 2 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = (((ip[0] & 0xf) << 8) | ip[1]); /* c_id = ((ip[2] << 16) | (ip[3] << 8) | ip[4]); */ /* vsi = ((ip[5] << 16) | (ip[6] << 8) | ip[7]); */ pr2serr(" 0x"); for (m = 0; m < 8; ++m) pr2serr("%02x", (unsigned int)ip[m]); pr2serr("\n"); } else if (5 == naa) { if (8 != i_len) { pr2serr(" << unexpected NAA 5 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } /* c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | */ /* (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); */ vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } pr2serr(" 0x"); for (m = 0; m < 8; ++m) pr2serr("%02x", (unsigned int)ip[m]); pr2serr("\n"); } else if (6 == naa) { if (16 != i_len) { pr2serr(" << unexpected NAA 6 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } /* c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | */ /* (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); */ vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } pr2serr(" 0x"); for (m = 0; m < 16; ++m) pr2serr("%02x", (unsigned int)ip[m]); pr2serr("\n"); } break; case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target port " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = ((ip[2] << 8) | ip[3]); pr2serr(" Relative target port: 0x%x\n", d_id); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target port " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = ((ip[2] << 8) | ip[3]); pr2serr(" Target port group: 0x%x\n", d_id); break; case 6: /* Logical unit group */ if ((1 != c_set) || (0 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, logical unit " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = ((ip[2] << 8) | ip[3]); pr2serr(" Logical unit group: 0x%x\n", d_id); break; case 7: /* MD5 logical unit identifier */ if ((1 != c_set) || (0 != assoc)) { pr2serr(" << expected binary code_set, logical unit " "association>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } pr2serr(" MD5 logical unit identifier:\n"); dStrHexErr((const char *)ip, i_len, 0); break; case 8: /* SCSI name string */ if (3 != c_set) { pr2serr(" << expected UTF-8 code_set>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } pr2serr(" SCSI name string:\n"); /* does %s print out UTF-8 ok?? * Seems to depend on the locale. Looks ok here with my * locale setting: en_AU.UTF-8 */ pr2serr(" %s\n", (const char *)ip); break; case 9: /* Protocol specific port identifier */ /* added in spc4r36, PIV must be set, proto_id indicates */ /* whether UAS (USB) or SOP (PCIe) or ... */ if (! piv) pr2serr(" >>>> Protocol specific port identifier " "expects protocol\n" " identifier to be valid and it is not\n"); if (TPROTO_UAS == p_id) { pr2serr(" USB device address: 0x%x\n", 0x7f & ip[0]); pr2serr(" USB interface number: 0x%x\n", ip[2]); } else if (TPROTO_SOP == p_id) { pr2serr(" PCIe routing ID, bus number: 0x%x\n", ip[0]); pr2serr(" function number: 0x%x\n", ip[1]); pr2serr(" [or device number: 0x%x, function number: " "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); } else pr2serr(" >>>> unexpected protocol indentifier: 0x%x\n" " with Protocol specific port " "identifier\n", p_id); break; default: /* reserved */ pr2serr(" reserved designator=0x%x\n", desig_type); dStrHexErr((const char *)ip, i_len, 0); break; } } static int desc_from_vpd_id(int sg_fd, unsigned char *desc, int desc_len, unsigned int block_size, int pad) { int res, verb; unsigned char rcBuff[256], *ucp, *best = NULL; unsigned int len = 254; int off = -1, u, i_len, best_len = 0, assoc, desig, f_desig = 0; char b[80]; verb = (verbose ? verbose - 1: 0); memset(rcBuff, 0xff, len); res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rcBuff, 4, 1, verb); if (0 != res) { if (SG_LIB_CAT_ILLEGAL_REQ == res) pr2serr("Device identification VPD page not found\n"); else { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("VPD inquiry (Device ID): %s\n", b); pr2serr(" try again with '-vv'\n"); } return res; } else if (rcBuff[1] != VPD_DEVICE_ID) { pr2serr("invalid VPD response\n"); return SG_LIB_CAT_MALFORMED; } len = ((rcBuff[2] << 8) + rcBuff[3]) + 4; res = sg_ll_inquiry(sg_fd, 0, 1, VPD_DEVICE_ID, rcBuff, len, 1, verb); if (0 != res) { sg_get_category_sense_str(res, sizeof(b), b, verbose); pr2serr("VPD inquiry (Device ID): %s\n", b); return res; } else if (rcBuff[1] != VPD_DEVICE_ID) { pr2serr("invalid VPD response\n"); return SG_LIB_CAT_MALFORMED; } if (verbose > 2) { pr2serr("Output response in hex:\n"); dStrHexErr((const char *)rcBuff, len, 1); } while ((u = sg_vpd_dev_id_iter(rcBuff + 4, len - 4, &off, 0, -1, -1)) == 0) { ucp = rcBuff + 4 + off; i_len = ucp[3]; if (((unsigned int)off + i_len + 4) > len) { pr2serr(" VPD page error: designator length %d longer " "than\n remaining response length=%d\n", i_len, (len - off)); return SG_LIB_CAT_MALFORMED; } assoc = ((ucp[1] >> 4) & 0x3); desig = (ucp[1] & 0xf); if (verbose > 2) pr2serr(" Desc %d: assoc %u desig %u len %d\n", off, assoc, desig, i_len); /* Descriptor must be less than 16 bytes */ if (i_len > 16) continue; if (desig == 3) { best = ucp; best_len = i_len; break; } if (desig == 2) { if (!best || f_desig < 2) { best = ucp; best_len = i_len; f_desig = 2; } } else if (desig == 1) { if (!best || f_desig == 0) { best = ucp; best_len = i_len; f_desig = desig; } } else if (desig == 0) { if (!best) { best = ucp; best_len = i_len; f_desig = desig; } } } if (best) { if (verbose) decode_designation_descriptor(best, best_len); if (best_len + 4 < desc_len) { memset(desc, 0, 32); desc[0] = 0xe4; memcpy(desc + 4, best, best_len + 4); desc[4] &= 0x1f; desc[28] = pad << 2; desc[29] = (block_size >> 16) & 0xff; desc[30] = (block_size >> 8) & 0xff; desc[31] = block_size & 0xff; if (verbose > 3) { pr2serr("Descriptor in hex (bs %d):\n", block_size); dStrHexErr((const char *)desc, 32, 1); } return 32; } return best_len + 8; } return 0; } static void calc_duration_throughput(int contin) { struct timeval end_tm, res_tm; double a, b; int64_t blks; if (start_tm_valid && (start_tm.tv_sec || start_tm.tv_usec)) { blks = (in_full > out_full) ? in_full : out_full; 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)blk_sz * blks; pr2serr("time to transfer data%s: %d.%06d secs", (contin ? " so far" : ""), (int)res_tm.tv_sec, (int)res_tm.tv_usec); if ((a > 0.00001) && (b > 511)) pr2serr(" at %.2f MB/sec\n", b / (a * 1000000.0)); else pr2serr("\n"); } } /* Process arguments given to 'iflag=" or 'oflag=" options. Returns 0 * on success, 1 on error. */ static int process_flags(const char * arg, struct xcopy_fp_t * fp) { char buff[256]; char * cp; char * np; strncpy(buff, arg, sizeof(buff)); buff[sizeof(buff) - 1] = '\0'; if ('\0' == buff[0]) { pr2serr("no flag found\n"); return 1; } cp = buff; do { np = strchr(cp, ','); if (np) *np++ = '\0'; if (0 == strcmp(cp, "append")) fp->append = 1; else if (0 == strcmp(cp, "excl")) fp->excl = 1; else if (0 == strcmp(cp, "flock")) ++fp->flock; else if (0 == strcmp(cp, "null")) ; else if (0 == strcmp(cp, "pad")) fp->pad = 1; else if (0 == strcmp(cp, "xcopy")) ++fp->xcopy_given; /* for ddpt compatibility */ else { pr2serr("unrecognised flag: %s\n", cp); return 1; } cp = np; } while (cp); return 0; } /* Returns open input file descriptor (>= 0) or a negative value * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error. */ static int open_if(struct xcopy_fp_t * ifp, int verbose) { int infd = -1, flags, fl, res; char ebuff[EBUFF_SZ]; ifp->sg_type = dd_filetype(ifp); if (verbose) pr2serr(" >> Input file type: %s, devno %d:%d\n", dd_filetype_str(ifp->sg_type, ebuff), major(ifp->devno), minor(ifp->devno)); if (FT_ERROR & ifp->sg_type) { pr2serr(ME "unable access %s\n", ifp->fname); goto file_err; } flags = O_NONBLOCK; if (ifp->excl) flags |= O_EXCL; fl = O_RDWR; if ((infd = open(ifp->fname, fl | flags)) < 0) { fl = O_RDONLY; if ((infd = open(ifp->fname, fl | flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg reading", ifp->fname); perror(ebuff); goto file_err; } } if (verbose) pr2serr(" open input(sg_io), flags=0x%x\n", fl | flags); if (ifp->flock) { res = flock(infd, LOCK_EX | LOCK_NB); if (res < 0) { close(infd); snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %s " "failed", ifp->fname); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return infd; file_err: if (infd >= 0) close(infd); return -SG_LIB_FILE_ERROR; } /* Returns open output file descriptor (>= 0), -1 for don't * bother opening (e.g. /dev/null), or a more negative value * (-SG_LIB_FILE_ERROR or -SG_LIB_CAT_OTHER) if error. */ static int open_of(struct xcopy_fp_t * ofp, int verbose) { int outfd, flags, res; char ebuff[EBUFF_SZ]; ofp->sg_type = dd_filetype(ofp); if (verbose) pr2serr(" >> Output file type: %s, devno %d:%d\n", dd_filetype_str(ofp->sg_type, ebuff), major(ofp->devno), minor(ofp->devno)); if (!(FT_DEV_NULL & ofp->sg_type)) { flags = O_RDWR | O_NONBLOCK; if (ofp->excl) flags |= O_EXCL; if ((outfd = open(ofp->fname, flags)) < 0) { snprintf(ebuff, EBUFF_SZ, ME "could not open %s for sg writing", ofp->fname); perror(ebuff); goto file_err; } if (verbose) pr2serr(" open output(sg_io), flags=0x%x\n", flags); } else { outfd = -1; /* don't bother opening */ } if (ofp->flock) { res = flock(outfd, LOCK_EX | LOCK_NB); if (res < 0) { close(outfd); snprintf(ebuff, EBUFF_SZ, ME "flock(LOCK_EX | LOCK_NB) on %s " "failed", ofp->fname); perror(ebuff); return -SG_LIB_FLOCK_ERR; } } return outfd; file_err: return -SG_LIB_FILE_ERROR; } static int num_chs_in_str(const char * s, int slen, int ch) { int res = 0; while (--slen >= 0) { if (ch == s[slen]) ++res; } return res; } int main(int argc, char * argv[]) { int64_t skip = 0; int64_t seek = 0; int ibs = 0; int obs = 0; int bpt = DEF_BLOCKS_PER_TRANSFER; int bpt_given = 0; char str[STR_SZ]; char * key; char * buf; int blocks = 0; int num_help = 0; int num_xcopy = 0; int res, k, n, keylen; int infd, outfd, xcopy_fd; int ret = 0; unsigned char list_id = 1; int list_id_given = 0; unsigned char src_desc[256]; unsigned char dst_desc[256]; int src_desc_len; int dst_desc_len; int seg_desc_type; int on_src = 0; int on_dst = 0; ixcf.fname[0] = '\0'; oxcf.fname[0] = '\0'; ixcf.num_sect = -1; oxcf.num_sect = -1; if (argc < 2) { pr2serr("Won't default both IFILE to stdin _and_ OFILE to stdout\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } for (k = 1; k < argc; k++) { if (argv[k]) { strncpy(str, argv[k], STR_SZ); str[STR_SZ - 1] = '\0'; } else continue; for (key = str, buf = key; *buf && *buf != '=';) buf++; if (*buf) *buf++ = '\0'; keylen = (int)strlen(key); if (0 == strncmp(key, "app", 3)) { ixcf.append = sg_get_num(buf); oxcf.append = ixcf.append; } else if (0 == strcmp(key, "bpt")) { bpt = sg_get_num(buf); if (-1 == bpt) { pr2serr(ME "bad argument to 'bpt='\n"); return SG_LIB_SYNTAX_ERROR; } bpt_given = 1; } else if (0 == strcmp(key, "bs")) { blk_sz = sg_get_num(buf); if (-1 == blk_sz) { pr2serr(ME "bad argument to 'bs='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "list_id")) { ret = sg_get_num(buf); if (-1 == ret || ret > 0xff) { pr2serr(ME "bad argument to 'list_id='\n"); return SG_LIB_SYNTAX_ERROR; } list_id = (ret & 0xff); list_id_given = 1; } else if (0 == strcmp(key, "id_usage")) { if (!strncmp(buf, "hold", 4)) list_id_usage = 0; else if (!strncmp(buf, "discard", 7)) list_id_usage = 2; else if (!strncmp(buf, "disable", 7)) list_id_usage = 3; else { pr2serr(ME "bad argument to 'id_usage='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "conv")) pr2serr(ME ">>> ignoring all 'conv=' arguments\n"); else if (0 == strcmp(key, "count")) { if (0 != strcmp("-1", buf)) { dd_count = sg_get_llnum(buf); if (-1LL == dd_count) { pr2serr(ME "bad argument to 'count='\n"); return SG_LIB_SYNTAX_ERROR; } } /* treat 'count=-1' as calculate count (same as not given) */ } else if (0 == strcmp(key, "prio")) { priority = sg_get_num(buf); } else if (0 == strcmp(key, "cat")) { xcopy_flag_cat = sg_get_num(buf); if (xcopy_flag_cat < 0 || xcopy_flag_cat > 1) { pr2serr(ME "bad argument to 'cat='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "dc")) { xcopy_flag_dc = sg_get_num(buf); if (xcopy_flag_dc < 0 || xcopy_flag_dc > 1) { pr2serr(ME "bad argument to 'dc='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "ibs")) { ibs = sg_get_num(buf); } else if (strcmp(key, "if") == 0) { if ('\0' != ixcf.fname[0]) { pr2serr("Second IFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(ixcf.fname, buf, INOUTF_SZ); } else if (0 == strcmp(key, "iflag")) { if (process_flags(buf, &ixcf)) { pr2serr(ME "bad argument to 'iflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "obs")) { obs = sg_get_num(buf); } else if (strcmp(key, "of") == 0) { if ('\0' != oxcf.fname[0]) { pr2serr("Second OFILE argument??\n"); return SG_LIB_SYNTAX_ERROR; } else strncpy(oxcf.fname, buf, INOUTF_SZ); } else if (0 == strcmp(key, "oflag")) { if (process_flags(buf, &oxcf)) { pr2serr(ME "bad argument to 'oflag='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "seek")) { seek = sg_get_llnum(buf); if (-1LL == 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) { pr2serr(ME "bad argument to 'skip='\n"); return SG_LIB_SYNTAX_ERROR; } } else if (0 == strcmp(key, "time")) do_time = sg_get_num(buf); else if (0 == strncmp(key, "verb", 4)) verbose = sg_get_num(buf); /* look for long options that start with '--' */ else if (0 == strncmp(key, "--help", 6)) ++num_help; else if (0 == strncmp(key, "--on_dst", 8)) ++on_dst; else if (0 == strncmp(key, "--on_src", 8)) ++on_src; else if (0 == strncmp(key, "--verb", 6)) verbose += 1; else if (0 == strncmp(key, "--vers", 6)) { pr2serr(ME "%s\n", version_str); return 0; } else if (0 == strncmp(key, "--xcopy", 7)) ; /* ignore; for compatibility with ddpt */ /* look for short options that start with a single '-', they can be * concaternated (e.g. '-vvvV') */ else if ((keylen > 1) && ('-' == key[0]) && ('-' != key[1])) { res = 0; n = num_chs_in_str(key + 1, keylen - 1, 'h'); num_help += n; res += n; n = num_chs_in_str(key + 1, keylen - 1, 'v'); verbose += n; res += n; if (num_chs_in_str(key + 1, keylen - 1, 'V')) { pr2serr("%s\n", version_str); return -1; } n = num_chs_in_str(key + 1, keylen - 1, 'x'); /* accept and ignore; for compatibility with ddpt */ res += n; if (res < (keylen - 1)) { pr2serr(ME "Unrecognised short option in '%s', try " "'--help'\n", key); if (0 == num_help) return -1; } } else { pr2serr("Unrecognized option '%s'\n", key); if (num_help) usage(num_help); else pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } } if (num_help) { usage(num_help); return 0; } if (on_src && on_dst) { pr2serr("Syntax error - either specify --on_src OR " "--on_dst\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if ((! on_src) && (! on_dst)) { if ((!! ixcf.xcopy_given) == (!! oxcf.xcopy_given)) { char * csp; char * cdp; csp = getenv(XCOPY_TO_SRC); cdp = getenv(XCOPY_TO_DST); if ((!! csp) == (!! cdp)) { #if DEF_XCOPY_SRC0_DST1 == 0 on_src = 1; #else on_dst = 1; #endif } else if (csp) on_src = 1; else on_dst = 1; } else if (ixcf.xcopy_given) on_src = 1; else on_dst = 1; } if (verbose > 1) pr2serr(" >>> Extended Copy(LID1) command will be sent to %s device " "[%s]\n", (on_src ? "src" : "dst"), (on_src ? ixcf.fname : oxcf.fname)); if ((ibs && blk_sz && (ibs != blk_sz)) || (obs && blk_sz && (obs != blk_sz))) { pr2serr("If 'ibs' or 'obs' given must be same as 'bs'\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } if (blk_sz && !ibs) ibs = blk_sz; if (blk_sz && !obs) obs = blk_sz; if ((skip < 0) || (seek < 0)) { pr2serr("skip and seek cannot be negative\n"); return SG_LIB_SYNTAX_ERROR; } if ((oxcf.append > 0) && (seek > 0)) { pr2serr("Can't use both append and seek switches\n"); return SG_LIB_SYNTAX_ERROR; } if (bpt < 1) { pr2serr("bpt must be greater than 0\n"); return SG_LIB_SYNTAX_ERROR; } else if (bpt > MAX_BLOCKS_PER_TRANSFER) { pr2serr("bpt must be less than or equal to %d\n", MAX_BLOCKS_PER_TRANSFER); return SG_LIB_SYNTAX_ERROR; } if (list_id_usage == 3) { /* list_id usage disabled */ if (!list_id_given) list_id = 0; if (list_id) { pr2serr("list_id disabled by id_usage flag\n"); return SG_LIB_SYNTAX_ERROR; } } if (verbose > 1) pr2serr(" >>> " ME " if=%s skip=%" PRId64 " of=%s seek=%" PRId64 " count=%" PRId64 "\n", ixcf.fname, skip, oxcf.fname, seek, dd_count); install_handler(SIGINT, interrupt_handler); install_handler(SIGQUIT, interrupt_handler); install_handler(SIGPIPE, interrupt_handler); install_handler(SIGUSR1, siginfo_handler); infd = STDIN_FILENO; outfd = STDOUT_FILENO; ixcf.pdt = -1; oxcf.pdt = -1; if (ixcf.fname[0] && ('-' != ixcf.fname[0])) { infd = open_if(&ixcf, verbose); if (infd < 0) return -infd; } else { pr2serr("stdin not acceptable for IFILE\n"); return SG_LIB_FILE_ERROR; } if (oxcf.fname[0] && ('-' != oxcf.fname[0])) { outfd = open_of(&oxcf, verbose); if (outfd < -1) return -outfd; } else { pr2serr("stdout not acceptable for OFILE\n"); return SG_LIB_FILE_ERROR; } res = open_sg(&ixcf, verbose); if (res < 0) { if (-1 == res) return SG_LIB_FILE_ERROR; else return SG_LIB_CAT_OTHER; } res = open_sg(&oxcf, verbose); if (res < 0) { if (-1 == res) return SG_LIB_FILE_ERROR; else return SG_LIB_CAT_OTHER; } if ((STDIN_FILENO == infd) && (STDOUT_FILENO == outfd)) { pr2serr("Can't have both 'if' as stdin _and_ 'of' as stdout\n"); pr2serr("For more information use '--help'\n"); return SG_LIB_SYNTAX_ERROR; } res = scsi_read_capacity(&ixcf); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention (%s in), continuing\n", read_cap_str); res = scsi_read_capacity(&ixcf); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command (%s in), continuing\n", read_cap_str); res = scsi_read_capacity(&ixcf); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("%s command not supported on %s\n", read_cap_str, ixcf.fname); else if (res == SG_LIB_CAT_NOT_READY) pr2serr("%s failed on %s - not ready\n", read_cap_str, ixcf.fname); else pr2serr("Unable to %s on %s\n", read_cap_str, ixcf.fname); ixcf.num_sect = -1; } else if (ibs && ixcf.sect_sz != ibs) { pr2serr(">> warning: block size on %s confusion: " "ibs=%d, device claims=%d\n", ixcf.fname, ibs, ixcf.sect_sz); } if (skip && ixcf.num_sect < skip) { pr2serr("argument to 'skip=' exceeds device size (max %" PRId64 ")\n", ixcf.num_sect); return SG_LIB_SYNTAX_ERROR; } res = scsi_read_capacity(&oxcf); if (SG_LIB_CAT_UNIT_ATTENTION == res) { pr2serr("Unit attention (%s out), continuing\n", read_cap_str); res = scsi_read_capacity(&oxcf); } else if (SG_LIB_CAT_ABORTED_COMMAND == res) { pr2serr("Aborted command (%s out), continuing\n", read_cap_str); res = scsi_read_capacity(&oxcf); } if (0 != res) { if (res == SG_LIB_CAT_INVALID_OP) pr2serr("%s command not supported on %s\n", read_cap_str, oxcf.fname); else pr2serr("Unable to %s on %s\n", read_cap_str, oxcf.fname); oxcf.num_sect = -1; } else if (obs && obs != oxcf.sect_sz) { pr2serr(">> warning: block size on %s confusion: obs=%d, device " "claims=%d\n", oxcf.fname, obs, oxcf.sect_sz); } if (seek && oxcf.num_sect < seek) { pr2serr("argument to 'seek=' exceeds device size (max %" PRId64 ")\n", oxcf.num_sect); return SG_LIB_SYNTAX_ERROR; } if ((dd_count < 0) || ((verbose > 0) && (0 == dd_count))) { if (xcopy_flag_dc == 0) { dd_count = ixcf.num_sect - skip; if ((dd_count * ixcf.sect_sz) > ((oxcf.num_sect - seek) * oxcf.sect_sz)) dd_count = (oxcf.num_sect - seek) * oxcf.sect_sz / ixcf.sect_sz; } else { dd_count = oxcf.num_sect - seek; if ((dd_count * oxcf.sect_sz) > ((ixcf.num_sect - skip) * ixcf.sect_sz)) dd_count = (ixcf.num_sect - skip) * ixcf.sect_sz / oxcf.sect_sz; } } else { int64_t dd_bytes; if (xcopy_flag_dc) dd_bytes = dd_count * oxcf.sect_sz; else dd_bytes = dd_count * ixcf.sect_sz; if (dd_bytes > ixcf.num_sect * ixcf.sect_sz) { pr2serr("access beyond end of source device (max %" PRId64 ")\n", ixcf.num_sect); return SG_LIB_SYNTAX_ERROR; } if (dd_bytes > oxcf.num_sect * oxcf.sect_sz) { pr2serr("access beyond end of target device (max %" PRId64 ")\n", oxcf.num_sect); return SG_LIB_SYNTAX_ERROR; } } res = scsi_operating_parameter(&ixcf, 0); if (res < 0) { if (SG_LIB_CAT_UNIT_ATTENTION == -res) { pr2serr("Unit attention (%s), continuing\n", rec_copy_op_params_str); res = scsi_operating_parameter(&ixcf, 0); } else { if (-res == SG_LIB_CAT_INVALID_OP) { pr2serr("%s command not supported on %s\n", rec_copy_op_params_str, ixcf.fname); return EINVAL; } else if (-res == SG_LIB_CAT_NOT_READY) pr2serr("%s failed on %s - not ready\n", rec_copy_op_params_str, ixcf.fname); else { pr2serr("Unable to %s on %s\n", rec_copy_op_params_str, ixcf.fname); return -res; } } } else if (res == 0) return SG_LIB_CAT_INVALID_OP; if (res & TD_VPD) { if (verbose) pr2serr(" >> using VPD identification for source %s\n", ixcf.fname); src_desc_len = desc_from_vpd_id(ixcf.sg_fd, src_desc, sizeof(src_desc), ixcf.sect_sz, ixcf.pad); if (src_desc_len > (int)sizeof(src_desc)) { pr2serr("source descriptor too large (%d bytes)\n", res); return SG_LIB_CAT_MALFORMED; } } else { return SG_LIB_CAT_INVALID_OP; } res = scsi_operating_parameter(&oxcf, 1); if (res < 0) { if (SG_LIB_CAT_UNIT_ATTENTION == -res) { pr2serr("Unit attention (%s), continuing\n", rec_copy_op_params_str); res = scsi_operating_parameter(&oxcf, 1); } else { if (-res == SG_LIB_CAT_INVALID_OP) { pr2serr("%s command not supported on %s\n", rec_copy_op_params_str, oxcf.fname); return EINVAL; } else if (-res == SG_LIB_CAT_NOT_READY) pr2serr("%s failed on %s - not ready\n", rec_copy_op_params_str, oxcf.fname); else { pr2serr("Unable to %s on %s\n", rec_copy_op_params_str, oxcf.fname); return -res; } } } else if (res == 0) return SG_LIB_CAT_INVALID_OP; if (res & TD_VPD) { if (verbose) pr2serr(" >> using VPD identification for destination %s\n", oxcf.fname); dst_desc_len = desc_from_vpd_id(oxcf.sg_fd, dst_desc, sizeof(dst_desc), oxcf.sect_sz, oxcf.pad); if (dst_desc_len > (int)sizeof(dst_desc)) { pr2serr("destination descriptor too large (%d bytes)\n", res); return SG_LIB_CAT_MALFORMED; } } else { return SG_LIB_CAT_INVALID_OP; } if (dd_count < 0) { pr2serr("Couldn't calculate count, please give one\n"); return SG_LIB_CAT_OTHER; } if ((unsigned long)dd_count < ixcf.min_bytes / ixcf.sect_sz) { pr2serr("not enough data to read (min %ld bytes)\n", oxcf.min_bytes); return SG_LIB_CAT_OTHER; } if ((unsigned long)dd_count < oxcf.min_bytes / oxcf.sect_sz) { pr2serr("not enough data to write (min %ld bytes)\n", oxcf.min_bytes); return SG_LIB_CAT_OTHER; } if (bpt_given) { if (xcopy_flag_dc) { if ((unsigned long)bpt * oxcf.sect_sz > oxcf.max_bytes) { pr2serr("bpt too large (max %ld blocks)\n", oxcf.max_bytes / oxcf.sect_sz); return SG_LIB_SYNTAX_ERROR; } } else { if ((unsigned long)bpt * ixcf.sect_sz > ixcf.max_bytes) { pr2serr("bpt too large (max %ld blocks)\n", ixcf.max_bytes / ixcf.sect_sz); return SG_LIB_SYNTAX_ERROR; } } } else { unsigned long r; if (xcopy_flag_dc) r = oxcf.max_bytes / (unsigned long)oxcf.sect_sz; else r = ixcf.max_bytes / (unsigned long)ixcf.sect_sz; bpt = (r > MAX_BLOCKS_PER_TRANSFER) ? MAX_BLOCKS_PER_TRANSFER : r; } seg_desc_type = seg_desc_from_dd_type(simplified_ft(&ixcf), 0, simplified_ft(&oxcf), 0); if (do_time) { start_tm.tv_sec = 0; start_tm.tv_usec = 0; gettimeofday(&start_tm, NULL); start_tm_valid = 1; } if (verbose) pr2serr("Start of loop, count=%" PRId64 ", bpt=%d, lba_in=%" PRId64 ", lba_out=%" PRId64 "\n", dd_count, bpt, skip, seek); xcopy_fd = (on_src) ? infd : outfd; while (dd_count > 0) { if (dd_count > bpt) blocks = bpt; else blocks = dd_count; res = scsi_extended_copy(xcopy_fd, list_id, src_desc, src_desc_len, dst_desc, dst_desc_len, seg_desc_type, blocks, skip, seek); if (res != 0) break; in_full += blocks; skip += blocks; seek += blocks; dd_count -= blocks; num_xcopy++; } if (do_time) calc_duration_throughput(0); if (res) pr2serr("sg_xcopy: failed with error %d (%" PRId64 " blocks left)\n", res, dd_count); else pr2serr("sg_xcopy: %" PRId64 " blocks, %d command%s\n", in_full, num_xcopy, ((num_xcopy > 1) ? "s" : "")); return res; } sg3_utils-1.40/src/sg_ident.c0000664000175000017500000002166312404322612015103 0ustar douggdougg/* * Copyright (c) 2005-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_cmds_extra.h" /* A utility program originally written for the Linux OS SCSI subsystem. * * * This program issues these SCSI commands: REPORT IDENTIFYING INFORMATION * and SET IDENTIFYING INFORMATION. These commands were called REPORT * DEVICE IDENTIFIER and SET DEVICE IDENTIFIER prior to spc4r07. */ static const char * version_str = "1.13 20140904"; #define ME "sg_ident: " #define REPORT_ID_INFO_SANITY_LEN 512 static struct option long_options[] = { {"ascii", 0, 0, 'A'}, {"clear", 0, 0, 'C'}, {"help", 0, 0, 'h'}, {"itype", 1, 0, 'i'}, {"raw", 0, 0, 'r'}, {"set", 0, 0, 'S'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, {0, 0, 0, 0}, }; static void decode_ii(const unsigned char * iip, int ii_len, int itype, int ascii, int raw, int verbose) { int k; if (raw) { if (ii_len > 0) { int n; if (sg_set_binary_mode(STDOUT_FILENO) < 0) perror("sg_set_binary_mode"); #if 0 n = fwrite(iip, 1, ii_len, stdout); #else n = write(STDOUT_FILENO, iip, ii_len); #endif if (verbose && (n < 1)) fprintf(stderr, "unable to write to stdout\n"); } return; } if (0x7f == itype) { /* list of available information types */ for (k = 0; k < (ii_len - 3); k += 4) printf(" Information type: %d, Maximum information length: " "%d bytes\n", iip[k], ((iip[k + 2] << 8) + iip[k + 3])); } else { /* single element */ if (verbose) printf("Information:\n"); if (ii_len > 0) { if (ascii) printf("%.*s\n", ii_len, (const char *)iip); else dStrHex((const char *)iip, ii_len, 0); } } } static void usage() { fprintf(stderr, "Usage: " "sg_ident [--ascii] [--clear] [--help] [--itype=IT] [--raw] " "[--set]\n" " [--verbose] [--version] DEVICE\n" " where:\n" " --ascii|-A report identifying information as ASCII " "(or UTF8) string\n" " --clear|-C clear (set to zero length) identifying " "information\n" " --help|-h print out usage message\n" " --itype=IT|-i IT specify identifying information type " "(def: 0)\n" " --raw|-r output identifying information to " "stdout\n" " --set|-S invoke set identifying information with " "data from stdin\n" " --verbose|-v increase verbosity of output\n" " --version|-V print version string and exit\n\n" "Performs a SCSI REPORT (or SET) IDENTIFYING INFORMATION command\n" ); } int main(int argc, char * argv[]) { int sg_fd, res, c, ii_len; unsigned char rdi_buff[REPORT_ID_INFO_SANITY_LEN + 4]; char b[80]; unsigned char * ucp = NULL; int ascii = 0; int do_clear = 0; int itype = 0; int raw = 0; int do_set = 0; int verbose = 0; const char * device_name = NULL; int ret = 0; while (1) { int option_index = 0; c = getopt_long(argc, argv, "AChi:rSvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'A': ascii = 1; break; case 'C': do_clear = 1; break; case 'h': case '?': usage(); return 0; case 'i': itype = sg_get_num(optarg); if ((itype < 0) || (itype > 127)) { fprintf(stderr, "argument to '--itype' should be in range " "0 to 127\n"); return SG_LIB_SYNTAX_ERROR; } break; case 'r': raw = 1; break; case 'S': do_set = 1; break; case 'v': ++verbose; break; case 'V': fprintf(stderr, ME "version: %s\n", version_str); return 0; default: fprintf(stderr, "unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == device_name) { 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; } } if (NULL == device_name) { fprintf(stderr, "missing device name!\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (do_set && do_clear) { fprintf(stderr, "only one of '--clear' and '--set' can be given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (ascii && raw) { fprintf(stderr, "only one of '--ascii' and '--raw' can be given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if ((do_set || do_clear) && (raw || ascii)) { fprintf(stderr, "'--set' cannot be used with either '--ascii' or " "'--raw'\n"); usage(); return SG_LIB_SYNTAX_ERROR; } sg_fd = sg_cmds_open_device(device_name, 0 /* rw */, verbose); if (sg_fd < 0) { fprintf(stderr, ME "open error: %s: %s\n", device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } memset(rdi_buff, 0x0, sizeof(rdi_buff)); if (do_set || do_clear) { if (do_set) { res = fread(rdi_buff, 1, REPORT_ID_INFO_SANITY_LEN + 2, stdin); if (res <= 0) { fprintf(stderr, "no data read from stdin; to clear " "identifying information use '--clear' instead\n"); ret = -1; goto err_out; } else if (res > REPORT_ID_INFO_SANITY_LEN) { fprintf(stderr, "SPC-4 limits information length to 512 " "bytes\n"); ret = -1; goto err_out; } ii_len = res; res = sg_ll_set_id_info(sg_fd, itype, rdi_buff, ii_len, 1, verbose); } else /* do_clear */ res = sg_ll_set_id_info(sg_fd, itype, rdi_buff, 0, 1, verbose); if (res) { ret = res; sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Set identifying information: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for more information\n"); } } else { /* do report identifying information */ res = sg_ll_report_id_info(sg_fd, itype, rdi_buff, 4, 1, verbose); if (0 == res) { ii_len = (rdi_buff[0] << 24) + (rdi_buff[1] << 16) + (rdi_buff[2] << 8) + rdi_buff[3]; if ((! raw) && (verbose > 0)) printf("Reported identifying information length = %d\n", ii_len); if (0 == ii_len) { if (verbose > 1) fprintf(stderr, " This implies the device has an " "empty information field\n"); goto err_out; } if (ii_len > REPORT_ID_INFO_SANITY_LEN) { fprintf(stderr, " That length (%d) seems too long for an " "information\n", ii_len); ret = -1; goto err_out; } ucp = rdi_buff; res = sg_ll_report_id_info(sg_fd, itype, ucp, ii_len + 4, 1, verbose); if (0 == res) { ii_len = (ucp[0] << 24) + (ucp[1] << 16) + (ucp[2] << 8) + ucp[3]; decode_ii(ucp + 4, ii_len, itype, ascii, raw, verbose); } else ret = res; } else ret = res; if (ret) { sg_get_category_sense_str(res, sizeof(b), b, verbose); fprintf(stderr, "Report identifying information: %s\n", b); if (0 == verbose) fprintf(stderr, " try '-v' for more information\n"); } } err_out: res = sg_cmds_close_device(sg_fd); if (res < 0) { fprintf(stderr, "close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/src/sg_vpd.c0000664000175000017500000042365612430315266014607 0ustar douggdougg/* * Copyright (c) 2006-2014 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS 1 #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "sg_lib.h" #include "sg_cmds_basic.h" #include "sg_pt.h" #include "sg_unaligned.h" /* This utility program was originally written for the Linux OS SCSI subsystem. This program fetches Vital Product Data (VPD) pages from the given device and outputs it as directed. VPD pages are obtained via a SCSI INQUIRY command. Most of the data in this program is obtained from the SCSI SPC-4 document at http://www.t10.org . */ static const char * version_str = "0.96 20141110"; /* spc4r37 + sbc4r03 */ /* These structures are duplicates of those of the same name in * sg_vpd_vendor.c . Take care that both are the same. */ struct opts_t { int do_all; int do_enum; int do_hex; int num_vpd; int do_ident; int do_long; int maxlen; int do_quiet; int do_raw; int vend_prod_num; int verbose; const char * device_name; const char * page_str; const char * inhex_fn; const char * vend_prod; }; struct svpd_values_name_t { int value; /* VPD page number */ int subvalue; /* to differentiate if value+pdt are not unique */ int pdt; /* peripheral device type id, -1 is the default */ /* (all or not applicable) value */ const char * acron; const char * name; }; void svpd_enumerate_vendor(int vend_prod_num); int svpd_count_vendor_vpds(int num_vpd, int vend_prod_num); int svpd_decode_vendor(int sg_fd, struct opts_t * op, int off); const struct svpd_values_name_t * svpd_find_vendor_by_acron(const char * ap); int svpd_find_vp_num_by_acron(const char * vp_ap); const struct svpd_values_name_t * svpd_find_vendor_by_num(int page_num, int vend_prod_num); int vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page, int mxlen, int vb, int * rlenp); /* standard VPD pages, in ascending page number order */ #define VPD_SUPPORTED_VPDS 0x0 #define VPD_UNIT_SERIAL_NUM 0x80 #define VPD_IMP_OP_DEF 0x81 /* obsolete in SPC-2 */ #define VPD_ASCII_OP_DEF 0x82 /* obsolete in SPC-2 */ #define VPD_DEVICE_ID 0x83 #define VPD_SOFTW_INF_ID 0x84 #define VPD_MAN_NET_ADDR 0x85 #define VPD_EXT_INQ 0x86 #define VPD_MODE_PG_POLICY 0x87 #define VPD_SCSI_PORTS 0x88 #define VPD_ATA_INFO 0x89 #define VPD_POWER_CONDITION 0x8a #define VPD_DEVICE_CONSTITUENTS 0x8b #define VPD_CFA_PROFILE_INFO 0x8c #define VPD_POWER_CONSUMPTION 0x8d #define VPD_3PARTY_COPY 0x8f /* 3PC, XCOPY, SPC-4, SBC-3 */ #define VPD_PROTO_LU 0x90 #define VPD_PROTO_PORT 0x91 #define VPD_BLOCK_LIMITS 0xb0 /* SBC-3 */ #define VPD_SA_DEV_CAP 0xb0 /* SSC-3 */ #define VPD_OSD_INFO 0xb0 /* OSD */ #define VPD_BLOCK_DEV_CHARS 0xb1 /* SBC-3 */ #define VPD_MAN_ASS_SN 0xb1 /* SSC-3, ADC-2 */ #define VPD_SECURITY_TOKEN 0xb1 /* OSD */ #define VPD_TA_SUPPORTED 0xb2 /* SSC-3 */ #define VPD_LB_PROVISIONING 0xb2 /* SBC-3 */ #define VPD_REFERRALS 0xb3 /* SBC-3 */ #define VPD_AUTOMATION_DEV_SN 0xb3 /* SSC-3 */ #define VPD_SUP_BLOCK_LENS 0xb4 /* SBC-4 */ #define VPD_DTDE_ADDRESS 0xb4 /* SSC-4 */ #define VPD_BLOCK_DEV_C_EXTENS 0xb5 /* SBC-4 */ #define VPD_ZBC_DEV_CHARS 0xb6 /* ZBC */ #define VPD_NO_RATHER_STD_INQ -2 /* request for standard inquiry */ /* Device identification VPD page associations */ #define VPD_ASSOC_LU 0 #define VPD_ASSOC_TPORT 1 #define VPD_ASSOC_TDEVICE 2 /* values for selection one or more associations (2**vpd_assoc), except _AS_IS */ #define VPD_DI_SEL_LU 1 #define VPD_DI_SEL_TPORT 2 #define VPD_DI_SEL_TARGET 4 #define VPD_DI_SEL_AS_IS 32 #define DEF_ALLOC_LEN 252 #define MX_ALLOC_LEN (0xc000 + 0x80) #define VPD_ATA_INFO_LEN 572 #define SENSE_BUFF_LEN 64 /* Arbitrary, could be larger */ #define INQUIRY_CMD 0x12 #define INQUIRY_CMDLEN 6 #define DEF_PT_TIMEOUT 60 /* 60 seconds */ unsigned char rsp_buff[MX_ALLOC_LEN + 2]; static int decode_dev_ids(const char * print_if_found, unsigned char * buff, int len, int m_assoc, int m_desig_type, int m_code_set, int long_out, int quiet); static void decode_transport_id(const char * leadin, unsigned char * ucp, int len); static struct option long_options[] = { {"all", no_argument, 0, 'a'}, {"enumerate", no_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"hex", no_argument, 0, 'H'}, {"ident", no_argument, 0, 'i'}, {"inhex", required_argument, 0, 'I'}, {"long", no_argument, 0, 'l'}, {"maxlen", required_argument, 0, 'm'}, {"page", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, {"raw", no_argument, 0, 'r'}, {"vendor", required_argument, 0, 'M'}, {"verbose", no_argument, 0, 'v'}, {"version", no_argument, 0, 'V'}, {0, 0, 0, 0}, }; /* arranged in alphabetical order by acronym */ static struct svpd_values_name_t standard_vpd_pg[] = { {VPD_ATA_INFO, 0, -1, "ai", "ATA information (SAT)"}, {VPD_ASCII_OP_DEF, 0, -1, "aod", "ASCII implemented operating definition (obsolete)"}, {VPD_AUTOMATION_DEV_SN, 0, 1, "adsn", "Automation device serial " "number (SSC)"}, {VPD_BLOCK_LIMITS, 0, 0, "bl", "Block limits (SBC)"}, {VPD_BLOCK_DEV_CHARS, 0, 0, "bdc", "Block device characteristics " "(SBC)"}, {VPD_BLOCK_DEV_C_EXTENS, 0, 0, "bdce", "Block device characteristics " "extension (SBC)"}, {VPD_CFA_PROFILE_INFO, 0, 0, "cfa", "CFA profile information"}, {VPD_DEVICE_CONSTITUENTS, 0, -1, "dc", "Device constituents"}, {VPD_DEVICE_ID, 0, -1, "di", "Device identification"}, {VPD_DEVICE_ID, VPD_DI_SEL_AS_IS, -1, "di_asis", "Like 'di' " "but designators ordered as found"}, {VPD_DEVICE_ID, VPD_DI_SEL_LU, -1, "di_lu", "Device identification, " "lu only"}, {VPD_DEVICE_ID, VPD_DI_SEL_TPORT, -1, "di_port", "Device " "identification, target port only"}, {VPD_DEVICE_ID, VPD_DI_SEL_TARGET, -1, "di_target", "Device " "identification, target device only"}, {VPD_DTDE_ADDRESS, 0, 1, "dtde", "Data transfer device element address (SSC)"}, {VPD_EXT_INQ, 0, -1, "ei", "Extended inquiry data"}, {VPD_IMP_OP_DEF, 0, -1, "iod", "Implemented operating definition (obsolete)"}, {VPD_LB_PROVISIONING, 0, 0, "lbpv", "Logical block provisioning (SBC)"}, {VPD_MAN_ASS_SN, 0, 1, "mas", "Manufacturer assigned serial number (SSC)"}, {VPD_MAN_ASS_SN, 0, 0x12, "masa", "Manufacturer assigned serial number (ADC)"}, {VPD_MAN_NET_ADDR, 0, -1, "mna", "Management network addresses"}, {VPD_MODE_PG_POLICY, 0, -1, "mpp", "Mode page policy"}, {VPD_OSD_INFO, 0, 0x11, "oi", "OSD information"}, {VPD_POWER_CONDITION, 0, -1, "pc", "Power condition"}, {VPD_POWER_CONSUMPTION, 0, -1, "psm", "Power consumption"}, {VPD_PROTO_LU, 0, -1, "pslu", "Protocol-specific logical unit " "information"}, {VPD_PROTO_PORT, 0, -1, "pspo", "Protocol-specific port information"}, {VPD_REFERRALS, 0, 0, "ref", "Referrals (SBC)"}, {VPD_SA_DEV_CAP, 0, 1, "sad", "Sequential access device capabilities (SSC)"}, {VPD_SOFTW_INF_ID, 0, -1, "sii", "Software interface identification"}, {VPD_NO_RATHER_STD_INQ, 0, -1, "sinq", "Standard inquiry response"}, {VPD_UNIT_SERIAL_NUM, 0, -1, "sn", "Unit serial number"}, {VPD_SCSI_PORTS, 0, -1, "sp", "SCSI ports"}, {VPD_SECURITY_TOKEN, 0, 0x11, "st", "Security token (OSD)"}, {VPD_SUP_BLOCK_LENS, 0, 0, "sbl", "Supported block lengths and " "protection types (SBC)"}, {VPD_SUPPORTED_VPDS, 0, -1, "sv", "Supported VPD pages"}, {VPD_TA_SUPPORTED, 0, 1, "tas", "TapeAlert supported flags (SSC)"}, {VPD_3PARTY_COPY, 0, -1, "tpc", "Third party copy"}, {VPD_ZBC_DEV_CHARS, 0, -1, "zbdc", "Zoned block device characteristics"}, /* Use pdt of -1 since this page both for pdt=0 and pdt=0x14 */ {0, 0, 0, NULL, NULL}, }; #ifdef __GNUC__ static int pr2serr(const char * fmt, ...) __attribute__ ((format (printf, 1, 2))); #else static int pr2serr(const char * fmt, ...); #endif static int pr2serr(const char * fmt, ...) { va_list args; int n; va_start(args, fmt); n = vfprintf(stderr, fmt, args); va_end(args); return n; } static void usage() { pr2serr("Usage: sg_vpd [--all] [--enumerate] [--help] [--hex] " "[--ident]\n" " [--inhex=FN] [--long] [--maxlen=LEN] " "[--page=PG] [--quiet]\n" " [--raw] [--vendor=VP] [--verbose] [--version] " "DEVICE\n"); pr2serr(" where:\n" " --all|-a output all pages listed in the supported " "pages VPD\n" " page\n" " --enumerate|-e enumerate known VPD pages names (ignore " "DEVICE),\n" " can be used with --page=num to search\n" " --help|-h output this usage message then exit\n" " --hex|-H output page in ASCII hexadecimal\n" " --ident|-i output device identification VPD page, " "twice for\n" " short logical unit designator (equiv: " "'-qp di_lu')\n" " --inhex=FN|-I FN read ASCII hex from file FN instead of " "DEVICE;\n" " if used with --raw then read binary " "from FN\n" " --long|-l perform extra decoding\n" " --maxlen=LEN|-m LEN max response length (allocation " "length in cdb)\n" " (def: 0 -> 252 bytes)\n" " --page=PG|-p PG fetch VPD page where PG is an " "acronym, or a decimal\n" " number unless hex indicator " "is given (e.g. '0x83')\n" " --quiet|-q suppress some output when decoding\n" " --raw|-r output page in binary\n" " --vendor=VP | -M VP vendor/product abbreviation [or " "number]\n" " --verbose|-v increase verbosity\n" " --version|-V print version string and exit\n\n" "Fetch Vital Product Data (VPD) page using SCSI INQUIRY or " "decodes VPD\npage response held in file FN. To list available " "pages use '-e'. Also\n'-p -1' yields the standard INQUIRY " "response.\n"); } /* Read ASCII hex bytes or binary from fname (a file named '-' taken as * stdin). If reading ASCII hex then there should be either one entry per * line or a comma, space or tab separated list of bytes. If no_space is * set then a string of ACSII hex digits is expected, 2 per byte. Everything * from and including a '#' on a line is ignored. Returns 0 if ok, or 1 if * error. */ static int f2hex_arr(const char * fname, int as_binary, int no_space, unsigned char * mp_arr, int * mp_arr_len, int max_arr_len) { int fn_len, in_len, k, j, m, split_line, fd, has_stdin; unsigned int h; const char * lcp; FILE * fp; char line[512]; char carry_over[4]; int off = 0; struct stat a_stat; if ((NULL == fname) || (NULL == mp_arr) || (NULL == mp_arr_len)) return 1; fn_len = strlen(fname); if (0 == fn_len) return 1; has_stdin = ((1 == fn_len) && ('-' == fname[0])); /* read from stdin */ if (as_binary) { if (has_stdin) fd = STDIN_FILENO; else { fd = open(fname, O_RDONLY); if (fd < 0) { pr2serr("unable to open binary file %s: %s\n", fname, safe_strerror(errno)); return 1; } } k = read(fd, mp_arr, max_arr_len); if (k <= 0) { if (0 == k) pr2serr("read 0 bytes from binary file %s\n", fname); else pr2serr("read from binary file %s: %s\n", fname, safe_strerror(errno)); if (! has_stdin) close(fd); return 1; } if ((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); if (0 == m) break; if (m < 0) { pr2serr("read from binary pipe %s: %s\n", fname, safe_strerror(errno)); if (! has_stdin) close(fd); return 1; } k += m; } } *mp_arr_len = k; if (! has_stdin) close(fd); return 0; } else { /* So read the file as ASCII hex */ if (has_stdin) fp = stdin; else { fp = fopen(fname, "r"); if (NULL == fp) { pr2serr("Unable to open %s for reading\n", fname); return 1; } } } carry_over[0] = 0; for (j = 0; j < 512; ++j) { if (NULL == fgets(line, sizeof(line), fp)) break; in_len = strlen(line); if (in_len > 0) { if ('\n' == line[in_len - 1]) { --in_len; line[in_len] = '\0'; split_line = 0; } else split_line = 1; } if (in_len < 1) { carry_over[0] = 0; continue; } if (carry_over[0]) { if (isxdigit(line[0])) { carry_over[1] = line[0]; carry_over[2] = '\0'; if (1 == sscanf(carry_over, "%x", &h)) mp_arr[off - 1] = h; /* back up and overwrite */ else { pr2serr("f2hex_arr: carry_over error ['%s'] around line " "%d\n", carry_over, j + 1); goto bad; } lcp = line + 1; --in_len; } else lcp = line; carry_over[0] = 0; } else lcp = line; m = strspn(lcp, " \t"); if (m == in_len) continue; lcp += m; in_len -= m; if ('#' == *lcp) continue; k = strspn(lcp, "0123456789aAbBcCdDeEfF ,\t"); if ((k < in_len) && ('#' != lcp[k])) { pr2serr("f2hex_arr: syntax error at line %d, pos %d\n", j + 1, m + k + 1); goto bad; } if (no_space) { for (k = 0; isxdigit(*lcp) && isxdigit(*(lcp + 1)); ++k, lcp += 2) { if (1 != sscanf(lcp, "%2x", &h)) { pr2serr("f2hex_arr: bad hex number in line %d, " "pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; } if (isxdigit(*lcp) && (! isxdigit(*(lcp + 1)))) carry_over[0] = *lcp; off += k; } else { for (k = 0; k < 1024; ++k) { if (1 == sscanf(lcp, "%x", &h)) { if (h > 0xff) { pr2serr("f2hex_arr: hex number larger than " "0xff in line %d, pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } if (split_line && (1 == strlen(lcp))) { /* single trailing hex digit might be a split pair */ carry_over[0] = *lcp; } if ((off + k) >= max_arr_len) { pr2serr("f2hex_arr: array length exceeded\n"); goto bad; } mp_arr[off + k] = h; lcp = strpbrk(lcp, " ,\t"); if (NULL == lcp) break; lcp += strspn(lcp, " ,\t"); if ('\0' == *lcp) break; } else { if ('#' == *lcp) { --k; break; } pr2serr("f2hex_arr: error in line %d, at pos %d\n", j + 1, (int)(lcp - line + 1)); goto bad; } } off += (k + 1); } } *mp_arr_len = off; if (stdin != fp) fclose(fp); return 0; bad: if (stdin != fp) fclose(fp); return 1; } /* Local version of sg_ll_inquiry() [found in libsgutils] that additionally * passes back resid. Same return values as sg_ll_inquiry() (0 is good). */ static int pt_inquiry(int sg_fd, int evpd, int pg_op, void * resp, int mx_resp_len, int * residp, int noisy, int verbose) { int res, ret, k, sense_cat, resid; unsigned char inqCmdBlk[INQUIRY_CMDLEN] = {INQUIRY_CMD, 0, 0, 0, 0, 0}; unsigned char sense_b[SENSE_BUFF_LEN]; unsigned char * up; struct sg_pt_base * ptvp; if (evpd) inqCmdBlk[1] |= 1; inqCmdBlk[2] = (unsigned char)pg_op; /* 16 bit allocation length (was 8) is a recent SPC-3 addition */ inqCmdBlk[3] = (unsigned char)((mx_resp_len >> 8) & 0xff); inqCmdBlk[4] = (unsigned char)(mx_resp_len & 0xff); if (verbose) { pr2serr(" inquiry cdb: "); for (k = 0; k < INQUIRY_CMDLEN; ++k) pr2serr("%02x ", inqCmdBlk[k]); pr2serr("\n"); } if (resp && (mx_resp_len > 0)) { up = (unsigned char *)resp; up[0] = 0x7f; /* defensive prefill */ if (mx_resp_len > 4) up[4] = 0; } ptvp = construct_scsi_pt_obj(); if (NULL == ptvp) { pr2serr("inquiry: out of memory\n"); return -1; } set_scsi_pt_cdb(ptvp, inqCmdBlk, sizeof(inqCmdBlk)); set_scsi_pt_sense(ptvp, sense_b, sizeof(sense_b)); set_scsi_pt_data_in(ptvp, (unsigned char *)resp, mx_resp_len); res = do_scsi_pt(ptvp, sg_fd, DEF_PT_TIMEOUT, verbose); ret = sg_cmds_process_resp(ptvp, "inquiry", res, mx_resp_len, sense_b, noisy, verbose, &sense_cat); resid = get_scsi_pt_resid(ptvp); if (residp) *residp = resid; destruct_scsi_pt_obj(ptvp); if (-1 == ret) ; else if (-2 == ret) { switch (sense_cat) { case SG_LIB_CAT_RECOVERED: case SG_LIB_CAT_NO_SENSE: ret = 0; break; default: ret = sense_cat; break; } } else if (ret < 4) { if (verbose) pr2serr("inquiry: got too few bytes (%d)\n", ret); ret = SG_LIB_CAT_MALFORMED; } else ret = 0; if (resid > 0) { if (resid > mx_resp_len) { pr2serr("INQUIRY resid (%d) should never exceed requested " "len=%d\n", resid, mx_resp_len); return ret ? ret : SG_LIB_CAT_MALFORMED; } /* zero unfilled section of response buffer */ memset((unsigned char *)resp + (mx_resp_len - resid), 0, resid); } return ret; } /* mxlen is command line --maxlen=LEN option (def: 0) or -1 for a VPD page * with a short length (1 byte). Returns 0 for success. */ int /* global: use by sg_vpd_vendor.c */ vpd_fetch_page_from_dev(int sg_fd, unsigned char * rp, int page, int mxlen, int vb, int * rlenp) { int res, resid, rlen, len, n; if (sg_fd < 0) { len = sg_get_unaligned_be16(rp + 2) + 4; if (vb && (len > mxlen)) pr2serr("warning: VPD page's length (%d) > bytes in --inhex=FN " "file (%d)\n", len , mxlen); if (rlenp) *rlenp = (len < mxlen) ? len : mxlen; return 0; } if (mxlen > MX_ALLOC_LEN) { pr2serr("--maxlen=LEN too long: %d > %d\n", mxlen, MX_ALLOC_LEN); return SG_LIB_SYNTAX_ERROR; } n = (mxlen > 0) ? mxlen : DEF_ALLOC_LEN; res = pt_inquiry(sg_fd, 1, page, rp, n, &resid, 1, vb); if (res) return res; rlen = n - resid; if (rlen < 4) { pr2serr("VPD response too short (len=%d)\n", rlen); return SG_LIB_CAT_MALFORMED; } if (page != rp[1]) { pr2serr("invalid VPD response; probably a STANDARD INQUIRY " "response\n"); n = (rlen < 32) ? rlen : 32; if (vb) { pr2serr("First %d bytes of bad response\n", n); dStrHexErr((const char *)rp, n, 0); } return SG_LIB_CAT_MALFORMED; } if (mxlen < 0) len = rp[3] + 4; else len = sg_get_unaligned_be16(rp + 2) + 4; if (len <= rlen) { if (rlenp) *rlenp = len; return 0; } else if (mxlen) { if (rlenp) *rlenp = rlen; return 0; } if (len > MX_ALLOC_LEN) { pr2serr("response length too long: %d > %d\n", len, MX_ALLOC_LEN); return SG_LIB_CAT_MALFORMED; } else { res = pt_inquiry(sg_fd, 1, page, rp, len, &resid, 1, vb); if (res) return res; rlen = len - resid; /* assume it is well behaved: hence page and len still same */ if (rlenp) *rlenp = rlen; return 0; } } static const struct svpd_values_name_t * sdp_get_vpd_detail(int page_num, int subvalue, int pdt) { const struct svpd_values_name_t * vnp; int sv, ty; sv = (subvalue < 0) ? 1 : 0; ty = (pdt < 0) ? 1 : 0; for (vnp = standard_vpd_pg; vnp->acron; ++vnp) { if ((page_num == vnp->value) && (sv || (subvalue == vnp->subvalue)) && (ty || (pdt == vnp->pdt))) return vnp; } if (! ty) return sdp_get_vpd_detail(page_num, subvalue, -1); if (! sv) return sdp_get_vpd_detail(page_num, -1, -1); return NULL; } static const struct svpd_values_name_t * sdp_find_vpd_by_acron(const char * ap) { const struct svpd_values_name_t * vnp; for (vnp = standard_vpd_pg; vnp->acron; ++vnp) { if (0 == strcmp(vnp->acron, ap)) return vnp; } return NULL; } static void enumerate_vpds(int standard, int vendor) { const struct svpd_values_name_t * vnp; if (standard) { for (vnp = standard_vpd_pg; vnp->acron; ++vnp) { if (vnp->name) { if (vnp->value < 0) printf(" %-10s -1 %s\n", vnp->acron, vnp->name); else printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value, vnp->name); } } } if (vendor) svpd_enumerate_vendor(-2); } static int count_standard_vpds(int num_vpd) { const struct svpd_values_name_t * vnp; int matches; for (vnp = standard_vpd_pg, matches = 0; vnp->acron; ++vnp) { if ((num_vpd == vnp->value) && vnp->name) { if (0 == matches) printf("Matching standard VPD pages:\n"); ++matches; if (vnp->value < 0) printf(" %-10s -1 %s\n", vnp->acron, vnp->name); else printf(" %-10s 0x%02x %s\n", vnp->acron, vnp->value, vnp->name); } } return matches; } static void dStrRaw(const char * str, int len) { int k; for (k = 0 ; k < len; ++k) printf("%c", str[k]); } /* Assume index is less than 16 */ const char * sg_ansi_version_arr[] = { "no conformance claimed", "SCSI-1", /* obsolete, ANSI X3.131-1986 */ "SCSI-2", /* obsolete, ANSI X3.131-1994 */ "SPC", /* withdrawn */ "SPC-2", "SPC-3", "SPC-4", "SPC-5", "ecma=1, [8h]", "ecma=1, [9h]", "ecma=1, [Ah]", "ecma=1, [Bh]", "reserved [Ch]", "reserved [Dh]", "reserved [Eh]", "reserved [Fh]", }; static void decode_std_inq(unsigned char * b, int len, int verbose) { int pqual, n; if (len < 4) return; pqual = (b[0] & 0xe0) >> 5; if (0 == pqual) printf("standard INQUIRY:\n"); else if (1 == pqual) printf("standard INQUIRY: [qualifier indicates no connected " "LU]\n"); else if (3 == pqual) printf("standard INQUIRY: [qualifier indicates not capable " "of supporting LU]\n"); else printf("standard INQUIRY: [reserved or vendor specific " "qualifier [%d]]\n", pqual); printf(" PQual=%d Device_type=%d RMB=%d LU_CONG=%d version=0x%02x ", pqual, b[0] & 0x1f, !!(b[1] & 0x80), !!(b[1] & 0x40), (unsigned int)b[2]); printf(" [%s]\n", sg_ansi_version_arr[b[2] & 0xf]); printf(" [AERC=%d] [TrmTsk=%d] NormACA=%d HiSUP=%d " " Resp_data_format=%d\n", !!(b[3] & 0x80), !!(b[3] & 0x40), !!(b[3] & 0x20), !!(b[3] & 0x10), b[3] & 0x0f); if (len < 5) return; n = b[4] + 5; if (verbose) pr2serr(">> requested %d bytes, %d bytes available\n", len, n); printf(" SCCS=%d ACC=%d TPGS=%d 3PC=%d Protect=%d ", !!(b[5] & 0x80), !!(b[5] & 0x40), ((b[5] & 0x30) >> 4), !!(b[5] & 0x08), !!(b[5] & 0x01)); printf(" [BQue=%d]\n EncServ=%d ", !!(b[6] & 0x80), !!(b[6] & 0x40)); if (b[6] & 0x10) printf("MultiP=1 (VS=%d) ", !!(b[6] & 0x20)); else printf("MultiP=0 "); printf("[MChngr=%d] [ACKREQQ=%d] Addr16=%d\n [RelAdr=%d] ", !!(b[6] & 0x08), !!(b[6] & 0x04), !!(b[6] & 0x01), !!(b[7] & 0x80)); printf("WBus16=%d Sync=%d [Linked=%d] [TranDis=%d] ", !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x08), !!(b[7] & 0x04)); printf("CmdQue=%d\n", !!(b[7] & 0x02)); if (len < 36) return; printf(" Vendor_identification: %.8s\n", b + 8); printf(" Product_identification: %.16s\n", b + 16); printf(" Product_revision_level: %.4s\n", b + 32); } static const char * assoc_arr[] = { "Addressed logical unit", "Target port", /* that received request; unless SCSI ports VPD */ "Target device that contains addressed lu", "Reserved [0x3]", }; static void decode_id_vpd(unsigned char * buff, int len, int subvalue, int do_long, int do_quiet) { int m_a, m_d, m_cs; if (len < 4) { pr2serr("Device identification VPD page length too short=%d\n", len); return; } m_a = -1; m_d = -1; m_cs = -1; if (0 == subvalue) { decode_dev_ids(assoc_arr[VPD_ASSOC_LU], buff + 4, len - 4, VPD_ASSOC_LU, m_d, m_cs, do_long, do_quiet); decode_dev_ids(assoc_arr[VPD_ASSOC_TPORT], buff + 4, len - 4, VPD_ASSOC_TPORT, m_d, m_cs, do_long, do_quiet); decode_dev_ids(assoc_arr[VPD_ASSOC_TDEVICE], buff + 4, len - 4, VPD_ASSOC_TDEVICE, m_d, m_cs, do_long, do_quiet); } else if (VPD_DI_SEL_AS_IS == subvalue) decode_dev_ids(NULL, buff + 4, len - 4, m_a, m_d, m_cs, do_long, do_quiet); else { if (VPD_DI_SEL_LU & subvalue) decode_dev_ids(assoc_arr[VPD_ASSOC_LU], buff + 4, len - 4, VPD_ASSOC_LU, m_d, m_cs, do_long, do_quiet); if (VPD_DI_SEL_TPORT & subvalue) decode_dev_ids(assoc_arr[VPD_ASSOC_TPORT], buff + 4, len - 4, VPD_ASSOC_TPORT, m_d, m_cs, do_long, do_quiet); if (VPD_DI_SEL_TARGET & subvalue) decode_dev_ids(assoc_arr[VPD_ASSOC_TDEVICE], buff + 4, len - 4, VPD_ASSOC_TDEVICE, m_d, m_cs, do_long, do_quiet); } } static const char * network_service_type_arr[] = { "unspecified", "storage configuration service", "diagnostics", "status", "logging", "code download", "copy service", "administrative configuration service", "reserved[0x8]", "reserved[0x9]", "reserved[0xa]", "reserved[0xb]", "reserved[0xc]", "reserved[0xd]", "reserved[0xe]", "reserved[0xf]", "reserved[0x10]", "reserved[0x11]", "reserved[0x12]", "reserved[0x13]", "reserved[0x14]", "reserved[0x15]", "reserved[0x16]", "reserved[0x17]", "reserved[0x18]", "reserved[0x19]", "reserved[0x1a]", "reserved[0x1b]", "reserved[0x1c]", "reserved[0x1d]", "reserved[0x1e]", "reserved[0x1f]", }; /* VPD_MAN_NET_ADDR */ static void decode_net_man_vpd(unsigned char * buff, int len, int do_hex) { int k, bump, na_len; unsigned char * ucp; if ((1 == do_hex) || (do_hex > 2)) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } if (len < 4) { pr2serr("Management network addresses VPD page length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { printf(" %s, Service type: %s\n", assoc_arr[(ucp[0] >> 5) & 0x3], network_service_type_arr[ucp[0] & 0x1f]); na_len = sg_get_unaligned_be16(ucp + 2); bump = 4 + na_len; if ((k + bump) > len) { pr2serr("Management network addresses VPD page, short " "descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (na_len > 0) { if (do_hex > 1) { printf(" Network address:\n"); dStrHex((const char *)(ucp + 4), na_len, 0); } else printf(" %s\n", ucp + 4); } } } static const char * mode_page_policy_arr[] = { "shared", "per target port", "per initiator port", "per I_T nexus", }; /* VPD_MODE_PG_POLICY */ static void decode_mode_policy_vpd(unsigned char * buff, int len, int do_hex) { int k, bump; unsigned char * ucp; if ((1 == do_hex) || (do_hex > 2)) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (len < 4) { pr2serr("Mode page policy VPD page length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { bump = 4; if ((k + bump) > len) { pr2serr("Mode page policy VPD page, short " "descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (do_hex > 1) dStrHex((const char *)ucp, 4, 1); else { printf(" Policy page code: 0x%x", (ucp[0] & 0x3f)); if (ucp[1]) printf(", subpage code: 0x%x\n", ucp[1]); else printf("\n"); printf(" MLUS=%d, Policy: %s\n", !!(ucp[2] & 0x80), mode_page_policy_arr[ucp[2] & 0x3]); } } } /* VPD_SCSI_PORTS */ static void decode_scsi_ports_vpd(unsigned char * buff, int len, int do_hex, int do_long, int do_quiet) { int k, bump, rel_port, ip_tid_len, tpd_len; unsigned char * ucp; if ((1 == do_hex) || (do_hex > 2)) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (len < 4) { pr2serr("SCSI Ports VPD page length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { rel_port = sg_get_unaligned_be16(ucp + 2); printf(" Relative port=%d\n", rel_port); ip_tid_len = sg_get_unaligned_be16(ucp + 6); bump = 8 + ip_tid_len; if ((k + bump) > len) { pr2serr("SCSI Ports VPD page, short descriptor " "length=%d, left=%d\n", bump, (len - k)); return; } if (ip_tid_len > 0) { if (do_hex > 1) { printf(" Initiator port transport id:\n"); dStrHex((const char *)(ucp + 8), ip_tid_len, 1); } else decode_transport_id(" ", ucp + 8, ip_tid_len); } tpd_len = sg_get_unaligned_be16(ucp + bump + 2); if ((k + bump + tpd_len + 4) > len) { pr2serr("SCSI Ports VPD page, short descriptor(tgt) " "length=%d, left=%d\n", bump, (len - k)); return; } if (tpd_len > 0) { if (do_hex > 1) { printf(" Target port descriptor(s):\n"); dStrHex((const char *)(ucp + bump + 4), tpd_len, 1); } else { if ((0 == do_quiet) || (ip_tid_len > 0)) printf(" Target port descriptor(s):\n"); decode_dev_ids("SCSI Ports", ucp + bump + 4, tpd_len, VPD_ASSOC_TPORT, -1, -1, do_long, do_quiet); } } bump += tpd_len + 4; } } static const char * code_set_arr[] = { "Reserved [0x0]", "Binary", "ASCII", "UTF-8", "Reserved [0x4]", "Reserved [0x5]", "Reserved [0x6]", "Reserved [0x7]", "Reserved [0x8]", "Reserved [0x9]", "Reserved [0xa]", "Reserved [0xb]", "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]", }; static const char * desig_type_arr[] = { "vendor specific [0x0]", "T10 vendor identification", "EUI-64 based", "NAA", "Relative target port", "Target port group", /* spc4r09: _primary_ target port group */ "Logical unit group", "MD5 logical unit identifier", "SCSI name string", "Protocol specific port identifier", /* spc4r36 */ "Reserved [0xa]", "Reserved [0xb]", "Reserved [0xc]", "Reserved [0xd]", "Reserved [0xe]", "Reserved [0xf]", }; /* Prints outs an abridged set of device identification designators selected by association, designator type and/or code set. */ static int decode_dev_ids_quiet(unsigned char * buff, int len, int m_assoc, int m_desig_type, int m_code_set) { int m, p_id, c_set, piv, desig_type, i_len, naa, off, u; int assoc, is_sas, rtp; const unsigned char * ucp; const unsigned char * ip; unsigned char sas_tport_addr[8]; rtp = 0; memset(sas_tport_addr, 0, sizeof(sas_tport_addr)); off = -1; if (buff[2] != 0) { if (m_assoc != VPD_ASSOC_LU) return 0; ip = buff; p_id = 0; c_set = 1; assoc = VPD_ASSOC_LU; piv = 0; is_sas = 0; desig_type = 3; i_len = 16; off = 16; goto decode; } while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type, m_code_set)) == 0) { ucp = buff + off; i_len = ucp[3]; if ((off + i_len + 4) > len) { pr2serr(" VPD page error: designator length longer than\n" " remaining response length=%d\n", (len - off)); return SG_LIB_CAT_MALFORMED; } ip = ucp + 4; p_id = ((ucp[0] >> 4) & 0xf); c_set = (ucp[0] & 0xf); piv = ((ucp[1] & 0x80) ? 1 : 0); is_sas = (piv && (6 == p_id)) ? 1 : 0; assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); decode: switch (desig_type) { case 0: /* vendor specific */ break; case 1: /* T10 vendor identification */ break; case 2: /* EUI-64 based */ if ((8 != i_len) && (12 != i_len) && (16 != i_len)) pr2serr(" << expect 8, 12 and 16 byte " "EUI, got %d>>\n", i_len); printf(" 0x"); for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; case 3: /* NAA */ naa = (ip[0] >> 4) & 0xff; if (1 != c_set) { pr2serr(" << expected binary code_set (1), got %d for " "NAA=%d>>\n", c_set, naa); dStrHexErr((const char *)ip, i_len, 0); break; } switch (naa) { case 2: /* NAA IEEE extended */ if (8 != i_len) { pr2serr(" << unexpected NAA 2 identifier " "length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; case 3: /* Locally assigned */ case 5: /* IEEE Registered */ if (8 != i_len) { pr2serr(" << unexpected NAA 3 or 5 " "identifier length: 0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } if ((0 == is_sas) || (1 != assoc)) { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } else if (rtp) { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf(",0x%x\n", rtp); rtp = 0; } else { if (sas_tport_addr[0]) { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)sas_tport_addr[m]); printf("\n"); } memcpy(sas_tport_addr, ip, sizeof(sas_tport_addr)); } break; case 6: /* NAA IEEE registered extended */ if (16 != i_len) { pr2serr(" << unexpected NAA 6 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } printf(" 0x"); for (m = 0; m < 16; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; default: pr2serr(" << bad NAA nibble, expected 2, 3, 5 or 6, got " "%d>>\n", naa); dStrHexErr((const char *)ip, i_len, 0); break; } break; case 4: /* Relative target port */ if ((0 == is_sas) || (1 != c_set) || (1 != assoc) || (4 != i_len)) break; rtp = sg_get_unaligned_be16(ip + 2); if (sas_tport_addr[0]) { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)sas_tport_addr[m]); printf(",0x%x\n", rtp); memset(sas_tport_addr, 0, sizeof(sas_tport_addr)); rtp = 0; } break; case 5: /* (primary) Target port group */ break; case 6: /* Logical unit group */ break; case 7: /* MD5 logical unit identifier */ break; case 8: /* SCSI name string */ if (3 != c_set) { pr2serr(" << expected UTF-8 code_set>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } if (strncmp((const char *)ip, "eui.", 4) || strncmp((const char *)ip, "naa.", 4) || strncmp((const char *)ip, "iqn.", 4)) { pr2serr(" << expected name string prefix>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } /* does %s print out UTF-8 ok?? * Seems to depend on the locale. Looks ok here with my * locale setting: en_AU.UTF-8 */ printf(" %s\n", (const char *)ip); break; case 9: /* PCIe routing ID */ break; default: /* reserved */ break; } } if (sas_tport_addr[0]) { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)sas_tport_addr[m]); printf("\n"); } if (-2 == u) { pr2serr("VPD page error: short designator around offset %d\n", off); return SG_LIB_CAT_MALFORMED; } return 0; } static void decode_designation_descriptor(const unsigned char * ip, int i_len, int p_id, int c_set, int piv, int assoc, int desig_type, int long_out, int print_assoc) { int m, ci_off, c_id, d_id, naa; int vsi, k; uint64_t vsei; uint64_t id_ext; char b[64]; if (print_assoc) printf(" %s:\n", assoc_arr[assoc]); printf(" designator type: %s, code set: %s\n", desig_type_arr[desig_type], code_set_arr[c_set]); if (piv && ((1 == assoc) || (2 == assoc))) printf(" transport: %s\n", sg_get_trans_proto_str(p_id, sizeof(b), b)); /* printf(" associated with the %s\n", assoc_arr[assoc]); */ switch (desig_type) { case 0: /* vendor specific */ k = 0; if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ for (k = 0; (k < i_len) && isprint(ip[k]); ++k) ; if (k >= i_len) k = 1; } if (k) printf(" vendor specific: %.*s\n", i_len, ip); else { pr2serr(" vendor specific:\n"); dStrHexErr((const char *)ip, i_len, 0); } break; case 1: /* T10 vendor identification */ printf(" vendor id: %.8s\n", ip); if (i_len > 8) { if ((2 == c_set) || (3 == c_set)) { /* ASCII or UTF-8 */ printf(" vendor specific: %.*s\n", i_len - 8, ip + 8); } else { printf(" vendor specific: 0x"); for (m = 8; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } } break; case 2: /* EUI-64 based */ if (! long_out) { if ((8 != i_len) && (12 != i_len) && (16 != i_len)) { pr2serr(" << expect 8, 12 and 16 byte EUI, got %d>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } printf(" 0x"); for (m = 0; m < i_len; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; } printf(" EUI-64 based %d byte identifier\n", i_len); if (1 != c_set) { pr2serr(" << expected binary code_set (1)>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } ci_off = 0; if (16 == i_len) { ci_off = 8; id_ext = sg_get_unaligned_be64(ip); printf(" Identifier extension: 0x%" PRIx64 "\n", id_ext); } else if ((8 != i_len) && (12 != i_len)) { pr2serr(" << can only decode 8, 12 and 16 byte ids>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } c_id = sg_get_unaligned_be24(ip + ci_off); printf(" IEEE Company_id: 0x%x\n", c_id); vsei = ((uint64_t)sg_get_unaligned_be32(ip + ci_off + 3) << 8) + ip[ci_off + 3 + 4]; /* 5 byte integer */ printf(" Vendor Specific Extension Identifier: 0x%" PRIx64 "\n", vsei); if (12 == i_len) { d_id = sg_get_unaligned_be32(ip + 8); printf(" Directory ID: 0x%x\n", d_id); } break; case 3: /* NAA */ if (1 != c_set) { pr2serr(" << unexpected code set %d for NAA>>\n", c_set); dStrHexErr((const char *)ip, i_len, 0); break; } naa = (ip[0] >> 4) & 0xff; switch (naa) { case 2: /* NAA 2: IEEE Extended */ if (8 != i_len) { pr2serr(" << unexpected NAA 2 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = sg_get_unaligned_be16(ip) & 0xfff; c_id = sg_get_unaligned_be24(ip + 2); vsi = sg_get_unaligned_be24(ip + 5); if (long_out) { printf(" NAA 2, vendor specific identifier A: " "0x%x\n", d_id); printf(" IEEE Company_id: 0x%x\n", c_id); printf(" vendor specific identifier B: 0x%x\n", vsi); printf(" [0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); } printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; case 3: /* NAA 3: Locally assigned */ if (8 != i_len) { pr2serr(" << unexpected NAA 3 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } if (long_out) printf(" NAA 3, Locally assigned value:\n"); printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); break; case 5: /* NAA 5: IEEE Registered */ if (8 != i_len) { pr2serr(" << unexpected NAA 5 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } if (long_out) { c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } printf(" NAA 5, IEEE Company_id: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); printf(" [0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); } else { printf(" 0x"); for (m = 0; m < 8; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } break; case 6: /* NAA 6: IEEE Registered extended */ if (16 != i_len) { pr2serr(" << unexpected NAA 6 identifier length: " "0x%x>>\n", i_len); dStrHexErr((const char *)ip, i_len, 0); break; } c_id = (((ip[0] & 0xf) << 20) | (ip[1] << 12) | (ip[2] << 4) | ((ip[3] & 0xf0) >> 4)); vsei = ip[3] & 0xf; for (m = 1; m < 5; ++m) { vsei <<= 8; vsei |= ip[3 + m]; } if (long_out) { printf(" NAA 6, IEEE Company_id: 0x%x\n", c_id); printf(" Vendor Specific Identifier: 0x%" PRIx64 "\n", vsei); vsei = sg_get_unaligned_be64(ip + 8); printf(" Vendor Specific Identifier Extension: " "0x%" PRIx64 "\n", vsei); printf(" [0x"); for (m = 0; m < 16; ++m) printf("%02x", (unsigned int)ip[m]); printf("]\n"); } else { printf(" 0x"); for (m = 0; m < 16; ++m) printf("%02x", (unsigned int)ip[m]); printf("\n"); } break; default: pr2serr(" << unexpected NAA [0x%x]>>\n", naa); dStrHexErr((const char *)ip, i_len, 0); break; } break; case 4: /* Relative target port */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target port " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = sg_get_unaligned_be16(ip + 2); printf(" Relative target port: 0x%x\n", d_id); break; case 5: /* (primary) Target port group */ if ((1 != c_set) || (1 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, target port " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = sg_get_unaligned_be16(ip + 2); printf(" Target port group: 0x%x\n", d_id); break; case 6: /* Logical unit group */ if ((1 != c_set) || (0 != assoc) || (4 != i_len)) { pr2serr(" << expected binary code_set, logical unit " "association, length 4>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } d_id = sg_get_unaligned_be16(ip + 2); printf(" Logical unit group: 0x%x\n", d_id); break; case 7: /* MD5 logical unit identifier */ if ((1 != c_set) || (0 != assoc)) { pr2serr(" << expected binary code_set, logical unit " "association>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } printf(" MD5 logical unit identifier:\n"); dStrHex((const char *)ip, i_len, 0); break; case 8: /* SCSI name string */ if (3 != c_set) { pr2serr(" << expected UTF-8 code_set>>\n"); dStrHexErr((const char *)ip, i_len, 0); break; } if (strncmp((const char *)ip, "eui.", 4) || strncmp((const char *)ip, "naa.", 4) || strncmp((const char *)ip, "iqn.", 4)) { pr2serr(" << expected name string prefix>>\n"); dStrHexErr((const char *)ip, i_len, -1); break; } printf(" SCSI name string:\n"); /* does %s print out UTF-8 ok?? * Seems to depend on the locale. Looks ok here with my * locale setting: en_AU.UTF-8 */ printf(" %s\n", (const char *)ip); break; case 9: /* Protocol specific port identifier */ /* added in spc4r36, PIV must be set, proto_id indicates */ /* whether UAS (USB) or SOP (PCIe) or ... */ if (! piv) printf(" >>>> Protocol specific port identifier " "expects protocol\n" " identifier to be valid and it is not\n"); if (TPROTO_UAS == p_id) { printf(" USB device address: 0x%x\n", 0x7f & ip[0]); printf(" USB interface number: 0x%x\n", ip[2]); } else if (TPROTO_SOP == p_id) { printf(" PCIe routing ID, bus number: 0x%x\n", ip[0]); printf(" function number: 0x%x\n", ip[1]); printf(" [or device number: 0x%x, function number: " "0x%x]\n", (0x1f & (ip[1] >> 3)), 0x7 & ip[1]); } else pr2serr(" >>>> unexpected protocol indentifier: %s\n" " with Protocol specific port " "identifier\n", sg_get_trans_proto_str(p_id, sizeof(b), b)); break; default: /* reserved */ pr2serr(" reserved designator=0x%x\n", desig_type); dStrHexErr((const char *)ip, i_len, 0); break; } } /* Prints outs device identification designators selected by association, designator type and/or code set. */ static int decode_dev_ids(const char * print_if_found, unsigned char * buff, int len, int m_assoc, int m_desig_type, int m_code_set, int long_out, int quiet) { int assoc, i_len, c_set, piv, p_id, desig_type; int printed, off, u; const unsigned char * ucp; if (quiet) return decode_dev_ids_quiet(buff, len, m_assoc, m_desig_type, m_code_set); if ( buff[2] != 0 ) { if (m_assoc == VPD_ASSOC_LU) decode_designation_descriptor( buff, 16, 0, 1, 0, m_assoc, 3, long_out, 0); return 0; } off = -1; printed = 0; while ((u = sg_vpd_dev_id_iter(buff, len, &off, m_assoc, m_desig_type, m_code_set)) == 0) { ucp = buff + off; i_len = ucp[3]; if ((off + i_len + 4) > len) { pr2serr(" VPD page error: designator length longer than\n" " remaining response length=%d\n", (len - off)); return SG_LIB_CAT_MALFORMED; } assoc = ((ucp[1] >> 4) & 0x3); if (print_if_found && (0 == printed)) { printed = 1; printf(" %s:\n", print_if_found); } if (NULL == print_if_found) printf(" %s:\n", assoc_arr[assoc]); p_id = ((ucp[0] >> 4) & 0xf); c_set = (ucp[0] & 0xf); piv = ((ucp[1] & 0x80) ? 1 : 0); desig_type = (ucp[1] & 0xf); decode_designation_descriptor(ucp + 4, i_len, p_id, c_set, piv, assoc, desig_type, long_out, 0); } if (-2 == u) { pr2serr("VPD page error: short designator around offset %d\n", off); return SG_LIB_CAT_MALFORMED; } return 0; } /* Transport IDs are initiator port identifiers, typically other than the initiator port issuing a SCSI command. */ static void decode_transport_id(const char * leadin, unsigned char * ucp, int len) { int format_code, proto_id, num, k; uint64_t ull; int bump; for (k = 0, bump= 24; k < len; k += bump, ucp += bump) { if ((len < 24) || (0 != (len % 4))) printf("%sTransport Id short or not multiple of 4 " "[length=%d]:\n", leadin, len); else printf("%sTransport Id of initiator:\n", leadin); format_code = ((ucp[0] >> 6) & 0x3); proto_id = (ucp[0] & 0xf); switch (proto_id) { case TPROTO_FCP: /* Fibre channel */ printf("%s FCP-2 World Wide Name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); bump = 24; break; case TPROTO_SPI: /* Scsi Parallel Interface */ printf("%s Parallel SCSI initiator SCSI address: 0x%x\n", leadin, sg_get_unaligned_be16(ucp + 2)); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); printf("%s relative port number (of corresponding target): " "0x%x\n", leadin, sg_get_unaligned_be16(ucp + 6)); bump = 24; break; case TPROTO_SSA: printf("%s SSA (transport id not defined):\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; case TPROTO_1394: /* IEEE 1394 */ printf("%s IEEE 1394 EUI-64 name:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 8, -1); bump = 24; break; case TPROTO_SRP: printf("%s RDMA initiator port identifier:\n", leadin); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); dStrHex((const char *)&ucp[8], 16, -1); bump = 24; break; case TPROTO_ISCSI: printf("%s iSCSI ", leadin); num = sg_get_unaligned_be16(ucp + 2); if (0 == format_code) printf("name: %.*s\n", num, &ucp[4]); else if (1 == format_code) printf("world wide unique port id: %.*s\n", num, &ucp[4]); else { pr2serr(" [Unexpected format code: %d]\n", format_code); dStrHexErr((const char *)ucp, num + 4, 0); } bump = (((num + 4) < 24) ? 24 : num + 4); break; case TPROTO_SAS: ull = sg_get_unaligned_be64(ucp + 4); printf("%s SAS address: 0x%" PRIx64 "\n", leadin, ull); if (0 != format_code) printf("%s [Unexpected format code: %d]\n", leadin, format_code); bump = 24; break; case TPROTO_ADT: printf("%s ADT:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; case TPROTO_ATA: /* ATA/ATAPI */ printf("%s ATAPI:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; case TPROTO_UAS: printf("%s UAS:\n", leadin); printf("%s format code: %d\n", leadin, format_code); dStrHex((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; case TPROTO_SOP: printf("%s SOP ", leadin); num = sg_get_unaligned_be16(ucp + 2); if (0 == format_code) printf("Routing ID: 0x%x\n", num); else { pr2serr(" [Unexpected format code: %d]\n", format_code); dStrHexErr((const char *)ucp, 24, 0); } bump = 24; break; case TPROTO_NONE: pr2serr("%s No specified protocol\n", leadin); /* dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0); */ bump = 24; break; default: pr2serr("%s unknown protocol id=0x%x format_code=%d\n", leadin, proto_id, format_code); dStrHexErr((const char *)ucp, ((len > 24) ? 24 : len), 0); bump = 24; break; } } } /* VPD_EXT_INQ Extended Inquiry VPD */ static void decode_x_inq_vpd(unsigned char * b, int len, int do_hex, int do_long, int protect) { int n; if (len < 7) { pr2serr("Extended INQUIRY data VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1); return; } if (do_long) { n = (b[4] >> 6) & 0x3; printf(" ACTIVATE_MICROCODE=%d", n); if (1 == n) printf(" [before final WRITE BUFFER]\n"); else if (2 == n) printf(" [after power on or hard reset]\n"); else printf("\n"); n = (b[4] >> 3) & 0x7; printf(" SPT=%d", n); if (protect) { switch (n) { case 0: printf(" [protection type 1 supported]\n"); break; case 1: printf(" [protection types 1 and 2 supported]\n"); break; case 2: printf(" [protection type 2 supported]\n"); break; case 3: printf(" [protection types 1 and 3 supported]\n"); break; case 4: printf(" [protection type 3 supported]\n"); break; case 5: printf(" [protection types 2 and 3 supported]\n"); break; case 7: printf(" [protection types 1, 2 and 3 supported]\n"); break; default: printf("\n"); break; } } else printf("\n"); printf(" GRD_CHK=%d\n", !!(b[4] & 0x4)); printf(" APP_CHK=%d\n", !!(b[4] & 0x2)); printf(" REF_CHK=%d\n", !!(b[4] & 0x1)); printf(" UASK_SUP=%d\n", !!(b[5] & 0x20)); printf(" GROUP_SUP=%d\n", !!(b[5] & 0x10)); printf(" PRIOR_SUP=%d\n", !!(b[5] & 0x8)); printf(" HEADSUP=%d\n", !!(b[5] & 0x4)); printf(" ORDSUP=%d\n", !!(b[5] & 0x2)); printf(" SIMPSUP=%d\n", !!(b[5] & 0x1)); printf(" WU_SUP=%d\n", !!(b[6] & 0x8)); printf(" CRD_SUP=%d\n", !!(b[6] & 0x4)); printf(" NV_SUP=%d\n", !!(b[6] & 0x2)); printf(" V_SUP=%d\n", !!(b[6] & 0x1)); printf(" P_I_I_SUP=%d\n", !!(b[7] & 0x10)); printf(" LUICLR=%d\n", !!(b[7] & 0x1)); printf(" R_SUP=%d\n", !!(b[8] & 0x10)); printf(" CBCS=%d\n", !!(b[8] & 0x1)); printf(" Multi I_T nexus microcode download=%d\n", b[9] & 0xf); printf(" Extended self-test completion minutes=%d\n", sg_get_unaligned_be16(b + 10)); printf(" POA_SUP=%d\n", !!(b[12] & 0x80)); /* spc4r32 */ printf(" HRA_SUP=%d\n", !!(b[12] & 0x40)); /* spc4r32 */ printf(" VSA_SUP=%d\n", !!(b[12] & 0x20)); /* spc4r32 */ printf(" Maximum supported sense data length=%d\n", b[13]); /* spc4r34 */ return; } printf(" ACTIVATE_MICROCODE=%d SPT=%d GRD_CHK=%d APP_CHK=%d " "REF_CHK=%d\n", ((b[4] >> 6) & 0x3), ((b[4] >> 3) & 0x7), !!(b[4] & 0x4), !!(b[4] & 0x2), !!(b[4] & 0x1)); printf(" UASK_SUP=%d GROUP_SUP=%d PRIOR_SUP=%d HEADSUP=%d ORDSUP=%d " "SIMPSUP=%d\n", !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8), !!(b[5] & 0x4), !!(b[5] & 0x2), !!(b[5] & 0x1)); printf(" WU_SUP=%d CRD_SUP=%d NV_SUP=%d V_SUP=%d\n", !!(b[6] & 0x8), !!(b[6] & 0x4), !!(b[6] & 0x2), !!(b[6] & 0x1)); printf(" P_I_I_SUP=%d LUICLR=%d R_SUP=%d CBCS=%d\n", !!(b[7] & 0x10), !!(b[7] & 0x1), !!(b[8] & 0x10), !!(b[8] & 0x1)); printf(" Multi I_T nexus microcode download=%d\n", b[9] & 0xf); printf(" Extended self-test completion minutes=%d\n", sg_get_unaligned_be16(b + 10)); /* spc4r27 */ printf(" POA_SUP=%d HRA_SUP=%d VSA_SUP=%d\n", /* spc4r32 */ !!(b[12] & 0x80), !!(b[12] & 0x40), !!(b[12] & 0x20)); printf(" Maximum supported sense data length=%d\n", b[13]); /* spc4r34 */ } /* VPD_SOFTW_INF_ID */ static void decode_softw_inf_id(unsigned char * buff, int len, int do_hex) { if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } len -= 4; buff += 4; for ( ; len > 5; len -= 6, buff += 6) { printf(" IEEE Company_id: 0x%06x, vendor specific extension " "id: 0x%06x\n", sg_get_unaligned_be24(buff), sg_get_unaligned_be24(buff + 3)); } } /* VPD_ATA_INFO */ static void decode_ata_info_vpd(unsigned char * buff, int len, int do_long, int do_hex) { char b[80]; int num, is_be; const char * cp; const char * ata_transp; if (len < 36) { pr2serr("ATA information VPD page length too short=%d\n", len); return; } if (do_hex && (2 != do_hex)) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } memcpy(b, buff + 8, 8); b[8] = '\0'; printf(" SAT Vendor identification: %s\n", b); memcpy(b, buff + 16, 16); b[16] = '\0'; printf(" SAT Product identification: %s\n", b); memcpy(b, buff + 32, 4); b[4] = '\0'; printf(" SAT Product revision level: %s\n", b); if (len < 56) return; ata_transp = (0x34 == buff[36]) ? "SATA" : "PATA"; if (do_long) { printf(" Device signature [%s] (in hex):\n", ata_transp); dStrHex((const char *)buff + 36, 20, 0); } else printf(" Device signature indicates %s transport\n", ata_transp); if (len < 60) return; is_be = sg_is_big_endian(); if ((0xec == buff[56]) || (0xa1 == buff[56])) { cp = (0xa1 == buff[56]) ? "PACKET " : ""; printf(" ATA command IDENTIFY %sDEVICE response summary:\n", cp); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 27, 20, is_be, b); b[num] = '\0'; printf(" model: %s\n", b); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 10, 10, is_be, b); b[num] = '\0'; printf(" serial number: %s\n", b); num = sg_ata_get_chars((const unsigned short *)(buff + 60), 23, 4, is_be, b); b[num] = '\0'; printf(" firmware revision: %s\n", b); if (do_long) printf(" ATA command IDENTIFY %sDEVICE response in hex:\n", cp); } else if (do_long) printf(" ATA command 0x%x got following response:\n", (unsigned int)buff[56]); if (len < 572) return; if (2 == do_hex) dStrHex((const char *)(buff + 60), 512, 0); else if (do_long) dWordHex((const unsigned short *)(buff + 60), 256, 0, is_be); } /* VPD_POWER_CONDITION */ static void decode_power_condition(unsigned char * buff, int len, int do_hex) { if (len < 18) { pr2serr("Power condition VPD page length too short=%d\n", len); return; } if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } printf(" Standby_y=%d Standby_z=%d Idle_c=%d Idle_b=%d Idle_a=%d\n", !!(buff[4] & 0x2), !!(buff[4] & 0x1), !!(buff[5] & 0x4), !!(buff[5] & 0x2), !!(buff[5] & 0x1)); printf(" Stopped condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 6)); printf(" Standby_z condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 8)); printf(" Standby_y condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 10)); printf(" Idle_a condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 12)); printf(" Idle_b condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 14)); printf(" Idle_c condition recovery time (ms) %d\n", sg_get_unaligned_be16(buff + 16)); } static const char * power_unit_arr[] = { "Gigawatts", "Megawatts", "Kilowatts", "Watts", "Milliwatts", "Microwatts", "Unit reserved", "Unit reserved", }; /* VPD_POWER_CONSUMPTION */ static void decode_power_consumption_vpd(unsigned char * buff, int len, int do_hex) { int k, bump; unsigned char * ucp; unsigned int value; if ((1 == do_hex) || (do_hex > 2)) { dStrHex((const char *)buff, len, (1 == do_hex) ? 1 : -1); return; } if (len < 4) { pr2serr("Power consumption VPD page length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { bump = 4; if ((k + bump) > len) { pr2serr("Power consumption VPD page, short descriptor " "length=%d, left=%d\n", bump, (len - k)); return; } if (do_hex > 1) dStrHex((const char *)ucp, 4, 1); else { value = sg_get_unaligned_be16(ucp + 2); printf(" Power consumption identifier: 0x%x", ucp[0]); if (value >= 1000 && (ucp[1] & 0x7) > 0) printf(" Maximum power consumption: %d.%03d %s\n", value / 1000, value % 1000, power_unit_arr[(ucp[1] & 0x7) - 1]); else printf(" Maximum power consumption: %d %s\n", value, power_unit_arr[ucp[1] & 0x7]); } } } /* This is xcopy(LID4) related: "ROD" == Representation Of Data * Used by VPD_3PARTY_COPY */ static void decode_rod_descriptor(const unsigned char * buff, int len) { const unsigned char * ucp = buff; int k, bump; for (k = 0; k < len; k += bump, ucp += bump) { bump = sg_get_unaligned_be16(ucp + 2) + 4; switch (ucp[0]) { case 0: /* Block ROD device type specific descriptor */ printf(" Optimal block ROD length granularity: %d\n", sg_get_unaligned_be16(ucp + 6)); printf(" Maximum Bytes in block ROD: %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 8)); printf(" Optimal Bytes in block ROD transfer: %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 16)); printf(" Optimal Bytes to token per segment: %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 24)); printf(" Optimal Bytes from token per segment:" " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 32)); break; case 1: /* Stream ROD device type specific descriptor */ printf(" Maximum Bytes in stream ROD: %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 8)); printf(" Optimal Bytes in stream ROD transfer:" " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 16)); break; case 3: /* Copy manager ROD device type specific descriptor */ printf(" Maximum Bytes in processor ROD: %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 8)); printf(" Optimal Bytes in processor ROD transfer:" " %" PRIu64 "\n", sg_get_unaligned_be64(ucp + 16)); break; default: printf(" Unhandled descriptor (format %d, device type %d)\n", ucp[0] >> 5, ucp[0] & 0x1F); break; } } } struct tpc_desc_type { unsigned char code; const char * name; }; static struct tpc_desc_type tpc_desc_arr[] = { {0x0, "block -> stream"}, {0x1, "stream -> block"}, {0x2, "block -> block"}, {0x3, "stream -> stream"}, {0x4, "inline -> stream"}, {0x5, "embedded -> stream"}, {0x6, "stream -> discard"}, {0x7, "verify CSCD"}, {0x8, "block -> stream"}, {0x9, "stream -> block"}, {0xa, "block -> block"}, {0xb, "block -> stream & application_client"}, {0xc, "stream -> block & application_client"}, {0xd, "block -> block & application_client"}, {0xe, "stream -> stream&application_client"}, {0xf, "stream -> discard&application_client"}, {0x10, "filemark -> tape"}, {0x11, "space -> tape"}, {0x12, "locate -> tape"}, {0x13, "tape -> tape"}, {0x14, "register persistent reservation key"}, {0x15, "third party persistent reservation source I_T nexus"}, {0x16, "block -> block"}, {0xbe, "ROD <- block range(n)"}, {0xbf, "ROD <- block range(1)"}, {0xe0, "CSCD: FC N_Port_Name"}, {0xe1, "CSCD: FC N_Port_ID"}, {0xe2, "CSCD: FC N_Port_ID with N_Port_Name, checking"}, {0xe3, "CSCD: Parallel interface: I_T"}, {0xe4, "CSCD: Identification Descriptor"}, {0xe5, "CSCD: IPv4"}, {0xe6, "CSCD: Alias"}, {0xe7, "CSCD: RDMA"}, {0xe8, "CSCD: IEEE 1394 EUI-64"}, {0xe9, "CSCD: SAS SSP"}, {0xea, "CSCD: IPv6"}, {0xeb, "CSCD: IP copy service"}, {0xfe, "CSCD: ROD"}, {0xff, "CSCD: extension"}, {0x0, NULL}, }; static const char * get_tpc_desc_name(unsigned char code) { const struct tpc_desc_type * dtp; for (dtp = tpc_desc_arr; dtp->name; ++dtp) { if (code == dtp->code) return dtp->name; } return ""; } struct tpc_rod_type { uint32_t type; const char * name; }; static struct tpc_rod_type tpc_rod_arr[] = { {0x0, "copy manager internal"}, {0x10000, "access upon reference"}, {0x800000, "point in time copy - default"}, {0x800001, "point in time copy - change vulnerable"}, {0x800002, "point in time copy - persistent"}, {0x80ffff, "point in time copy - any"}, {0xffff0001, "block device zero"}, {0x0, NULL}, }; static const char * get_tpc_rod_name(uint32_t rod_type) { const struct tpc_rod_type * rtp; for (rtp = tpc_rod_arr; rtp->name; ++rtp) { if (rod_type == rtp->type) return rtp->name; } return ""; } /* VPD_3PARTY_COPY [3PC, third party copy] */ static void decode_3party_copy_vpd(unsigned char * buff, int len, int do_hex, int verbose) { int j, k, m, bump, desc_type, desc_len, sa_len; unsigned int u; const unsigned char * ucp; const char * cp; uint64_t ull; char b[80]; if (len < 4) { pr2serr("Third-party Copy VPD page length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { desc_type = sg_get_unaligned_be16(ucp); desc_len = sg_get_unaligned_be16(ucp + 2); if (verbose) printf("Descriptor type=%d, len %d\n", desc_type, desc_len); bump = 4 + desc_len; if ((k + bump) > len) { pr2serr("Third-party Copy VPD page, short descriptor length=%d, " "left=%d\n", bump, (len - k)); return; } if (0 == desc_len) continue; if (2 == do_hex) dStrHex((const char *)ucp + 4, desc_len, 1); else if (do_hex > 2) dStrHex((const char *)ucp, bump, 1); else { switch (desc_type) { case 0x0000: /* Required if POPULATE TOKEN (or friend) used */ printf(" Block Device ROD Token Limits:\n"); printf(" Maximum Range Descriptors: %d\n", sg_get_unaligned_be16(ucp + 10)); u = sg_get_unaligned_be32(ucp + 12); printf(" Maximum Inactivity Timeout: %u seconds\n", u); u = sg_get_unaligned_be32(ucp + 16); printf(" Default Inactivity Timeout: %u seconds\n", u); ull = sg_get_unaligned_be64(ucp + 20); printf(" Maximum Token Transfer Size: %" PRIu64 "\n", ull); ull = sg_get_unaligned_be64(ucp + 28); printf(" Optimal Transfer Count: %" PRIu64 "\n", ull); break; case 0x0001: /* Mandatory (SPC-4) */ printf(" Supported Commands:\n"); j = 0; while (j < ucp[4]) { sa_len = ucp[6 + j]; for (m = 0; m < sa_len; ++m) { sg_get_opcode_sa_name(ucp[5 + j], ucp[7 + j + m], 0, sizeof(b), b); printf(" %s\n", b); } j += sa_len + 2; } break; case 0x0004: printf(" Parameter Data:\n"); printf(" Maximum CSCD Descriptor Count: %d\n", sg_get_unaligned_be16(ucp + 8)); printf(" Maximum Segment Descriptor Count: %d\n", sg_get_unaligned_be16(ucp + 10)); u = sg_get_unaligned_be32(ucp + 12); printf(" Maximum Descriptor List Length: %u\n", u); u = sg_get_unaligned_be32(ucp + 16); printf(" Maximum Inline Data Length: %u\n", u); break; case 0x0008: printf(" Supported Descriptors:\n"); for (j = 0; j < ucp[4]; j++) { cp = get_tpc_desc_name(ucp[5 + j]); if (strlen(cp) > 0) printf(" %s [0x%x]\n", cp, ucp[5 + j]); else printf(" 0x%x\n", ucp[5 + j]); } break; case 0x000C: printf(" Supported CSCD IDs:\n"); for (j = 0; j < sg_get_unaligned_be16(ucp + 4); j += 2) { u = sg_get_unaligned_be16(ucp + 6 + j); printf(" 0x%04x\n", u); } break; case 0x0106: printf(" ROD Token Features:\n"); printf(" Remote Tokens: %d\n", ucp[4] & 0x0f); u = sg_get_unaligned_be32(ucp + 16); printf(" Minimum Token Lifetime: %u seconds\n", u); u = sg_get_unaligned_be32(ucp + 20); printf(" Maximum Token Lifetime: %u seconds\n", u); u = sg_get_unaligned_be32(ucp + 24); printf(" Maximum Token inactivity timeout: %d\n", u); decode_rod_descriptor(ucp + 48, sg_get_unaligned_be16(ucp + 46)); break; case 0x0108: printf(" Supported ROD Token and ROD Types:\n"); for (j = 0; j < sg_get_unaligned_be16(ucp + 6); j+= 64) { u = sg_get_unaligned_be32(ucp + 8 + j); cp = get_tpc_rod_name(u); if (strlen(cp) > 0) printf(" ROD Type: %s [0x%x]\n", cp, u); else printf(" ROD Type: 0x%x\n", u); printf(" Internal: %s\n", (ucp[8 + j + 4] & 0x80) ? "yes" : "no"); printf(" Token In: %s\n", (ucp[8 + j + 4] & 0x02) ? "yes" : "no"); printf(" Token Out: %s\n", (ucp[8 + j + 4] & 0x01) ? "yes" : "no"); printf(" Preference: %d\n", sg_get_unaligned_be16(ucp + 8 + j + 6)); } break; case 0x8001: /* Mandatory (SPC-4) */ printf(" General Copy Operations:\n"); u = sg_get_unaligned_be32(ucp + 4); printf(" Total Concurrent Copies: %u\n", u); u = sg_get_unaligned_be32(ucp + 8); printf(" Maximum Identified Concurrent Copies: %u\n", u); u = sg_get_unaligned_be32(ucp + 12); printf(" Maximum Segment Length: %u\n", u); ull = (1 << ucp[16]); /* field is power of 2 */ printf(" Data Segment Granularity: %" PRIu64 "\n", ull); ull = (1 << ucp[17]); printf(" Inline Data Granularity: %" PRIu64 "\n", ull); break; case 0x9101: printf(" Stream Copy Operations:\n"); u = sg_get_unaligned_be32(ucp + 4); printf(" Maximum Stream Device Transfer Size: %u\n", u); break; case 0xC001: printf(" Held Data:\n"); u = sg_get_unaligned_be32(ucp + 4); printf(" Held Data Limit: %u\n", u); ull = (1 << ucp[8]); printf(" Held Data Granularity: %" PRIu64 "\n", ull); break; default: pr2serr("Unexpected type=%d\n", desc_type); dStrHexErr((const char *)ucp, bump, 1); break; } } } } /* VPD_PROTO_LU */ static void decode_proto_lu_vpd(unsigned char * buff, int len, int do_hex) { int k, bump, rel_port, desc_len, proto; unsigned char * ucp; if (1 == do_hex) { dStrHex((const char *)buff, len, 0); return; } if (len < 4) { pr2serr("Protocol-specific logical unit information VPD page length " "too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { rel_port = sg_get_unaligned_be16(ucp); printf(" Relative port=%d\n", rel_port); proto = ucp[2] & 0xf; desc_len = sg_get_unaligned_be16(ucp + 6); bump = 8 + desc_len; if ((k + bump) > len) { pr2serr("Protocol-specific logical unit information VPD page, " "short descriptor length=%d, left=%d\n", bump, (len - k)); return; } if (0 == desc_len) continue; if (2 == do_hex) dStrHex((const char *)ucp + 8, desc_len, 1); else if (do_hex > 2) dStrHex((const char *)ucp, bump, 1); else { switch (proto) { case TPROTO_SAS: printf(" Protocol identifier: SAS\n"); printf(" TLR control supported: %d\n", !!(ucp[8] & 0x1)); break; default: pr2serr("Unexpected proto=%d\n", proto); dStrHexErr((const char *)ucp, bump, 1); break; } } } } /* VPD_PROTO_PORT */ static void decode_proto_port_vpd(unsigned char * buff, int len, int do_hex) { int k, j, bump, rel_port, desc_len, proto; unsigned char * ucp; unsigned char * pidp; if (1 == do_hex) { dStrHex((const char *)buff, len, 0); return; } if (len < 4) { pr2serr("Protocol-specific port information VPD page length too " "short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += bump, ucp += bump) { rel_port = sg_get_unaligned_be16(ucp); printf(" Relative port=%d\n", rel_port); proto = ucp[2] & 0xf; desc_len = sg_get_unaligned_be16(ucp + 6); bump = 8 + desc_len; if ((k + bump) > len) { pr2serr("Protocol-specific port VPD page, short descriptor " "length=%d, left=%d\n", bump, (len - k)); return; } if (0 == desc_len) continue; if (2 == do_hex) dStrHex((const char *)ucp + 8, desc_len, 1); else if (do_hex > 2) dStrHex((const char *)ucp, bump, 1); else { switch (proto) { case TPROTO_SAS: /* page added in spl3r02 */ printf(" power disable supported (pwr_d_s)=%d\n", !!(ucp[3] & 0x1)); /* added spl3r03 */ pidp = ucp + 8; for (j = 0; j < desc_len; j += 4, pidp += 4) printf(" phy id=%d, ssp persistent capable=%d\n", pidp[1], (0x1 & pidp[2])); break; default: pr2serr("Unexpected proto=%d\n", proto); dStrHexErr((const char *)ucp, bump, 1); break; } } } } /* VPD_BLOCK_LIMITS sbc */ /* VPD_SA_DEV_CAP ssc */ /* VPD_OSD_INFO osd */ static void decode_b0_vpd(unsigned char * buff, int len, int do_hex, int pdt) { unsigned int u; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 16) { pr2serr("Block limits VPD page length too short=%d\n", len); return; } printf(" Write same non-zero (WSNZ): %d\n", !!(buff[4] & 0x1)); printf(" Maximum compare and write length: %u blocks\n", buff[5]); u = sg_get_unaligned_be16(buff + 6); printf(" Optimal transfer length granularity: %u blocks\n", u); u = sg_get_unaligned_be32(buff + 8); printf(" Maximum transfer length: %u blocks\n", u); u = sg_get_unaligned_be32(buff + 12); printf(" Optimal transfer length: %u blocks\n", u); if (len > 19) { /* added in sbc3r09 */ u = sg_get_unaligned_be32(buff + 16); printf(" Maximum prefetch length: %u blocks\n", u); /* was 'Maximum prefetch transfer length' prior to sbc3r33 */ } if (len > 27) { /* added in sbc3r18 */ u = sg_get_unaligned_be32(buff + 20); printf(" Maximum unmap LBA count: %u\n", u); u = sg_get_unaligned_be32(buff + 24); printf(" Maximum unmap block descriptor count: %u\n", u); } if (len > 35) { /* added in sbc3r19 */ u = sg_get_unaligned_be32(buff + 28); printf(" Optimal unmap granularity: %u\n", u); printf(" Unmap granularity alignment valid: %u\n", !!(buff[32] & 0x80)); u = sg_get_unaligned_be32(buff + 32); printf(" Unmap granularity alignment: %u\n", u); /* added in sbc3r26 */ printf(" Maximum write same length: 0x%" PRIx64 " blocks\n", sg_get_unaligned_be64(buff + 36)); } if (len > 44) { /* added in sbc4r02 */ u = sg_get_unaligned_be32(buff + 44); printf(" Maximum atomic transfer length: %u\n", u); u = sg_get_unaligned_be32(buff + 48); printf(" Atomic alignment: %u\n", u); u = sg_get_unaligned_be32(buff + 52); printf(" Atomic transfer length granularity: %u\n", u); } break; case PDT_TAPE: case PDT_MCHANGER: printf(" WORM=%d\n", !!(buff[4] & 0x1)); break; case PDT_OSD: default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)buff, len, 0); break; } } static const char * product_type_arr[] = { "Not specified", "CFast", "CompactFlash", "MemoryStick", "MultiMediaCard", "Secure Digital Card (SD)", "XQD", "Universal Flash Storage Card (UFS)", }; /* VPD_BLOCK_DEV_CHARS sbc */ /* VPD_MAN_ASS_SN ssc */ /* VPD_SECURITY_TOKEN osd */ static void decode_b1_vpd(unsigned char * buff, int len, int do_hex, int pdt) { unsigned int u, k; if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 64) { pr2serr("Block device characteristics VPD page length too " "short=%d\n", len); return; } u = sg_get_unaligned_be16(buff + 4); if (0 == u) printf(" Medium rotation rate is not reported\n"); else if (1 == u) printf(" Non-rotating medium (e.g. solid state)\n"); else if ((u < 0x401) || (0xffff == u)) printf(" Reserved [0x%x]\n", u); else printf(" Nominal rotation rate: %d rpm\n", u); u = buff[6]; k = sizeof(product_type_arr) / sizeof(product_type_arr[0]); if (u < k) printf(" Product type: %s\n", product_type_arr[u]); else if (u < 0xf0) printf(" Product type: Reserved [0x%x]\n", u); else printf(" Product type: Vendor specific [0x%x]\n", u); printf(" WABEREQ=%d\n", (buff[7] >> 6) & 0x3); printf(" WACEREQ=%d\n", (buff[7] >> 4) & 0x3); u = buff[7] & 0xf; printf(" Nominal form factor"); switch (u) { case 0: printf(" not reported\n"); break; case 1: printf(": 5.25 inch\n"); break; case 2: printf(": 3.5 inch\n"); break; case 3: printf(": 2.5 inch\n"); break; case 4: printf(": 1.8 inch\n"); break; case 5: printf(": less then 1.8 inch\n"); break; default: printf(": reserved\n"); break; } printf(" HAW_ZBC=%d\n", !!(buff[8] & 0x10)); /* sbc4r01 */ printf(" FUAB=%d\n", !!(buff[8] & 0x2)); printf(" VBULS=%d\n", !!(buff[8] & 0x1)); break; case PDT_TAPE: case PDT_MCHANGER: case PDT_ADC: printf(" Manufacturer-assigned serial number: %.*s\n", len - 4, buff + 4); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)buff, len, 0); break; } } /* VPD_LB_PROVISIONING */ static int decode_block_lb_prov_vpd(unsigned char * b, int len) { int dp; if (len < 4) { pr2serr("Logical block provisioning page too short=%d\n", len); return SG_LIB_CAT_MALFORMED; } printf(" Unmap command supported (LBPU): %d\n", !!(0x80 & b[5])); printf(" Write same (16) with unmap bit supported (LBWS): %d\n", !!(0x40 & b[5])); printf(" Write same (10) with unmap bit supported (LBWS10): %d\n", !!(0x20 & b[5])); printf(" Logical block provisioning read zeros (LBPRZ): %d\n", !!(0x4 & b[5])); printf(" Anchored LBAs supported (ANC_SUP): %d\n", !!(0x2 & b[5])); dp = !!(b[5] & 0x1); printf(" Threshold exponent: %d\n", b[4]); printf(" Descriptor present (DP): %d\n", dp); printf(" Provisioning type: %d\n", b[6] & 0x7); if (dp) { const unsigned char * ucp; int i_len, p_id, c_set, piv, assoc, desig_type; ucp = b + 8; i_len = ucp[3]; if (0 == i_len) { pr2serr("Logical block provisioning page provisioning group " "descriptor too short=%d\n", i_len); return 0; } printf(" Provisioning group descriptor\n"); p_id = ((ucp[0] >> 4) & 0xf); c_set = (ucp[0] & 0xf); piv = ((ucp[1] & 0x80) ? 1 : 0); assoc = ((ucp[1] >> 4) & 0x3); desig_type = (ucp[1] & 0xf); decode_designation_descriptor(ucp, i_len, p_id, c_set, piv, assoc, desig_type, 0, 1); } return 0; } /* VPD_SUP_BLOCK_LENS 0xb4 */ static void decode_sup_block_lens_vpd(unsigned char * buff, int len) { int k; unsigned int u; unsigned char * ucp; if (len < 4) { pr2serr("Supported block lengths and protection types VPD page " "length too short=%d\n", len); return; } len -= 4; ucp = buff + 4; for (k = 0; k < len; k += 8, ucp += 8) { u = sg_get_unaligned_be32(ucp); printf(" Logical block length: %u\n", u); printf(" P_I_I_SUP: %d\n", !!(ucp[4] & 0x40)); printf(" GRD_CHK: %d\n", !!(ucp[4] & 0x4)); printf(" APP_CHK: %d\n", !!(ucp[4] & 0x2)); printf(" REF_CHK: %d\n", !!(ucp[4] & 0x1)); printf(" T3PS_SUP: %d\n", !!(ucp[5] & 0x8)); printf(" T2PS_SUP: %d\n", !!(ucp[5] & 0x4)); printf(" T1PS_SUP: %d\n", !!(ucp[5] & 0x2)); printf(" T0PS_SUP: %d\n", !!(ucp[5] & 0x1)); } } /* VPD_BLOCK_DEV_C_EXTENS 0xb5 */ static void decode_block_dev_char_ext_vpd(unsigned char * b, int len) { if (len < 16) { pr2serr("Block device characteristics extension VPD page " "length too short=%d\n", len); return; } printf(" Utilization type: "); switch (b[5]) { case 1: printf("Combined writes and reads"); break; case 2: printf("Writes only"); break; case 3: printf("Separate writes and reads"); break; default: printf("Reserved"); break; } printf(" [0x%x]\n", b[5]); printf(" Utilization units: "); switch (b[6]) { case 2: printf("megabytes"); break; case 3: printf("gigabytes"); break; case 4: printf("terabytes"); break; case 5: printf("petabytes"); break; case 6: printf("exabytes"); break; default: printf("Reserved"); break; } printf(" [0x%x]\n", b[6]); printf(" Utilization interval: "); switch (b[7]) { case 0xa: printf("per day"); break; case 0xe: printf("per year"); break; default: printf("Reserved"); break; } printf(" [0x%x]\n", b[7]); printf(" Utilization B: %u\n", sg_get_unaligned_be32(b + 8)); printf(" Utilization A: %u\n", sg_get_unaligned_be32(b + 12)); } /* VPD_TA_SUPPORTED */ static int decode_tapealert_supported_vpd(unsigned char * b, int len) { if (len < 12) { pr2serr("TapeAlert supported flags length too short=%d\n", len); return SG_LIB_CAT_MALFORMED; } printf(" Flag01h: %d 02h: %d 03h: %d 04h: %d 05h: %d 06h: %d " "07h: %d 08h: %d\n", !!(b[4] & 0x80), !!(b[4] & 0x40), !!(b[4] & 0x20), !!(b[4] & 0x10), !!(b[4] & 0x8), !!(b[4] & 0x4), !!(b[4] & 0x2), !!(b[4] & 0x1)); printf(" Flag09h: %d 0ah: %d 0bh: %d 0ch: %d 0dh: %d 0eh: %d " "0fh: %d 10h: %d\n", !!(b[5] & 0x80), !!(b[5] & 0x40), !!(b[5] & 0x20), !!(b[5] & 0x10), !!(b[5] & 0x8), !!(b[5] & 0x4), !!(b[5] & 0x2), !!(b[5] & 0x1)); printf(" Flag11h: %d 12h: %d 13h: %d 14h: %d 15h: %d 16h: %d " "17h: %d 18h: %d\n", !!(b[6] & 0x80), !!(b[6] & 0x40), !!(b[6] & 0x20), !!(b[6] & 0x10), !!(b[6] & 0x8), !!(b[6] & 0x4), !!(b[6] & 0x2), !!(b[6] & 0x1)); printf(" Flag19h: %d 1ah: %d 1bh: %d 1ch: %d 1dh: %d 1eh: %d " "1fh: %d 20h: %d\n", !!(b[7] & 0x80), !!(b[7] & 0x40), !!(b[7] & 0x20), !!(b[7] & 0x10), !!(b[7] & 0x8), !!(b[7] & 0x4), !!(b[7] & 0x2), !!(b[7] & 0x1)); printf(" Flag21h: %d 22h: %d 23h: %d 24h: %d 25h: %d 26h: %d " "27h: %d 28h: %d\n", !!(b[8] & 0x80), !!(b[8] & 0x40), !!(b[8] & 0x20), !!(b[8] & 0x10), !!(b[8] & 0x8), !!(b[8] & 0x4), !!(b[8] & 0x2), !!(b[8] & 0x1)); printf(" Flag29h: %d 2ah: %d 2bh: %d 2ch: %d 2dh: %d 2eh: %d " "2fh: %d 30h: %d\n", !!(b[9] & 0x80), !!(b[9] & 0x40), !!(b[9] & 0x20), !!(b[9] & 0x10), !!(b[9] & 0x8), !!(b[9] & 0x4), !!(b[9] & 0x2), !!(b[9] & 0x1)); printf(" Flag31h: %d 32h: %d 33h: %d 34h: %d 35h: %d 36h: %d " "37h: %d 38h: %d\n", !!(b[10] & 0x80), !!(b[10] & 0x40), !!(b[10] & 0x20), !!(b[10] & 0x10), !!(b[10] & 0x8), !!(b[10] & 0x4), !!(b[10] & 0x2), !!(b[10] & 0x1)); printf(" Flag39h: %d 3ah: %d 3bh: %d 3ch: %d 3dh: %d 3eh: %d " "3fh: %d 40h: %d\n", !!(b[11] & 0x80), !!(b[11] & 0x40), !!(b[11] & 0x20), !!(b[11] & 0x10), !!(b[11] & 0x8), !!(b[11] & 0x4), !!(b[11] & 0x2), !!(b[11] & 0x1)); return 0; } /* VPD_LB_PROVISIONING sbc */ /* VPD_TA_SUPPORTED ssc */ static void decode_b2_vpd(unsigned char * buff, int len, int do_hex, int pdt) { if (do_hex) { dStrHex((const char *)buff, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: decode_block_lb_prov_vpd(buff, len); break; case PDT_TAPE: case PDT_MCHANGER: decode_tapealert_supported_vpd(buff, len); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)buff, len, 0); break; } } /* VPD_REFERRALS sbc */ /* VPD_AUTOMATION_DEV_SN ssc */ static void decode_b3_vpd(unsigned char * b, int len, int do_hex, int pdt) { char obuff[DEF_ALLOC_LEN]; unsigned int u; if (do_hex) { dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: if (len < 16) { pr2serr("Referrals VPD page length too short=%d\n", len); break; } u = sg_get_unaligned_be32(b + 8); printf(" User data segment size: %u\n", u); u = sg_get_unaligned_be32(b + 12); printf(" User data segment multiplier: %u\n", u); break; case PDT_TAPE: case PDT_MCHANGER: memset(obuff, 0, sizeof(obuff)); len -= 4; if (len >= (int)sizeof(obuff)) len = sizeof(obuff) - 1; memcpy(obuff, b + 4, len); printf(" Automation device serial number: %s\n", obuff); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)b, len, 0); break; } } /* VPD_SUP_BLOCK_LENS sbc */ /* VPD_DTDE_ADDRESS ssc */ static void decode_b4_vpd(unsigned char * b, int len, int do_hex, int pdt) { int k; if (do_hex) { dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: decode_sup_block_lens_vpd(b, len); break; case PDT_TAPE: case PDT_MCHANGER: printf(" Data transfer device element address: 0x"); for (k = 4; k < len; ++k) printf("%02x", (unsigned int)b[k]); printf("\n"); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)b, len, 0); break; } } /* VPD_BLOCK_DEV_C_EXTENS sbc */ static void decode_b5_vpd(unsigned char * b, int len, int do_hex, int pdt) { if (do_hex) { dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1); return; } switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: decode_block_dev_char_ext_vpd(b, len); break; default: pr2serr(" Unable to decode pdt=0x%x, in hex:\n", pdt); dStrHexErr((const char *)b, len, 0); break; } } /* VPD_ZBC_DEV_CHARS sbc or zbc */ static void decode_zbdc_vpd(unsigned char * b, int len, int do_hex) { uint32_t u; if (do_hex) { dStrHex((const char *)b, len, (1 == do_hex) ? 0 : -1); return; } if (len < 64) { pr2serr("Zoned block device characteristics VPD page length too " "short=%d\n", len); return; } printf(" URSWRZ type: %d\n", !!(b[4] & 0x1)); u = sg_get_unaligned_be32(b + 8); printf(" Optimal number of open sequential write preferred zones: "); if (0xffffffff == u) printf("0xffffffff\n"); else printf("%" PRIu32 "\n", u); u = sg_get_unaligned_be32(b + 12); printf(" Optimal number of non-sequentially written sequential write " "preferred zones: "); if (0xffffffff == u) printf("0xffffffff\n"); else printf("%" PRIu32 "\n", u); u = sg_get_unaligned_be32(b + 16); printf(" Maximum number of open sequential write required: "); if (0xffffffff == u) printf("0xffffffff\n"); else printf("%" PRIu32 "\n", u); } /* Returns 0 if successful */ static int svpd_unable_to_decode(int sg_fd, struct opts_t * op, int subvalue, int off) { int len, res; int alloc_len = op->maxlen; unsigned char * rp; rp = rsp_buff + off; if ((! op->do_hex) && (! op->do_raw)) printf("Only hex output supported\n"); if ((!op->do_raw) && (op->do_hex < 2)) { if (subvalue) printf("VPD page code=0x%.2x, subvalue=0x%.2x:\n", op->num_vpd, subvalue); else if (op->num_vpd >= 0) printf("VPD page code=0x%.2x:\n", op->num_vpd); else printf("VPD page code=%d:\n", op->num_vpd); } if (sg_fd >= 0) { if (0 == alloc_len) alloc_len = DEF_ALLOC_LEN; } res = vpd_fetch_page_from_dev(sg_fd, rp, op->num_vpd, alloc_len, op->verbose, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { if (op->do_hex > 1) dStrHex((const char *)rp, len, -1); else if (VPD_ASCII_OP_DEF == op->num_vpd) dStrHex((const char *)rp, len, 0); else dStrHex((const char *)rp, len, (op->do_long ? 0 : 1)); } return 0; } else { if (op->num_vpd >= 0) pr2serr("fetching VPD page code=0x%.2x: failed\n", op->num_vpd); else pr2serr("fetching VPD page code=%d: failed\n", op->num_vpd); return res; } } /* Returns 0 if successful, else see sg_ll_inquiry() */ static int svpd_decode_t10(int sg_fd, struct opts_t * op, int subvalue, int off) { int len, pdt, num, k, resid, alloc_len, pn, vb, allow_name, long_notquiet; int res = 0; char b[48]; const struct svpd_values_name_t * vnp; char obuff[DEF_ALLOC_LEN]; unsigned char * rp; pn = op->num_vpd; vb = op->verbose; long_notquiet = op->do_long && (! op->do_quiet); if (op->do_raw || (op->do_quiet && (! op->do_long) && (! op->do_all)) || (op->do_hex >= 3)) allow_name = 0; else allow_name = 1; rp = rsp_buff + off; switch(pn) { case VPD_NO_RATHER_STD_INQ: /* -2 (want standard inquiry response) */ if (sg_fd >= 0) { if (op->maxlen > 0) alloc_len = op->maxlen; else if (op->do_long) alloc_len = DEF_ALLOC_LEN; else alloc_len = 36; res = pt_inquiry(sg_fd, 0, 0, rp, alloc_len, &resid, 1, vb); } else { alloc_len = op->maxlen; resid = 0; res = 0; } if (0 == res) { alloc_len -= resid; if (op->do_raw) dStrRaw((const char *)rp, alloc_len); else if (op->do_hex) { if (! op->do_quiet && (op->do_hex < 3)) printf("Standard Inquiry reponse:\n"); dStrHex((const char *)rp, alloc_len, (1 == op->do_hex) ? 0 : -1); } else decode_std_inq(rp, alloc_len, vb); return 0; } break; case VPD_SUPPORTED_VPDS: /* 0x0 */ if (allow_name) printf("Supported VPD pages VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); num = rp[3]; if (num > (len - 4)) num = (len - 4); for (k = 0; k < num; ++k) { pn = rp[4 + k]; vnp = sdp_get_vpd_detail(pn, -1, pdt); if (vnp) { if (op->do_long) printf(" 0x%02x %s [%s]\n", pn, vnp->name, vnp->acron); else printf(" %s [%s]\n", vnp->name, vnp->acron); } else if (op->vend_prod_num >= 0) { vnp = svpd_find_vendor_by_num(pn, op->vend_prod_num); if (vnp) { if (op->do_long) printf(" 0x%02x %s [%s]\n", pn, vnp->name, vnp->acron); else printf(" %s [%s]\n", vnp->name, vnp->acron); } else printf(" 0x%x\n", pn); } else printf(" 0x%x\n", pn); } } return 0; } break; case VPD_UNIT_SERIAL_NUM: /* 0x80 */ if (allow_name) printf("Unit serial number VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); memset(obuff, 0, sizeof(obuff)); len -= 4; if (len >= (int)sizeof(obuff)) len = sizeof(obuff) - 1; memcpy(obuff, rp + 4, len); printf(" Unit serial number: %s\n", obuff); } return 0; } break; case VPD_DEVICE_ID: /* 0x83 */ if (allow_name) printf("Device Identification VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else if (op->do_hex) dStrHex((const char *)rp, len, (1 == op->do_hex) ? 0 : -1); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_id_vpd(rp, len, subvalue, op->do_long, op->do_quiet); } return 0; } break; case VPD_SOFTW_INF_ID: /* 0x84 */ if (allow_name) printf("Software interface identification VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_softw_inf_id(rp, len, op->do_hex); } return 0; } break; case VPD_MAN_NET_ADDR: /* 0x85 */ if (allow_name) printf("Management network addresses VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else decode_net_man_vpd(rp, len, op->do_hex); return 0; } break; case VPD_EXT_INQ: /* 0x86 */ if (allow_name) printf("extended INQUIRY data VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { int protect = 0; struct sg_simple_inquiry_resp sir; if ((sg_fd >= 0) && long_notquiet) { res = sg_simple_inquiry(sg_fd, &sir, 0, vb); if (res) { if (op->verbose) pr2serr("%s: sg_simple_inquiry() failed, " "res=%d\n", __func__, res); } else protect = sir.byte_5 & 0x1; /* SPC-3 and later */ } pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_x_inq_vpd(rp, len, op->do_hex, long_notquiet, protect); } return 0; } break; case VPD_MODE_PG_POLICY: /* 0x87 */ if (allow_name) printf("Mode page policy VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_mode_policy_vpd(rp, len, op->do_hex); } return 0; } break; case VPD_SCSI_PORTS: /* 0x88 */ if (allow_name) printf("SCSI Ports VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_scsi_ports_vpd(rp, len, op->do_hex, op->do_long, op->do_quiet); } return 0; } break; case VPD_ATA_INFO: /* 0x89 */ if (allow_name) printf("ATA information VPD page:\n"); alloc_len = op->maxlen ? op->maxlen : VPD_ATA_INFO_LEN; res = vpd_fetch_page_from_dev(sg_fd, rp, pn, alloc_len, vb, &len); if (0 == res) { if ((2 == op->do_raw) || (3 == op->do_hex)) { /* for hdparm */ if (len < (60 + 512)) pr2serr("ATA_INFO VPD page len (%d) less than expected " "572\n", len); else dWordHex((const unsigned short *)(rp + 60), 256, -2, sg_is_big_endian()); } else if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_ata_info_vpd(rp, len, long_notquiet, op->do_hex); } return 0; } break; case VPD_POWER_CONDITION: /* 0x8a */ if (allow_name) printf("Power condition VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_power_condition(rp, len, op->do_hex); } return 0; } break; case VPD_POWER_CONSUMPTION: /* 0x8d */ if (allow_name) printf("Power consumption VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_power_consumption_vpd(rp, len, op->do_hex); } return 0; } break; case VPD_3PARTY_COPY: /* 0x8f */ if (allow_name) printf("Third party copy VPD page:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else if (1 == op->do_hex) dStrHex((const char *)rp, len, 0); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_3party_copy_vpd(rp, len, op->do_hex, vb); } return 0; } break; case VPD_PROTO_LU: /* 0x90 */ if (allow_name) printf("Protocol-specific logical unit information:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rsp_buff[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_proto_lu_vpd(rp, len, op->do_hex); } return 0; } break; case VPD_PROTO_PORT: /* 0x91 */ if (allow_name) printf("Protocol-specific port information:\n"); res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_proto_port_vpd(rp, len, op->do_hex); } return 0; } break; case 0xb0: /* depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Block limits VPD page (SBC):\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("Sequential access device capabilities VPD page " "(SSC):\n"); break; case PDT_OSD: printf("OSD information VPD page (OSD):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { pdt = rp[0] & 0x1f; if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b0_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb0\n"); break; case 0xb1: /* depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Block device characteristics VPD page (SBC):\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("Manufactured assigned serial number VPD page " "(SSC):\n"); break; case PDT_OSD: printf("Security token VPD page (OSD):\n"); break; case PDT_ADC: printf("Manufactured assigned serial number VPD page " "(ADC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b1_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb1\n"); break; case 0xb2: /* VPD page depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Logical block provisioning VPD page (SBC):\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("TapeAlert supported flags VPD page (SSC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b2_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb2\n"); break; case 0xb3: /* VPD page depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Referrals VPD page (SBC):\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("Automation device serial number VPD page " "(SSC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b3_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb3\n"); break; case 0xb4: /* VPD page depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Supported block lengths and protection types " "VPD page (SBC):\n"); break; case PDT_TAPE: case PDT_MCHANGER: printf("Data transfer device element address (SSC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b4_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb4\n"); break; case 0xb5: /* VPD page depends on pdt */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Block device characteristics extension VPD page " "(SBC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_b5_vpd(rp, len, op->do_hex, pdt); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb5\n"); break; case VPD_ZBC_DEV_CHARS: /* 0xb6 for both pdt=0 and pdt=0x14 */ res = vpd_fetch_page_from_dev(sg_fd, rp, pn, op->maxlen, vb, &len); if (0 == res) { pdt = rp[0] & 0x1f; if (allow_name) { switch (pdt) { case PDT_DISK: case PDT_WO: case PDT_OPTICAL: case PDT_ZBC: printf("Zoned block device characteristics VPD page " "(SBC, ZBC):\n"); break; default: printf("VPD page=0x%x, pdt=0x%x:\n", pn, pdt); break; } } if (op->do_raw) dStrRaw((const char *)rp, len); else { if (vb || long_notquiet) printf(" [PQual=%d Peripheral device type: %s]\n", (rp[0] & 0xe0) >> 5, sg_get_pdt_str(pdt, sizeof(b), b)); decode_zbdc_vpd(rp, len, op->do_hex); } return 0; } else if ((! op->do_raw) && (! op->do_quiet) && (op->do_hex < 3)) printf("VPD page=0xb5\n"); break; default: return SG_LIB_SYNTAX_ERROR; } return res; } static int svpd_decode_all(int sg_fd, struct opts_t * op) { int k, res, rlen, n, pn; int max_pn = 255; int any_err = 0; unsigned char vpd0_buff[512]; unsigned char * rp = vpd0_buff; if (op->num_vpd > 0) max_pn = op->num_vpd; if (sg_fd >= 0) { res = vpd_fetch_page_from_dev(sg_fd, rp, VPD_SUPPORTED_VPDS, op->maxlen, op->verbose, &rlen); if (res) { if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("%s: VPD page 0, aborted command\n", __func__); else if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("%s: fetching VPD page 0 failed: %s\n", __func__, b); } return res; } n = (rp[2] >> 8) + rp[3]; if (n > (rlen - 4)) { if (op->verbose) pr2serr("%s: rlen=%d > page0 size=%d\n", __func__, rlen, n + 4); n = (rlen - 4); } for (k = 0; k < n; ++k) { pn = rp[4 + k]; if (pn > max_pn) continue; op->num_vpd = pn; if (op->do_long) printf("[0x%x] ", pn); res = svpd_decode_t10(sg_fd, op, 0, 0); if (SG_LIB_SYNTAX_ERROR == res) { res = svpd_decode_vendor(sg_fd, op, 0); if (SG_LIB_SYNTAX_ERROR == res) res = svpd_unable_to_decode(sg_fd, op, 0, 0); } if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("fetching VPD page failed, aborted command\n"); else if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("fetching VPD page failed: %s\n", b); } if (res) any_err = res; } res = any_err; } else { /* input is coming from --inhex=FN */ int bump, off; int in_len = op->maxlen; int prev_pn = -1; rp = rsp_buff; for (k = 0, off = 0; off < in_len; ++k, off += bump) { rp = rsp_buff + off; pn = rp[1]; bump = sg_get_unaligned_be16(rp + 2) + 4; if ((off + bump) > in_len) { pr2serr("%s: page 0x%x size (%d) exceeds buffer\n", __func__, pn, bump); bump = in_len - off; } if (pn <= prev_pn) { pr2serr("%s: prev_pn=0x%x, this pn=0x%x, not ascending so " "exit\n", __func__, prev_pn, pn); break; } prev_pn = pn; op->num_vpd = pn; if (pn > max_pn) { if (op->verbose > 2) pr2serr("%s: skipping as this pn=0x%x exceeds " "max_pn=0x%x\n", __func__, pn, max_pn); continue; } if (op->do_long) printf("[0x%x] ", pn); res = svpd_decode_t10(-1, op, 0, off); if (SG_LIB_SYNTAX_ERROR == res) { res = svpd_decode_vendor(-1, op, off); if (SG_LIB_SYNTAX_ERROR == res) res = svpd_unable_to_decode(-1, op, 0, off); } } } return 0; } int main(int argc, char * argv[]) { int sg_fd, c, res, matches; const struct svpd_values_name_t * vnp; const char * cp; int inhex_len = 0; int ret = 0; int subvalue = 0; int page_pdt = -1; struct opts_t opts; struct opts_t * op; op = &opts; memset(&opts, 0, sizeof(opts)); op->vend_prod_num = -1; while (1) { int option_index = 0; c = getopt_long(argc, argv, "aehHiI:lm:M:p:qrvV", long_options, &option_index); if (c == -1) break; switch (c) { case 'a': ++op->do_all; break; case 'e': ++op->do_enum; break; case 'h': case '?': usage(); return 0; case 'H': ++op->do_hex; break; case 'i': ++op->do_ident; break; case 'I': if (op->inhex_fn) { pr2serr("only one '--inhex=' option permitted\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else op->inhex_fn = optarg; break; case 'l': ++op->do_long; break; case 'm': op->maxlen = sg_get_num(optarg); if ((op->maxlen < 0) || (op->maxlen > MX_ALLOC_LEN)) { pr2serr("argument to '--maxlen' should be %d or less\n", MX_ALLOC_LEN); return SG_LIB_SYNTAX_ERROR; } break; case 'M': if (op->vend_prod) { pr2serr("only one '--vendor=' option permitted\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else op->vend_prod = optarg; break; case 'p': if (op->page_str) { pr2serr("only one '--page=' option permitted\n"); usage(); return SG_LIB_SYNTAX_ERROR; } else op->page_str = optarg; break; case 'q': ++op->do_quiet; break; case 'r': ++op->do_raw; break; case 'v': ++op->verbose; break; case 'V': pr2serr("version: %s\n", version_str); return 0; default: pr2serr("unrecognised option code 0x%x ??\n", c); usage(); return SG_LIB_SYNTAX_ERROR; } } if (optind < argc) { if (NULL == op->device_name) { op->device_name = argv[optind]; ++optind; } if (optind < argc) { for (; optind < argc; ++optind) pr2serr("Unexpected extra argument: %s\n", argv[optind]); usage(); return SG_LIB_SYNTAX_ERROR; } } if (op->do_enum) { if (op->device_name) pr2serr("Device name %s ignored when --enumerate given\n", op->device_name); if (op->vend_prod) { if (isdigit(op->vend_prod[0])) { op->vend_prod_num = sg_get_num_nomult(op->vend_prod); if ((op->vend_prod_num < 0) || (op->vend_prod_num > 10)) { pr2serr("Bad vendor/product number after '--vendor=' " "option\n"); return SG_LIB_SYNTAX_ERROR; } } else { op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod); if (op->vend_prod_num < 0) { pr2serr("Bad vendor/product acronym after '--vendor=' " "option\n"); return SG_LIB_SYNTAX_ERROR; } } svpd_enumerate_vendor(op->vend_prod_num); return 0; } if (op->page_str) { if ((0 == strcmp("-1", op->page_str)) || (0 == strcmp("-2", op->page_str))) op->num_vpd = VPD_NO_RATHER_STD_INQ; else if (isdigit(op->page_str[0])) { op->num_vpd = sg_get_num_nomult(op->page_str); if ((op->num_vpd < 0) || (op->num_vpd > 255)) { pr2serr("Bad page code value after '-p' option\n"); return SG_LIB_SYNTAX_ERROR; } } else { pr2serr("with --enumerate only search using VPD page " "numbers\n"); return SG_LIB_SYNTAX_ERROR; } matches = count_standard_vpds(op->num_vpd); if (0 == matches) matches = svpd_count_vendor_vpds(op->num_vpd, op->vend_prod_num); if (0 == matches) printf("No matches found for VPD page number 0x%x\n", op->num_vpd); } else { /* enumerate standard then vendor VPD pages */ printf("Standard VPD pages:\n"); enumerate_vpds(1, 1); } return 0; } if (op->page_str) { if ((0 == strcmp("-1", op->page_str)) || (0 == strcmp("-2", op->page_str))) op->num_vpd = VPD_NO_RATHER_STD_INQ; else if (isalpha(op->page_str[0])) { vnp = sdp_find_vpd_by_acron(op->page_str); if (NULL == vnp) { vnp = svpd_find_vendor_by_acron(op->page_str); if (NULL == vnp) { pr2serr("abbreviation doesn't match a VPD page\n"); printf("Available standard VPD pages:\n"); enumerate_vpds(1, 1); return SG_LIB_SYNTAX_ERROR; } } op->num_vpd = vnp->value; subvalue = vnp->subvalue; op->vend_prod_num = subvalue; page_pdt = vnp->pdt; } else { cp = strchr(op->page_str, ','); if (cp && op->vend_prod) { pr2serr("the --page=pg,vp and the --vendor=vp forms overlap, " "choose one or the other\n"); return SG_LIB_SYNTAX_ERROR; } op->num_vpd = sg_get_num_nomult(op->page_str); if ((op->num_vpd < 0) || (op->num_vpd > 255)) { pr2serr("Bad page code value after '-p' option\n"); printf("Available standard VPD pages:\n"); enumerate_vpds(1, 1); return SG_LIB_SYNTAX_ERROR; } if (cp) { if (isdigit(*(cp + 1))) op->vend_prod_num = sg_get_num_nomult(cp + 1); else op->vend_prod_num = svpd_find_vp_num_by_acron(cp + 1); if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) { pr2serr("Bad vendor/product acronym after comma in '-p' " "option\n"); if (op->vend_prod_num < 0) svpd_enumerate_vendor(-1); return SG_LIB_SYNTAX_ERROR; } subvalue = op->vend_prod_num; } else if (op->vend_prod) { if (isdigit(op->vend_prod[0])) op->vend_prod_num = sg_get_num_nomult(op->vend_prod); else op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod); if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) { pr2serr("Bad vendor/product acronym after '--vendor=' " "option\n"); svpd_enumerate_vendor(-1); return SG_LIB_SYNTAX_ERROR; } subvalue = op->vend_prod_num; } } } else if (op->vend_prod) { if (isdigit(op->vend_prod[0])) op->vend_prod_num = sg_get_num_nomult(op->vend_prod); else op->vend_prod_num = svpd_find_vp_num_by_acron(op->vend_prod); if ((op->vend_prod_num < 0) || (op->vend_prod_num > 255)) { pr2serr("Bad vendor/product acronym after '--vendor=' " "option\n"); svpd_enumerate_vendor(-1); return SG_LIB_SYNTAX_ERROR; } subvalue = op->vend_prod_num; } if (op->inhex_fn) { if (op->device_name) { pr2serr("Cannot have both a DEVICE and --inhex= option\n"); return SG_LIB_SYNTAX_ERROR; } if (f2hex_arr(op->inhex_fn, op->do_raw, 0, rsp_buff, &inhex_len, sizeof(rsp_buff))) return SG_LIB_FILE_ERROR; op->do_raw = 0; /* don't want raw on output with --inhex= */ if ((NULL == op->page_str) && (0 == op->do_all)) { /* may be able to deduce VPD page */ if ((0x2 == (0xf & rsp_buff[3])) && (rsp_buff[2] > 2)) { if (op->verbose) pr2serr("Guessing from --inhex= this is a standard " "INQUIRY\n"); if (page_pdt < 0) page_pdt = 0x1f & rsp_buff[0]; } else if (rsp_buff[2] <= 2) { if (op->verbose) pr2serr("Guessing from --inhex this is VPD page 0x%x\n", rsp_buff[1]); op->num_vpd = rsp_buff[1]; if (page_pdt < 0) page_pdt = 0x1f & rsp_buff[0]; } else { if (op->num_vpd > 0x80) { op->num_vpd = rsp_buff[1]; if (page_pdt < 0) page_pdt = 0x1f & rsp_buff[0]; if (op->verbose) pr2serr("Guessing from --inhex this is VPD page " "0x%x\n", rsp_buff[1]); } else { op->num_vpd = VPD_NO_RATHER_STD_INQ; if (op->verbose) pr2serr("page number unclear from --inhex, hope " "it's a standard INQUIRY response\n"); } } } } else if (NULL == op->device_name) { pr2serr("No DEVICE argument given\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (op->do_raw && op->do_hex) { pr2serr("Can't do hex and raw at the same time\n"); usage(); return SG_LIB_SYNTAX_ERROR; } if (op->do_ident) { op->num_vpd = VPD_DEVICE_ID; if (op->do_ident > 1) { if (0 == op->do_long) ++op->do_quiet; subvalue = VPD_DI_SEL_LU; } } if (op->do_raw) { if (sg_set_binary_mode(STDOUT_FILENO) < 0) { perror("sg_set_binary_mode"); return SG_LIB_FILE_ERROR; } } if (op->inhex_fn) { if ((0 == op->maxlen) || (inhex_len < op->maxlen)) op->maxlen = inhex_len; if (op->do_all) res = svpd_decode_all(-1, op); else { res = svpd_decode_t10(-1, op, subvalue, 0); if (SG_LIB_SYNTAX_ERROR == res) { res = svpd_decode_vendor(-1, op, 0); if (SG_LIB_SYNTAX_ERROR == res) res = svpd_unable_to_decode(-1, op, subvalue, 0); } } return res; } if ((sg_fd = sg_cmds_open_device(op->device_name, 1 /* ro */, op->verbose)) < 0) { pr2serr("error opening file: %s: %s\n", op->device_name, safe_strerror(-sg_fd)); return SG_LIB_FILE_ERROR; } if (op->do_all) ret = svpd_decode_all(sg_fd, op); else { memset(rsp_buff, 0, sizeof(rsp_buff)); res = svpd_decode_t10(sg_fd, op, subvalue, 0); if (SG_LIB_SYNTAX_ERROR == res) { res = svpd_decode_vendor(sg_fd, op, 0); if (SG_LIB_SYNTAX_ERROR == res) res = svpd_unable_to_decode(sg_fd, op, subvalue, 0); } if (SG_LIB_CAT_ABORTED_COMMAND == res) pr2serr("fetching VPD page failed, aborted command\n"); else if (res) { char b[80]; sg_get_category_sense_str(res, sizeof(b), b, op->verbose); pr2serr("fetching VPD page failed: %s\n", b); } ret = res; } res = sg_cmds_close_device(sg_fd); if (res < 0) { pr2serr("close error: %s\n", safe_strerror(-res)); if (0 == ret) return SG_LIB_FILE_ERROR; } return (ret >= 0) ? ret : SG_LIB_CAT_OTHER; } sg3_utils-1.40/suse/0000775000175000017500000000000012431015530013321 5ustar douggdouggsg3_utils-1.40/suse/sg3_utils.changes0000664000175000017500000004116012270322342016574 0ustar douggdougg------------------------------------------------------------------- Thu Jan 23 15:00:00 EST 2014 - dgilbert@interlog.com - import Suse build files into sg3_utils in the suse directory * change suse spec file to be patch-less * henceforth see ChangeLog in main directory ------------------------------------------------------------------- Thu Jan 23 08:57:56 CET 2014 - hare@suse.de - Update to inofficial release 1.38r546 * sg_ses: error and warning message cleanup - fix --data=- problem with large buffers - new --data=@FN to read hex data from file FN - add --maxlen= option * sg_inq: - add LU_CONG to standard inquiry response - sync version descriptors dated 20131126 - fix overflow in encode_whitespaces * sg_vpd: add LU_CONG to standard inquiry response output - decode Third Party Copy (tpc) page * sg_persist: add PROUT: Replace Lost Reservation (spc4r36) * sg_readcap: for --16 show physical block size if * sg_xcopy: - environment variables: XCOPY_TO_SRC and XCOPY_TO_DST indicate where xcopy command is sent - change default to send xcopy to dst (was src) - improve CL handling of short options (e.g. '-vv') * sg_write_same: repeat if unit attention * sg_rtpg: fix indexing bug with --extended option * sg_lib_data: sync asc/ascq codes with T10 dated 20131110 * sg_cmds_extra: fix sa bug in sg_ll_3party_copy_out() - Update tarball to 1.38b7r537 - Add sg3_utils-1.38r546.patch ------------------------------------------------------------------- Mon Nov 4 01:59:38 UTC 2013 - jengelh@inai.de - Update to new upstream release 1.37 * sg_compare_and_write: add --quiet option to suppress miscompare report * sg_persist: fix core dump on -Q option * sg_unmap: fix core dump on -g option * sg_ses: add --nickname and --nickid options - Remove sg3_utils-Fixup-T10-Vendor-designator-display.patch (merged upstream) ------------------------------------------------------------------- Sun Aug 25 18:45:14 CEST 2013 - ohering@suse.de - Fixup T10 Vendor designator display (bnc#805059) sg3_utils-Fixup-T10-Vendor-designator-display.patch - In rescan-scsi-bus.sh, check if the HBA driver exports issue_lip in sysfs before using it (bnc#780946) sg3_utils-check-if-hba-supports-issue-lip.patch ------------------------------------------------------------------- Thu Jun 13 14:15:26 UTC 2013 - jengelh@inai.de - Implement shlib packaging guidelines; rename sg3_utils-devel to libsgutils-devel (upstream recommendation) - More robust make install call; remove redundant %clean section; simplify file lists ------------------------------------------------------------------- Tue Jun 11 08:56:39 UTC 2013 - rmilasan@suse.com - Update to version 1.36 - sg_vpd: Protocol-specific port information VPD page for SAS SSP, persistent connection (spl3r2), power disable (spl3r3) - block device characteristics: add FUAB bit - sg_xcopy: handle more descriptor types; handle zero maximum segment length; allow list IDs to be disabled; improve skip/seek handling; allow xcopy on destination - sg_reset: and --no-esc option to stop reset escalation - clean up cli, add long option names - sg_luns: add --test=ALUN option for decoding LUNs - decoded luns output in decimal or hex (if -HH given) - add '--linux' option to show Linux LUN after T10 representation, can map one to the other - sg_inq: add --vendor option to show standard inquiry's vendor specific fields in ASCII - take resid into account with response output - sg_sync: add --16 (for 16 byte command) and --timeout= - sg_logs: add data compression page (ssc4) - sg_sat_set_features: increase --lba from 1 to 4 bytes - sg_write_same: add --ndob option (sbc3r35d) - sg_map: mark as deprecated - sginfo: mark as deprecated, especially -l (list) - sg_lib: improve snprintf handling - sg_lib_data: sync asc/ascq codes with T10 20130117 - sg_cmds (lib): if noisy given, give more UA info - make code more C++ friendly ------------------------------------------------------------------- Tue Mar 12 09:13:45 CET 2013 - hare@suse.de - Update to version 1.35 - sg_compare_and_write: new utility - sg_inq+sg_vpd: block device characteristics VPD page: add product_type, WABEREQ, WACEREQ and VBULS fields - sg_inq: more --export option changes for udev - sg_vpd: add more rdac vendor specific vpd pages - sg_verify: add --ebytchk option for sbc3r34 changes - sg_stpg: --offline option: fix 'Invalid state 0xe' - sg_ses: Door Lock element changed to Door element and abbreviation changed from 'dl' to 'do' (ses3r05) - archive/rescan-scsi-bus.sh: upgrade to version 1.53hr - move rescan-scsi-bus.sh to scripts directory - sync to sbc3r34 - sg_lib: sg_ll_verify10+16 expand BYTCHK to 2 bit field - sg_pt_win32, sg_scan(win32): changes for cygwin 1.7.17 - clean up man page summary lines - sg_xcopy: new dd like utility for extended copy command - sg_copy_results: new utility for receive copy results - sg_verify: add 16 byte cdb, bytchk (data-out buffer) and group number support - sync to spc4r36 and sbc3r32 - sg_inq: add --export so sg_inq can replace udev's scsi_id - decode old EMC Symmetrix abuse of VPD page 0x83 - sg_vpd: decode old EMC Symmetrix abuse of VPD page 0x83 - sg_ses: increase max dpage response size to 64 KB - allow ident,locate on enclosure controller - more sanity for additional element status descriptor - sg_sanitize: add --ause, --fail and --test= - sg_luns: add long extended flat space addressing format - sg_logs: add ATA pass-through results lpage (SAT-2) - sg_rtpg: add --extended option - sg_senddiag: list rebuild assist diag page name - sg_pt_linux: expand DID_ (host_byte) codes - cope with a transport error plus sense data - prefer major() over MAJOR() macro - sg_lib: fix sg_get_command_name() service actions - report sdat_ovfl bit (if set) in sense data - decode extended_copy and receive_copy service actions - decode read_buffer and write_buffer modes - decode ATA PT fixed format sense (SAT-2) - sg_cmds_extra: add sg_ll_report_tgt_prt_grp2() - ./configure options: - change --enable-no-linux-bsg to --disable-linuxbsg - add --disable-scsistrings to reduce utility sizes ------------------------------------------------------------------- Wed Jul 4 07:01:46 UTC 2012 - cfarrell@suse.com - license update: GPL-2.0+ and BSD-3-Clause Show aggregation and make compatible with Fedora declaration ------------------------------------------------------------------- Sun Apr 22 11:50:44 UTC 2012 - puzel@suse.com - Update to version 1.33 - sg_ses: major rework of indexes (again), now two level - sg_write_buffer: new --specific option for mode specific field; new mode 13 (spc4r32) - sg_vpd: add hp3par volume info vendor VPD page - fix 'scsi ports' [0x88] page problem - add 'sinq' pseudo page for standard inquiry response - add power consumption page - sg_format: add --poll= option for request sense polling - improve handling of disks > 2 TB and DIF (protection) - sg_logs: LB provision lpage extra (sbc3r28) - sg_modes: application tag mpage subcode 0xf0->0x2 - sg_write_same: no prot fields when wrprotect=0 - sg_get_lba_status: reflect change in sbc3r25 to Parameter Data Length response field (offset reduced from 8 to 4) - sg_inq, sg_vpd: sync with spc4r33 - win32: change DataBufferOffset type per MSDN; caused problem with 64 bit machines (with buffered interface) - sg_luns: tweak documentation for vendor specific reports - add man pages for scsi_loging_level, scsi_mandat, scsi_satl and scsi_temperature ------------------------------------------------------------------- Mon Jan 16 19:59:42 UTC 2012 - tabraham@novell.com - Update to version 1.32 + sg_sanitize: new utility for command added in sb3r27 + sg_sat_identify: add '--ident' to output WWN + sg_ses: major rework of descriptor output + add --index, --descriptor, --join, --clear, --get, and --set options + sg_raw: exit status corrections + sg_decode_sense: add --nospace and --hex options + sg_logs: fix bug with large --maxlen + zero response length when resid implies it is invalid + add scope field to lb provisioning lpage (sb3r27) + sg_inq: sync version descriptors with spc4r31 + sb_lib_data: sync asc/ascq codes with spc4r31 + sg_vpd: add LBPRZ field in LP provisioning VPD page + sg_format: allow format of pdt 7 (some MO drives) + sg_cmd_basic: sg_cmds_process_resp() handle status good with a sense key other than no_sense (e.g. completed) + add README.iscsi - Updated rescan-scsi-bus.sh to v1.56 ------------------------------------------------------------------- Thu Mar 10 08:47:43 UTC 2011 - coolo@novell.com - fix file list ------------------------------------------------------------------- Fri Feb 18 16:41:32 CET 2011 - hare@suse.de - Update to version 1.31: + sg_decode_sense: new utility to decode sense data + sg_vpd: LB provisioning + Block limits pages (sbc3r26) + sync asc/ascq and version descriptors with spc4r28 + sg_get_config, sg_rmsn, sg_verify: add --readonly option + sg_lib: implement forwarded sense data descriptor - decode user data segment referral sense data descriptor + sg_lib, sg_turs, sg_format: more precision for progress indication (two places after decimal point) + sg_lib(win32): add runtime selection of SPT direct or indirect interface - sg_read_buffer+sg_write_buffer: set SPT direct + add examples/forwarded_sense.txt + examples/ref_sense.txt - Changes from version 1.30: + sg_referrals: new utility for REPORT REFERRALS + sbc3r25 renames 'thin' provisioning' to 'logical block provisioning': changes in sg_format, sg_inq, sg_logs, sg_modes, sg_readcap, sg_vpd + sg_inq: update version descriptor list to spc4r27 - extended inquiry vpd page add extended self test completion minutes field + sg_lib: sync asc/ascq list to spc4r27 - dStrHex(): trim excess trailing spaces + sg_read_long: add --readonly option (open() is rw) + sg_raw: add --readonly option (open() is rw) - allow bidirectional commands + sg_vpd: rdac vendor page [0xc8] parse corrections - extended inquiry vpd page add extended self test -completion minutes field + sg_ses: expand --data (in) buffer to 2048 bytes + sg_opcodes: add extended parameter data for TMFs (spc4r26) + sg_dd: clean count calculation, document nocache flag - treat bsg devices as implicit sg_io + sg_write_same: if READ CAPACITY(16) fails try 10 byte variant - anticipate approval of proposal to allow UNMAP and ANCHOR bits to be set on WRITE SAME(10) with '--10' option + sg3_utils man page: sections added for OS device names ------------------------------------------------------------------- Fri Aug 13 11:42:50 CEST 2010 - dimstar@opensuse.org - Update to version 1.29: + sg_rtpg: new logical block dependent state and bit (spc4r23) + sg_start: add '--readonly' option for ATA disks + sg_lib: update asc/ascq list to spc4r23 + sg_inq: update version descriptor list to spc4r23 + sg_vpd: block device characteristics page: fix form factor - update Extended Inquiry VPD page to spc4r23 - update Block Limits VPD page to sbc3r22 - update Thin Provisioning VPD page to sbc3r22 - Automation device serial number and Data transfer device element VPD pages (ssc4r01) - add Referrals VPD page (sbc3r22) + sg_logs: add thin provisioning and solid state media log pages - addition of IBM LTO specific log pages + sg_modes: new page names from ssc4r01 + sg_ses: sync with ses3r02 (SAS-2.1 connector types) + sg_unmap: add '--anchor' option (sbc3r22) + sg_write_same: add '--anchor' option (sbc3r22) + sg_pt interface: add set_scsi_pt_flags() to permit passing through SCSI_PT_FLAGS_QUEUE_AT_TAIL and AT_HEAD flags + add examples/sg_queue_tst+bsg_queue_tst for SG_FLAG_Q_AT_TAIL + add AM_MAINTAINER_MODE to configure.ac to lessen build issues + add BSD_LICENSE file to this and lib directories, refer to it from source and header files. Some source has GPL license - Changes from version 1.28: + sg_unmap: new utility for thin provisioning - add examples/sg_unmap_example.txt + sg_get_lba_status: new utility for thin provisioning + sg_read_block_limits: new utility for tape drives + sg_logs: add cache memory statistics log (sub)page + sg_vpd, sg_inq: extend Block limits VPD page (sbc3r19) + sg_vpd: add Thin provisioning VPD page (sbc3r20) and TapeAlert supported flags VPD page + sg_inq: note VPD page support better in sg_vpd + sg_persist: add transport specific transportID format - allow transportIDs to be read from named file + sg_opcodes: allow --opcode= option to take OP and SA values (comma seperated) - tweak print format, remove test code + sg_requests: remove test code in progress calculation + sg_reset: add target reset option + sg_luns: reduce default maxlen to 8192 (for FreeBSD) + sg_raw: extend max cdb length from 16 to 256 bytes - align heap allocs to page boundaries + sg_lib: sg_set_binary_mode() needs config.h included - add progress indication sense data descriptor (0xa) - change SG3_UTILS_* constants to SG_LIB_* - decode service actions within persistent reserve in/out - sync with spc4r21 + sg_cmds_extra: add sg_ll_unmap() and sg_ll_get_lba_status() + sg_pt_linux: fix check condition but empty sense buffer; - major() macro grief, if present include and use MAJOR() instead + scripts/sas_disk_blink: moved from this package to sdparm + utils/hxascdmp: in Windows set binary mode on read files + examples/sg_persist_tst.sh: add PRIN read full status command + sg_raw,sg_write_buffer,sg_write_long,sg_write_same: in Windows set binary mode on read files + sg_pt_win32: default to non-direct variant of SPT interface - use './configure --enable-win32-spt-direct' to override - non-direct data length set to 16 KB, extended if required + debian: incorporate patch from debian sid ------------------------------------------------------------------- Mon Jun 28 06:38:35 UTC 2010 - jengelh@medozas.de - use %_smp_mflags ------------------------------------------------------------------- Tue Jul 21 14:00:16 CEST 2009 - hare@suse.de - Clean up spec file and remove obsolete cruft ------------------------------------------------------------------- Fri Apr 17 20:15:58 CEST 2009 - crrodriguez@suse.de - remove static libraries and "la" files ------------------------------------------------------------------- Mon Jan 26 15:30:31 CET 2009 - hare@suse.de - Fixes to rescan-scsi-bus.sh: * Implement '--forcerescan' to force a rescan of existing devices * Handle LUN changes correctly * Check variables before evaluation ------------------------------------------------------------------- Wed Oct 29 11:05:47 CET 2008 - garloff@suse.de - rescan-scsi-bus.sh 1.29: * Fix error in script (returning "" does not work) * Support systems without /proc/scsi - Don't install INSTALL ------------------------------------------------------------------- Tue Sep 30 14:11:15 CEST 2008 - hare@suse.de - Add %insserv_prereq (bnc#423204) ------------------------------------------------------------------- Fri Sep 12 20:29:08 CEST 2008 - garloff@suse.de - Update rescan-scsi-bus.sh script to 1.28: * Merge fixes from Hannes * Minor cleanups * Sort hosts numerically ------------------------------------------------------------------- Tue Aug 12 18:25:43 CEST 2008 - garloff@suse.de - Update to sg3_utils-1.27: * Adapted to linux-2.6.26 (sg_map26) * sg_dd uses flock (rw -- if that fails ro) * sg_get_config: OSSC feature (mmc6r02) - Update to sg3_utils-1.26: * Minor fixes and enhancements to sg_sat_phy_event, sg_ses, sg_get_config, sg_verify, sg_vpd, sg_inq, sg_modes, sg_start, sg_request, sg_luns, sg_dd, sg_opcodes, sg_turs. * sg_lib: asc/ascq update for spc4r15, osd2r03 service actions, sense key specific unit attn queue overflow decoding, ... * Restructuring: sg_lib -> sg_lib_data, sg_inq_data, (u)int64_t, sg_io_linux -> lib/. * Documentation enhancements. ------------------------------------------------------------------- Wed Jul 16 09:55:33 CEST 2008 - hare@suse.de - Use correct length parameter for sg_inq (bnc#363438) ------------------------------------------------------------------- Fri May 23 10:22:31 CEST 2008 - hare@suse.de - Use 'Provides' to clean update dependency ------------------------------------------------------------------- Fri May 9 17:31:33 CEST 2008 - schwab@suse.de - Use autoreconf -i. ------------------------------------------------------------------- Thu Apr 24 14:14:14 CEST 2008 - hare@suse.de - Split off from original scsi package. sg3_utils-1.40/suse/sg3_utils.spec0000664000175000017500000001042612406465611016127 0ustar douggdougg# # spec file for package sg3_utils # # Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # # # No patches, this is the maintainer's version for Suse targets. # Patch lines would appear after the "Source:" line and look like: # Patch1: sg3_utils-1.38r546.patch # then under the "%setup -q" line there would be one or more lines: # %patch1 -p1 Name: sg3_utils %define lname libsgutils2-2 Version: 1.40 Release: 0 Summary: A collection of tools that send SCSI commands to devices License: GPL-2.0+ and BSD-3-Clause Group: Hardware/Other Url: http://sg.danny.cz/sg/sg3_utils.html Source: http://sg.danny.cz/sg/p/%name-%{version}.tar.xz BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: xz Requires(pre): %insserv_prereq Provides: scsi Provides: sg_utils Obsoletes: scsi <= 1.7_2.38_1.25_0.19_1.02_0.93 %description The sg3_utils package contains utilities that send SCSI commands to devices. As well as devices on transports traditionally associated with SCSI (e.g. Fibre Channel (FCP), Serial Attached SCSI (SAS) and the SCSI Parallel Interface(SPI)) many other devices use SCSI command sets. ATAPI cd/dvd drives and SATA disks that connect via a translation layer or a bridge device are examples of devices that use SCSI command sets. %package -n %lname Summary: Library to hold functions common to the SCSI utilities License: BSD-3-Clause Group: System/Libraries %description -n %lname The sg3_utils package contains utilities that send SCSI commands to devices. As well as devices on transports traditionally associated with SCSI (e.g. Fibre Channel (FCP), Serial Attached SCSI (SAS) and the SCSI Parallel Interface(SPI)) many other devices use SCSI command sets. ATAPI cd/dvd drives and SATA disks that connect via a translation layer or a bridge device are examples of devices that use SCSI command sets. This subpackage contains the library of common sg_utils code, such as SCSI error processing. %package -n libsgutils-devel Summary: A collection of tools that send SCSI commands to devices License: BSD-3-Clause Group: Development/Libraries/C and C++ Requires: %lname = %version # Added for 13.1 Obsoletes: %name-devel < %version-%release Provides: %name-devel = %version-%release %description -n libsgutils-devel The sg3_utils package contains utilities that send SCSI commands to devices. As well as devices on transports traditionally associated with SCSI (e.g. Fibre Channel (FCP), Serial Attached SCSI (SAS) and the SCSI Parallel Interface(SPI)) many other devices use SCSI command sets. ATAPI cd/dvd drives and SATA disks that connect via a translation layer or a bridge device are examples of devices that use SCSI command sets. This subpackage contains libraries and header files for developing applications that want to make use of libsgutils. %prep %setup -q %build %configure --disable-static --with-pic make %{?_smp_mflags} %install make install DESTDIR="%buildroot" install -m 755 scripts/scsi_logging_level $RPM_BUILD_ROOT%{_bindir} install -m 755 scripts/rescan-scsi-bus.sh $RPM_BUILD_ROOT%{_bindir} %{__rm} -f %{buildroot}%{_libdir}/*.la %post -p /sbin/ldconfig -n %lname %postun -p /sbin/ldconfig -n %lname %files %defattr(-,root,root) %doc README README.sg_start %doc ChangeLog CREDITS NEWS %_bindir/sg_* %_bindir/scsi_* %_bindir/sginfo %_bindir/sgp_dd %_bindir/sgm_dd %_bindir/scsi_logging_level %_bindir/rescan-scsi-bus.sh %_mandir/man8/*.8* %files -n %lname %defattr(-,root,root) %_libdir/libsgutils2.so.2* %files -n libsgutils-devel %defattr(-,root,root) %_libdir/libsgutils2.so %_includedir/scsi/ %changelog sg3_utils-1.40/README.tru640000664000175000017500000000542112076116252014217 0ustar douggdouggIntroduction ============ The Tru64 port of sg3_utils contains those utilities that are _not_ specific to Linux. In some cases a utility could be ported but requires more work. An example is sg_dd which needs more work beyond the SCSI command pass through mechanism. Supported Utilities =================== Here is a list of utilities that have been ported: sg_compare_and_write sg_decode_sense sg_format sg_get_config sg_get_lba_status sg_ident sg_inq [dropped ATA IDENTIFY DEVICE capability] sg_logs sg_luns sg_modes sg_opcodes sg_persist sg_prevent sg_raw sg_rdac sg_read_block_limits sg_read_buffer sg_read_long sg_readcap sg_reassign sg_referrals sg_requests sg_rmsn sg_rtpg sg_safte sg_sanitize sg_sat_identify sg_sat_phy_event sg_sat_set_features sg_senddiag sg_ses sg_start sg_stpg sg_sync sg_turs sg_unmap sg_verify sg_vpd sg_wr_mode sg_write_buffer sg_write_long sg_write_same Most utility names are indicative of the main SCSI command that they execute. Some utilities are slightly higher level, for example sg_ses fetches SCSI Enclosure Services (SES) status pages and can send control pages. Each utility has a man page (placed in section 8). An overview of sg3_utils can be found at: http://sg.danny.cz/sg/sg3_utils.html . A copy of the "sg3_utils.html" file is in the "doc" subdirectory. This package uses autotools infrastructure with the now common "./configure ; make ; make install" sequence needed to build and install from the source found in the tarball. If the "./configure" sequence fails try using the ./autogen.sh prior to that sequence. Some man pages have examples which use Linux device names which hopefully will not confuse Tru64 users. Details ======= Most of the ported utilities listed above use SCSI command functions declared in sg_cmds_*.h headers . Those SCSI command functions are implemented in the corresponding ".c" files. The ".c" files pass SCSI commands to the host operating system via an interface declared in sg_pt.h . There are currently five implementations of that interface depending on the host operating system: system: - sg_pt_linux.c - sg_pt_osf1.c [Tru64] - sg_pt_freebsd.c - sg_pt_solaris.c - sg_pt_win32.c The sg_pt_osf1.c file uses the Tru64 CAM SCSI pass through mechanism. Tru64 does not have general library support for "long" options (e.g. "--verbose") which are used extensively by most of the utilities in this package. Rather than change all the utilities and their man/web pages a local implementation of the missing function "getopt_long()" has been placed in the "getopt_long" subdirectory. Currently only the Tru64 port uses it. Douglas Gilbert 14th January 2013 sg3_utils-1.40/sg3_utils.spec0000664000175000017500000001554712430315266015156 0ustar douggdouggSummary: Utilities for devices that use SCSI command sets Name: sg3_utils Version: 1.40 # Release: 1%{?dist} Release: 1 License: GPL Group: Utilities/System Source: ftp://sg.danny.cz/sg/p/sg3_utils-%{version}.tgz Url: http://sg.danny.cz/sg/sg3_utils.html Provides: sg_utils BuildRequires: libtool BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) Packager: Douglas Gilbert %description Collection of Linux utilities for devices that use the SCSI command set. Includes utilities to copy data based on "dd" syntax and semantics (called sg_dd, sgp_dd and sgm_dd); check INQUIRY data and VPD pages (sg_inq); check mode and log pages (sginfo, sg_modes and sg_logs); spin up and down disks (sg_start); do self tests (sg_senddiag); and various other functions. See the README, ChangeLog and COVERAGE files. Requires the linux kernel 2.4 series or later. In the 2.4 series SCSI generic device names (e.g. /dev/sg0) must be used. In the 2.6 series and later other device names may be used as well (e.g. /dev/sda). Warning: Some of these tools access the internals of your system and the incorrect usage of them may render your system inoperable. %package libs Summary: Shared library for %{name} Group: System/Libraries %description libs This package contains the shared library for %{name}. %package devel Summary: Static library and header files for the sgutils library Group: Development/C Requires: %{name}-libs = %{version}-%{release} %description devel This package contains the static %{name} library and its header files for developing applications. %prep %setup -q %build %configure %install if [ "$RPM_BUILD_ROOT" != "/" ]; then rm -rf $RPM_BUILD_ROOT fi make install \ DESTDIR=$RPM_BUILD_ROOT %clean if [ "$RPM_BUILD_ROOT" != "/" ]; then rm -rf $RPM_BUILD_ROOT fi %files %defattr(-,root,root) %doc AUTHORS ChangeLog COPYING COVERAGE CREDITS INSTALL NEWS README README.sg_start %attr(755,root,root) %{_bindir}/* %{_mandir}/man8/* %files libs %defattr(-,root,root) %{_libdir}/*.so.* %files devel %defattr(-,root,root) %{_includedir}/scsi/*.h %{_libdir}/*.so %{_libdir}/*.a %{_libdir}/*.la %changelog * Mon Nov 10 2014 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.40 * Thu Jun 12 2014 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.39 * Tue Apr 01 2014 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.38 * Mon Oct 14 2013 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.37 * Fri May 31 2013 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.36 * Thu Jan 17 2013 - dgilbert at interlog dot com - add sg_compare_and_write, track t10 changes * sg3_utils-1.35 * Sat Oct 13 2012 - dgilbert at interlog dot com - add sg_xcopy and sg_copy_results; track t10 changes * sg3_utils-1.34 * Wed Jan 18 2012 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.33 * Wed Jun 22 2011 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.32 * Wed Feb 16 2011 - dgilbert at interlog dot com - add sg_decode_sense; track t10 changes * sg3_utils-1.31 * Fri Nov 05 2010 - dgilbert at interlog dot com - add sg_referrals; track t10 changes * sg3_utils-1.30 * Wed Mar 31 2010 - dgilbert at interlog dot com - track t10 changes * sg3_utils-1.29 * Fri Oct 02 2009 - dgilbert at interlog dot com - add sg_get_lba_status, sg_unmap, sg_read_block_limits * sg3_utils-1.28 * Sat Apr 11 2009 - dgilbert at interlog dot com - add sg_write_same; sg_dd split; spc4r18 sync * sg3_utils-1.27 * Wed Jun 25 2008 - dgilbert at interlog dot com - add sg_sat_phy_event, sync with drafts prior to this date * sg3_utils-1.26 * Tue Oct 16 2007 - dgilbert at interlog dot com - add sg_sat_set_features, sg_stpg, sg_safte; sg_dd oflag=sparse,null * sg3_utils-1.25 * Mon May 07 2007 - dgilbert at interlog dot com - add sg_raw; sg_rtpg, sg_log, sg_inq and sg_format updates * sg3_utils-1.24 * Wed Jan 31 2007 - dgilbert at interlog dot com - add sg_read_buffer + sg_write_buffer * sg3_utils-1.23 * Mon Oct 16 2006 - dgilbert at interlog dot com - add sg_sat_identify, expand sg_format and sg_requests * sg3_utils-1.22 * Thu Jul 06 2006 - dgilbert at interlog dot com - add sg_vpd and sg_rdac, uniform exit statuses * sg3_utils-1.21 * Tue Apr 18 2006 - dgilbert at interlog dot com - sg_logs: sas port specific page decoding, sg*_dd updates * sg3_utils-1.20 * Fri Jan 27 2006 - dgilbert at interlog dot com - sg_get_config: resync features with mmc5 rev 1 * sg3_utils-1.19 * Fri Nov 18 2005 - dgilbert at interlog dot com - add sg_map26; sg_inq '-rr' option to play with hdparm * sg3_utils-1.18 * Thu Sep 22 2005 - dgilbert at interlog dot com - add ATA information VPD page to sg_inq * sg3_utils-1.17 * Wed Aug 10 2005 - dgilbert at interlog dot com - add sg_ident, sg_inq VPD page extensions * sg3_utils-1.16 * Sun Jun 05 2005 - dgilbert at interlog dot com - use O_NONBLOCK on all fds that use SG_IO ioctl * sg3_utils-1.15 * Fri May 06 2005 - dgilbert at interlog dot com - produce libsgutils (+ -devel variant) as well as sg3_utils binary rpm * sg3_utils-1.14 * Sun Mar 13 2005 - dgilbert at interlog dot com - add sg_format, sg_dd extensions * sg3_utils-1.13 * Fri Jan 21 2005 - dgilbert at interlog dot com - add sg_wr_mode, sg_rtpg + sg_reassign; sginfo sas tweaks * sg3_utils-1.12 * Fri Nov 26 2004 - dgilbert at interlog dot com - add sg_sync, sg_prevent and sg_get_config; fix sg_requests * sg3_utils-1.11 * Sat Oct 30 2004 - dgilbert at interlog dot com - fix read capacity (10+16), add sg_luns * sg3_utils-1.10 * Thu Oct 21 2004 - dgilbert at interlog dot com - sg_requests, sg_ses, sg_verify, libsgutils(sg_lib.c+sg_cmds.c), devel rpm * sg3_utils-1.09 * Tue Aug 31 2004 - dgilbert at interlog dot com - 'register+move' in sg_persist, sg_opcodes sorts, sg_write_long * sg3_utils-1.08 * Thu Jul 08 2004 - dgilbert at interlog dot com - add '-fHead' to sginfo, '-i' for sg_inq, new sg_opcodes + sg_persist * sg3_utils-1.07 * Mon Apr 26 2004 - dgilbert at interlog dot com - sg3_utils.spec for mandrake; more sginfo work, sg_scan, sg_logs * sg3_utils-1.06 * Wed Nov 12 2003 - dgilbert at interlog dot com - sg_readcap: sizes; sg_logs: double fetch; sg_map 256 sg devices; sginfo * sg3_utils-1.05 * Tue May 13 2003 - dgilbert at interlog dot com - default sg_turs '-n=' to 1, sg_logs gets '-t' for temperature, CREDITS * sg3_utils-1.04 * Wed Apr 02 2003 - dgilbert at interlog dot com - 6 byte CDBs for sg_modes, sg_start on block devs, sg_senddiag, man pages * sg3_utils-1.03 * Wed Jan 01 2003 - dgilbert at interlog dot com - interwork with block SG_IO, fix in sginfo, '-t' for sg_turs * sg3_utils-1.02 * Wed Aug 14 2002 - dgilbert at interlog dot com - raw switch in sg_inq * sg3_utils-1.01 * Sun Jul 28 2002 - dgilbert at interlog dot com - decode sg_logs pages, add dio to sgm_dd, drop "gen=1" arg, "of=/dev/null" * sg3_utils-1.00 sg3_utils-1.40/archive/0000755000175000017500000000000012431015530013761 5ustar douggdouggsg3_utils-1.40/archive/llseek.c0000664000175000017500000000645112072605715015427 0ustar douggdougg/* * llseek.c -- stub calling the llseek system call * * Copyright (C) 1994 Remy Card. This file may be redistributed * under the terms of the GNU Public License. * * This file is borrowed from the util-linux-2.11z tarball's implementation * of fdisk. It allows seeks to 64 bit offsets, if supported. * Changed "ext2_" prefix to "llse". */ #include "config.h" #define _XOPEN_SOURCE 500 #define _GNU_SOURCE #include #include #include #if defined(__GNUC__) || defined(HAS_LONG_LONG) typedef int64_t llse_loff_t; #else typedef long llse_loff_t; #endif extern llse_loff_t llse_llseek (unsigned int, llse_loff_t, unsigned int); #ifdef __linux__ #ifdef HAVE_LLSEEK #include #else /* HAVE_LLSEEK */ #if defined(__alpha__) || defined(__ia64__) || defined(__s390x__) || defined (__x86_64__) || defined (__powerpc64__) #define my_llseek lseek #else #include /* for __NR__llseek */ static int _llseek (unsigned int, unsigned long, unsigned long, llse_loff_t *, unsigned int); #ifdef __NR__llseek static _syscall5(int,_llseek,unsigned int,fd,unsigned long,offset_high, unsigned long, offset_low,llse_loff_t *,result, unsigned int, origin) #else /* no __NR__llseek on compilation machine - might give it explicitly */ static int _llseek (unsigned int fd, unsigned long oh, unsigned long ol, llse_loff_t *result, unsigned int origin) { errno = ENOSYS; return -1; } #endif static llse_loff_t my_llseek (unsigned int fd, llse_loff_t offset, unsigned int origin) { llse_loff_t result; int retval; #ifdef HAVE_LSEEK64 return lseek64 (fd, offset, origin); #else retval = _llseek (fd, ((uint64_t) offset) >> 32, ((uint64_t) offset) & 0xffffffff, &result, origin); return (retval == -1 ? (llse_loff_t) retval : result); #endif } #endif /* __alpha__ */ #endif /* HAVE_LLSEEK */ llse_loff_t llse_llseek (unsigned int fd, llse_loff_t offset, unsigned int origin) { llse_loff_t result; static int do_compat = 0; if (!do_compat) { result = my_llseek (fd, offset, origin); if (!(result == -1 && errno == ENOSYS)) return result; /* * Just in case this code runs on top of an old kernel * which does not support the llseek system call */ do_compat = 1; /* * Now try ordinary lseek. */ } if ((sizeof(off_t) >= sizeof(llse_loff_t)) || (offset < ((llse_loff_t) 1 << ((sizeof(off_t)*8) -1)))) return lseek(fd, (off_t) offset, origin); errno = EINVAL; return -1; } #else /* !linux */ llse_loff_t llse_llseek (unsigned int fd, llse_loff_t offset, unsigned int origin) { if ((sizeof(off_t) < sizeof(llse_loff_t)) && (offset >= ((llse_loff_t) 1 << ((sizeof(off_t)*8) -1)))) { errno = EINVAL; return -1; } return lseek (fd, (off_t) offset, origin); } #endif /* linux */ sg3_utils-1.40/archive/README0000664000175000017500000000131112073404614014646 0ustar douggdouggThe code and scripts in this directory may be removed at some later date. The last cleanup (i.e. purge of unused files) of this directory occurred between sg3_utils version 1.22 and 1.23 . No other code or script in this package currently uses the contents of this directory. The contents of this directory are not maintained by the author. The rescan-scsi-bus.sh script was copied long ago from http://www.garloff.de/kurt/linux (under the "Rescan SCSI bus" heading) and was later placed in this directory. Since others do use the version of this script found in this package then rescan-scsi-bus.sh was updated in sg3_utils version 1.35 and was moved to the scripts directory. Douglas Gilbert 9th January 2013 sg3_utils-1.40/archive/o_scsi_logging_level0000775000175000017500000002102710640357443020103 0ustar douggdougg#! /bin/bash ############################################################################### # Conveniently create and set scsi logging level, show SCSI_LOG fields in human # readable form. # # Copyright (C) IBM Corp. 2006 # # 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 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA # 02110-1301, USA. ############################################################################### # Contributed by Andreas Herrmann 2006/08/18 SCRIPTNAME="scsi_logging_level" declare -i LOG_ERROR=0 declare -i LOG_TIMEOUT=0 declare -i LOG_SCAN=0 declare -i LOG_MLQUEUE=0 declare -i LOG_MLCOMPLETE=0 declare -i LOG_LLQUEUE=0 declare -i LOG_LLCOMPLETE=0 declare -i LOG_HLQUEUE=0 declare -i LOG_HLCOMPLETE=0 declare -i LOG_IOCTL=0 declare -i LEVEL=0 _ERROR_SHIFT=0 _TIMEOUT_SHIFT=3 _SCAN_SHIFT=6 _MLQUEUE_SHIFT=9 _MLCOMPLETE_SHIFT=12 _LLQUEUE_SHIFT=15 _LLCOMPLETE_SHIFT=18 _HLQUEUE_SHIFT=21 _HLCOMPLETE_SHIFT=24 _IOCTL_SHIFT=27 SET=0 GET=0 CREATE=0 OPTS=`getopt -o hvcgsa:E:T:S:I:M:L:H: --long \ help,version,create,get,set,all:,error:,timeout:,scan:,ioctl:,\ midlevel:,mlqueue:,mlcomplete:,lowlevel:,llqueue:,llcomplete:,\ highlevel:,hlqueue:,hlcomplete: -n \'$SCRIPTNAME\' -- "$@"` eval set -- "$OPTS" # print version info printversion() { cat <>$_ERROR_SHIFT) & 7)) LOG_TIMEOUT=$((($LEVEL>>$_TIMEOUT_SHIFT) & 7)) LOG_SCAN=$((($LEVEL>>$_SCAN_SHIFT) & 7)) LOG_MLQUEUE=$((($LEVEL>>$_MLQUEUE_SHIFT) & 7)) LOG_MLCOMPLETE=$((($LEVEL>>$_MLCOMPLETE_SHIFT) & 7)) LOG_LLQUEUE=$((($LEVEL>>$_LLQUEUE_SHIFT) & 7)) LOG_LLCOMPLETE=$((($LEVEL>>$_LLCOMPLETE_SHIFT) & 7)) LOG_HLQUEUE=$((($LEVEL>>$_HLQUEUE_SHIFT) & 7)) LOG_HLCOMPLETE=$((($LEVEL>>$_HLCOMPLETE_SHIFT) & 7)) LOG_IOCTL=$((($LEVEL>>$_IOCTL_SHIFT) & 7)) echo "SCSI_LOG_ERROR=$LOG_ERROR" echo "SCSI_LOG_TIMEOUT=$LOG_TIMEOUT" echo "SCSI_LOG_SCAN=$LOG_SCAN" echo "SCSI_LOG_MLQUEUE=$LOG_MLQUEUE" echo "SCSI_LOG_MLCOMPLETE=$LOG_MLCOMPLETE" echo "SCSI_LOG_LLQUEUE=$LOG_LLQUEUE" echo "SCSI_LOG_LLCOMPLETE=$LOG_LLCOMPLETE" echo "SCSI_LOG_HLQUEUE=$LOG_HLQUEUE" echo "SCSI_LOG_HLCOMPLETE=$LOG_HLCOMPLETE" echo "SCSI_LOG_IOCTL=$LOG_IOCTL" } set_logging_level() { echo "New scsi logging level:" sysctl -q -w dev.scsi.logging_level=$LEVEL if [ $? != 0 ] then echo "$SCRIPTNAME: could not write scsi logging level" \ "(kernel probably without SCSI_LOGGING support)" exit 1 fi } create_logging_level() { LEVEL=$((($LOG_ERROR & 7)<<$_ERROR_SHIFT)) LEVEL=$(($LEVEL|(($LOG_TIMEOUT & 7)<<$_TIMEOUT_SHIFT))) LEVEL=$(($LEVEL|(($LOG_SCAN & 7)<<$_SCAN_SHIFT))) LEVEL=$(($LEVEL|(($LOG_MLQUEUE & 7)<<$_MLQUEUE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_MLCOMPLETE & 7)<<$_MLCOMPLETE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_LLQUEUE & 7)<<$_LLQUEUE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_LLCOMPLETE & 7)<<$_LLCOMPLETE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_HLQUEUE & 7)<<$_HLQUEUE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_HLCOMPLETE & 7)<<$_HLCOMPLETE_SHIFT))) LEVEL=$(($LEVEL|(($LOG_IOCTL & 7)<<$_IOCTL_SHIFT))) } check_cmdline $* if [ $SET = "1" ] then create_logging_level set_logging_level show_logging_level elif [ $GET = "1" ] then get_logging_level show_logging_level elif [ $CREATE = "1" ] then create_logging_level show_logging_level else invalid_cmdline missing option \'-g\', \'-s\' or \'-c\' fi sg3_utils-1.40/archive/llseek.h0000664000175000017500000000047510732244145015431 0ustar douggdougg#ifndef LLSEEK_H #define LLSEEK_H #if defined(__GNUC__) || defined(HAS_LONG_LONG) typedef int64_t llse_loff_t; #else typedef long llse_loff_t; #endif extern llse_loff_t llse_llseek(unsigned int fd, llse_loff_t offset, unsigned int origin); #endif sg3_utils-1.40/configure.ac0000664000175000017500000000647412401205666014653 0ustar douggdouggAC_INIT(sg3_utils, 1.40, dgilbert@interlog.com) AM_INIT_AUTOMAKE AM_MAINTAINER_MODE AM_CONFIG_HEADER(config.h) AC_PROG_CC # AC_PROG_CXX AC_PROG_INSTALL # Adding libtools to the build seems to bring in C++ environment AC_PROG_LIBTOOL # check for headers AC_HEADER_STDC AC_CHECK_HEADERS([linux/types.h linux/bsg.h linux/kdev_t.h], [], [], [[#ifdef HAVE_LINUX_TYPES_H # include #endif ]]) # check for functions AC_CHECK_FUNCS(getopt_long, GETOPT_O_FILES='', GETOPT_O_FILES='getopt_long.o') AC_CHECK_FUNCS(posix_fadvise) AC_CHECK_FUNCS(posix_memalign) AC_CHECK_FUNCS(sysconf) AC_CHECK_FUNCS(lseek64) AC_SUBST(GETOPT_O_FILES) AC_CANONICAL_HOST AC_DEFINE_UNQUOTED(SG_LIB_BUILD_HOST, "${host}", [sg3_utils Build Host]) case "${host}" in *-*-linux-gnu*) AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on linux]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; *-*-linux*) AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [sg3_utils on linux]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; *-*-freebsd*|*-*-kfreebsd*-gnu*) AC_DEFINE_UNQUOTED(SG_LIB_FREEBSD, 1, [sg3_utils on FreeBSD]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['-lcam']);; *-*-solaris*) AC_DEFINE_UNQUOTED(SG_LIB_SOLARIS, 1, [sg3_utils on Solaris]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']);; *-*-osf*) AC_DEFINE_UNQUOTED(SG_LIB_OSF1, 1, [sg3_utils on Tru64 UNIX]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; *-*-cygwin*) AC_DEFINE_UNQUOTED(SG_LIB_WIN32, 1, [sg3_utils on Win32]) AC_SUBST([os_cflags], ['-Wno-char-subscripts']) AC_SUBST([os_libs], ['']) ;; *-*-mingw*) AC_DEFINE_UNQUOTED(SG_LIB_WIN32, 1, [sg3_utils on Win32]) AC_DEFINE_UNQUOTED(SG_LIB_MINGW, 1, [also MinGW environment]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; *) AC_DEFINE_UNQUOTED(SG_LIB_LINUX, 1, [assume sg3_utils on linux]) AC_SUBST([os_cflags], ['']) AC_SUBST([os_libs], ['']) ;; esac # Define platform-specific symbol. AM_CONDITIONAL(OS_FREEBSD, [echo $host_os | grep 'freebsd' > /dev/null]) AM_CONDITIONAL(OS_LINUX, [echo $host_os | grep '^linux' > /dev/null]) AM_CONDITIONAL(OS_OSF, [echo $host_os | grep '^osf' > /dev/null]) AM_CONDITIONAL(OS_SOLARIS, [echo $host_os | grep '^solaris' > /dev/null]) AM_CONDITIONAL(OS_WIN32_MINGW, [echo $host_os | grep '^mingw' > /dev/null]) AM_CONDITIONAL(OS_WIN32_CYGWIN, [echo $host_os | grep '^cygwin' > /dev/null]) AC_ARG_ENABLE([linuxbsg], AC_HELP_STRING([--disable-linuxbsg], [ignore linux bsg (sgv4) if present]), [AC_DEFINE_UNQUOTED(IGNORE_LINUX_BSG, 1, [ignore linux bsg], )], []) AC_ARG_ENABLE([win32-spt-direct], AC_HELP_STRING([--enable-win32-spt-direct], [enable Win32 SPT Direct]), AC_DEFINE_UNQUOTED(WIN32_SPT_DIRECT, 1, [enable Win32 SPT Direct], ) ) AC_ARG_ENABLE([scsistrings], [AS_HELP_STRING([--disable-scsistrings], [Disable full SCSI sense strings])], [], [AC_DEFINE_UNQUOTED(SG_SCSI_STRINGS, 1, [full SCSI sense strings], )]) AC_OUTPUT(Makefile include/Makefile lib/Makefile src/Makefile doc/Makefile scripts/Makefile)